@open-mercato/core 0.10.1-develop.7888.1.96c8c2bd5f → 0.10.1-develop.7894.1.2c464c73e3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -191,7 +191,8 @@ async function updateCoverageRows(
191
191
  // overlapping adjustments compose, and drops the `SELECT` (and the window between it and the
192
192
  // write) that made the coverage row a contention point in the first place.
193
193
  //
194
- // In steady state that is one statement. The extra statements are recovery paths that do not
194
+ // For non-null tenants, steady state is one statement. NULL-tenant writers first take
195
+ // the scope advisory lock because the unique constraint cannot coordinate their rows. The extra statements are recovery paths that do not
195
196
  // fire once a scope has settled: the legacy NULL-organization fold below runs only for
196
197
  // global-organization scopes, the insert only until the scope's row exists, and the duplicate
197
198
  // prune only when the scope somehow holds more than one row.
@@ -209,6 +210,7 @@ async function incrementCoverageRow(
209
210
  scope: CoverageScope,
210
211
  deltas: { deltaBase: number; deltaIndex: number; deltaVector: number }
211
212
  ): Promise<void> {
213
+ if (scope.tenantId == null) await lockCoverageInitialization(db, scope)
212
214
  const storedOrgId = normalizeOrganizationForStore(scope.organizationId ?? null)
213
215
  let deltaBase = deltas.deltaBase
214
216
  let deltaIndex = deltas.deltaIndex
@@ -237,15 +239,7 @@ async function incrementCoverageRow(
237
239
  }
238
240
  }
239
241
 
240
- let updated = await updateCoverageRows(db, scope, { deltaBase, deltaIndex, deltaVector })
241
-
242
- if (updated.length === 0 && scope.tenantId == null) {
243
- // The unique constraint cannot serialize a first insert whose tenant is NULL. Take a
244
- // transaction-scoped lock only on this rowless branch, then repeat the UPDATE: a creator
245
- // that won while we waited has committed its row, so this adjustment composes into it.
246
- await lockCoverageInitialization(db, scope)
247
- updated = await updateCoverageRows(db, scope, { deltaBase, deltaIndex, deltaVector })
248
- }
242
+ const updated = await updateCoverageRows(db, scope, { deltaBase, deltaIndex, deltaVector })
249
243
 
250
244
  if (updated.length > 0) {
251
245
  // In steady state the scope holds exactly the row just incremented, so the adjustment is
@@ -257,7 +251,7 @@ async function incrementCoverageRow(
257
251
  }
258
252
 
259
253
  // No row for this scope yet. `ON CONFLICT` closes the insert race for scopes the unique
260
- // constraint can see. NULL-tenant initialization reaches here only while holding the scoped
254
+ // constraint can see. NULL-tenant writes reach here only while holding the scoped
261
255
  // transaction advisory lock above, so it has the same single-creator guarantee.
262
256
  const rows = await db
263
257
  .insertInto('entity_index_coverage' as any)
@@ -304,6 +298,27 @@ async function upsertCoverageRow(
304
298
  await purge.execute()
305
299
  }
306
300
 
301
+ if (scope.tenantId == null) {
302
+ const updated = await db
303
+ .updateTable('entity_index_coverage')
304
+ .set({
305
+ base_count: counts.baseCount,
306
+ indexed_count: counts.indexedCount,
307
+ vector_indexed_count: counts.vectorIndexedCount,
308
+ refreshed_at: sql`now()`,
309
+ })
310
+ .where('entity_type', '=', scope.entityType)
311
+ .where('tenant_id', 'is', null)
312
+ .where('organization_id', '=', storedOrgId)
313
+ .where('with_deleted', '=', scope.withDeleted === true)
314
+ .returning('id')
315
+ .execute() as Array<{ id: string }>
316
+ if (updated.length > 0) {
317
+ if (updated.length > 1) await pruneDuplicateCoverageRows(db, scope, updated[0]!.id)
318
+ return
319
+ }
320
+ }
321
+
307
322
  const rows = await db
308
323
  .insertInto('entity_index_coverage' as any)
309
324
  .values({
@@ -674,26 +689,34 @@ export async function writeCoverageCounts(
674
689
  const tenantId = scope.tenantId ?? null
675
690
  const organizationId = scope.organizationId ?? null
676
691
  const withDeleted = scope.withDeleted === true
677
- const existing = await fetchCoverageRow(db, {
678
- entityType,
679
- tenantId,
680
- organizationId,
681
- withDeleted,
682
- })
683
- const baseCount = counts.baseCount !== undefined
684
- ? Math.max(0, Math.trunc(toCount(counts.baseCount)))
685
- : Math.max(0, Math.trunc(toCount(existing?.base_count)))
686
- const indexCount = counts.indexedCount !== undefined
687
- ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))
688
- : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))
689
- const vectorCount = counts.vectorCount !== undefined
690
- ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))
691
- : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))
692
- await upsertCoverageRow(db, { entityType, tenantId, organizationId, withDeleted }, {
693
- baseCount,
694
- indexedCount: indexCount,
695
- vectorIndexedCount: vectorCount,
696
- })
692
+ const write = async (executor: CoverageExecutor): Promise<void> => {
693
+ if (tenantId == null) await lockCoverageInitialization(executor, scope)
694
+ const existing = await fetchCoverageRow(executor, {
695
+ entityType,
696
+ tenantId,
697
+ organizationId,
698
+ withDeleted,
699
+ })
700
+ const baseCount = counts.baseCount !== undefined
701
+ ? Math.max(0, Math.trunc(toCount(counts.baseCount)))
702
+ : Math.max(0, Math.trunc(toCount(existing?.base_count)))
703
+ const indexCount = counts.indexedCount !== undefined
704
+ ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))
705
+ : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))
706
+ const vectorCount = counts.vectorCount !== undefined
707
+ ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))
708
+ : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))
709
+ await upsertCoverageRow(executor, { entityType, tenantId, organizationId, withDeleted }, {
710
+ baseCount,
711
+ indexedCount: indexCount,
712
+ vectorIndexedCount: vectorCount,
713
+ })
714
+ }
715
+ if (tenantId == null && !db.isTransaction) {
716
+ await db.transaction().execute(write)
717
+ } else {
718
+ await write(db)
719
+ }
697
720
  }
698
721
 
699
722
  type AggregatedAdjustment = {