( trx: DbTransaction, tableId: string, afterRowId?: string, beforeRowId?: string )
| 230 | * row-order lock. |
| 231 | */ |
| 232 | export async function resolveInsertByNeighbor( |
| 233 | trx: DbTransaction, |
| 234 | tableId: string, |
| 235 | afterRowId?: string, |
| 236 | beforeRowId?: string |
| 237 | ): Promise<{ orderKey: string; position: number }> { |
| 238 | const anchorId = afterRowId ?? beforeRowId! |
| 239 | const [anchor] = await trx |
| 240 | .select({ orderKey: userTableRows.orderKey, position: userTableRows.position }) |
| 241 | .from(userTableRows) |
| 242 | .where(and(eq(userTableRows.tableId, tableId), eq(userTableRows.id, anchorId))) |
| 243 | .limit(1) |
| 244 | // The client targets a specific neighbor; a missing one (concurrent delete / |
| 245 | // stale view) is an error, not a silent insert at the front. |
| 246 | if (!anchor) throw new Error(`Row not found: ${anchorId}`) |
| 247 | const anchorKey = anchor.orderKey ?? null |
| 248 | // A null key on the anchor means the table isn't backfilled. With the flag on |
| 249 | // (key is authoritative) the adjacent-key lookup below can't work — fail |
| 250 | // loudly rather than mint a wrong key. Flag off keeps `position` authoritative, |
| 251 | // so a best-effort key here is fine (the backfill re-keys before the flip). |
| 252 | const fractionalOrdering = await isFeatureEnabled('tables-fractional-ordering') |
| 253 | if (anchorKey === null && fractionalOrdering) { |
| 254 | throw new Error(`Row ${anchorId} has no order_key yet (table not backfilled)`) |
| 255 | } |
| 256 | |
| 257 | if (afterRowId) { |
| 258 | // hi = the smallest key strictly GREATER than the anchor key. Comparing keys |
| 259 | // (not the `(order_key, id)` row tuple) skips past any sibling that shares the |
| 260 | // anchor's key, so `keyBetween` always gets strictly-ordered bounds and can't |
| 261 | // throw on a stray duplicate. Identical to the row tuple when keys are distinct. |
| 262 | // A null anchorKey (flag off, un-backfilled) has no key to compare — leave the |
| 263 | // upper bound open, matching the prior best-effort behavior. |
| 264 | let nextKey: string | null = null |
| 265 | if (anchorKey !== null) { |
| 266 | const [next] = await trx |
| 267 | .select({ orderKey: userTableRows.orderKey }) |
| 268 | .from(userTableRows) |
| 269 | .where(and(eq(userTableRows.tableId, tableId), gt(userTableRows.orderKey, anchorKey))) |
| 270 | .orderBy(asc(userTableRows.orderKey)) |
| 271 | .limit(1) |
| 272 | nextKey = next?.orderKey ?? null |
| 273 | } |
| 274 | return { |
| 275 | orderKey: keyBetween(anchorKey, nextKey), |
| 276 | position: anchor.position + 1, |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | // beforeRowId: lo = the largest key strictly LESS than the anchor key (distinct, |
| 281 | // same rationale as the afterRowId branch above). |
| 282 | let prevKey: string | null = null |
| 283 | if (anchorKey !== null) { |
| 284 | const [prev] = await trx |
| 285 | .select({ orderKey: userTableRows.orderKey }) |
| 286 | .from(userTableRows) |
| 287 | .where(and(eq(userTableRows.tableId, tableId), lt(userTableRows.orderKey, anchorKey))) |
| 288 | .orderBy(desc(userTableRows.orderKey)) |
| 289 | .limit(1) |
no test coverage detected