@proteinjs/db-driver-spanner 1.20.1 → 1.20.3

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.20.3](https://github.com/proteinjs/db/compare/@proteinjs/db-driver-spanner@1.20.2...@proteinjs/db-driver-spanner@1.20.3) (2026-08-15)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * reconcile re-read rides out brief INFORMATION_SCHEMA propagation (bounded retry) ([0f4739b](https://github.com/proteinjs/db/commit/0f4739bb2f233d9dff462cf7ec74777f53ea0de6))
12
+
13
+
14
+
15
+
16
+
17
+ ## [1.20.2](https://github.com/proteinjs/db/compare/@proteinjs/db-driver-spanner@1.20.1...@proteinjs/db-driver-spanner@1.20.2) (2026-08-15)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * schema reconcile logs the concurrent-ALREADY_EXISTS tolerance loudly (WARN) ([8e95c92](https://github.com/proteinjs/db/commit/8e95c92c3757bd577048a269e28a072a2e045208))
23
+
24
+
25
+
26
+
27
+
6
28
  ## [1.20.1](https://github.com/proteinjs/db/compare/@proteinjs/db-driver-spanner@1.20.0...@proteinjs/db-driver-spanner@1.20.1) (2026-08-15)
7
29
 
8
30
 
@@ -143,6 +143,15 @@ var internals = function (tableManager) { return tableManager; };
143
143
  var classifier = function (tableManager) {
144
144
  return tableManager.schemaOperations;
145
145
  };
146
+ /**
147
+ * Spy on THIS TableManager instance's own logger.warn. TableManager (@proteinjs/db) and this test
148
+ * (@proteinjs/db-driver-spanner) resolve separate physical @proteinjs/logger copies, so a
149
+ * Logger.prototype spy here would never intercept the reconcile's warns — spying the instance's
150
+ * method does, regardless of module identity.
151
+ */
152
+ var spyOnReconcileWarn = function (tableManager) {
153
+ return jest.spyOn(tableManager.logger, 'warn');
154
+ };
146
155
  describe('Concurrent schema reconcile', function () {
147
156
  var dropTable = (0, getDropTestTable_1.getDropTestTable)(spannerDriver);
148
157
  var tableManager = spannerDriver.getTableManager();
@@ -187,7 +196,7 @@ describe('Concurrent schema reconcile', function () {
187
196
  jest.restoreAllMocks();
188
197
  });
189
198
  test('two actors adding the SAME new column both succeed; the column lands once with the intended type', function () { return __awaiter(void 0, void 0, void 0, function () {
190
- var loserTm, realGetColumnMetadata, columnMetadata, runUpdateSchemaSpy;
199
+ var loserTm, realGetColumnMetadata, loserWarnSpy, toleratedWarn, columnMetadata, cleanWarnSpy, runUpdateSchemaSpy;
191
200
  return __generator(this, function (_a) {
192
201
  switch (_a.label) {
193
202
  case 0:
@@ -213,6 +222,7 @@ describe('Concurrent schema reconcile', function () {
213
222
  }
214
223
  });
215
224
  }); });
225
+ loserWarnSpy = spyOnReconcileWarn(loserTm);
216
226
  // OUTCOME: the loser's Db.init-equivalent does NOT reject — the duplicate DDL error is
217
227
  // reconciled to success. (Pre-fix, this rejects with "Duplicate column name" — the red run.)
218
228
  return [4 /*yield*/, expect(loserTm.loadTable(grownTable())).resolves.toBeUndefined()];
@@ -220,16 +230,27 @@ describe('Concurrent schema reconcile', function () {
220
230
  // OUTCOME: the loser's Db.init-equivalent does NOT reject — the duplicate DDL error is
221
231
  // reconciled to success. (Pre-fix, this rejects with "Duplicate column name" — the red run.)
222
232
  _a.sent();
233
+ toleratedWarn = loserWarnSpy.mock.calls.find(function (_a) {
234
+ var entry = _a[0];
235
+ return /\[schema reconcile\] tolerated concurrent ALREADY_EXISTS/.test(String(entry.message));
236
+ });
237
+ expect(toleratedWarn).toBeDefined();
238
+ expect(String(toleratedWarn[0].message)).toContain('db_test_reconcile');
223
239
  return [4 /*yield*/, tableManager.schemaMetadata.getColumnMetadata(grownTable())];
224
240
  case 4:
225
241
  columnMetadata = _a.sent();
226
242
  expect(columnMetadata['nickname']).toBeDefined();
227
243
  expect(columnMetadata['nickname'].type).toBe('STRING(255)');
244
+ cleanWarnSpy = spyOnReconcileWarn(tableManager);
228
245
  runUpdateSchemaSpy = jest.spyOn(spannerDriver, 'runUpdateSchema');
229
246
  return [4 /*yield*/, tableManager.loadTable(grownTable())];
230
247
  case 5:
231
248
  _a.sent();
232
249
  expect(runUpdateSchemaSpy).not.toHaveBeenCalled();
250
+ expect(cleanWarnSpy.mock.calls.filter(function (_a) {
251
+ var entry = _a[0];
252
+ return /\[schema reconcile\]/.test(String(entry.message));
253
+ })).toHaveLength(0);
233
254
  return [2 /*return*/];
234
255
  }
235
256
  });
@@ -263,8 +284,59 @@ describe('Concurrent schema reconcile', function () {
263
284
  }
264
285
  });
265
286
  }); }, 60000);
266
- test('GENUINE CONFLICT: an already-exists error whose live definition differs from intent STILL throws', function () { return __awaiter(void 0, void 0, void 0, function () {
287
+ test('PROPAGATION LAG: a briefly-stale re-read retries and succeeds instead of false-negative re-throwing', function () { return __awaiter(void 0, void 0, void 0, function () {
267
288
  var duplicateError, error_1;
289
+ return __generator(this, function (_a) {
290
+ switch (_a.label) {
291
+ case 0: return [4 /*yield*/, tableManager.loadTable(baseTable())];
292
+ case 1:
293
+ _a.sent();
294
+ _a.label = 2;
295
+ case 2:
296
+ _a.trys.push([2, 4, , 5]);
297
+ return [4 /*yield*/, spannerDriver.runUpdateSchema('ALTER TABLE `db_test_reconcile` ADD COLUMN `name` STRING(255)')];
298
+ case 3:
299
+ _a.sent();
300
+ return [3 /*break*/, 5];
301
+ case 4:
302
+ error_1 = _a.sent();
303
+ duplicateError = error_1;
304
+ return [3 /*break*/, 5];
305
+ case 5:
306
+ expect(duplicateError).toBeDefined();
307
+ expect(classifier(tableManager).isAlreadyExistsError(duplicateError)).toBe(true);
308
+ // Simulate brief INFORMATION_SCHEMA propagation lag on this connection: the FIRST re-read
309
+ // misses the table; the next sees the true schema. ALREADY_EXISTS guarantees the conflicting
310
+ // DDL committed — the object EXISTS — so the reconcile must ride out the stale read (bounded
311
+ // retry), not false-negative re-throw: a re-throw here IS the boot crash this fix closes.
312
+ jest.spyOn(tableManager.schemaMetadata, 'tableExists').mockImplementationOnce(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
313
+ return [2 /*return*/, false];
314
+ }); }); });
315
+ return [4 /*yield*/, expect(internals(tableManager).reconcileConcurrentSchemaChange([baseTable()], duplicateError)).resolves.toBeUndefined()];
316
+ case 6:
317
+ _a.sent();
318
+ return [2 /*return*/];
319
+ }
320
+ });
321
+ }); }, 60000);
322
+ test('BOUNDED RETRY: a definition that never becomes visible exhausts the retries and re-throws', function () { return __awaiter(void 0, void 0, void 0, function () {
323
+ var ghostDuplicate;
324
+ return __generator(this, function (_a) {
325
+ switch (_a.label) {
326
+ case 0:
327
+ ghostDuplicate = {
328
+ code: 9,
329
+ message: '9 FAILED_PRECONDITION: Duplicate name in schema: db_test_reconcile.',
330
+ };
331
+ return [4 /*yield*/, expect(internals(tableManager).reconcileConcurrentSchemaChange([baseTable()], ghostDuplicate)).rejects.toBe(ghostDuplicate)];
332
+ case 1:
333
+ _a.sent();
334
+ return [2 /*return*/];
335
+ }
336
+ });
337
+ }); }, 60000);
338
+ test('GENUINE CONFLICT: an already-exists error whose live definition differs from intent STILL throws', function () { return __awaiter(void 0, void 0, void 0, function () {
339
+ var duplicateError, error_2, warnSpy, conflictWarn;
268
340
  return __generator(this, function (_a) {
269
341
  switch (_a.label) {
270
342
  case 0:
@@ -281,27 +353,28 @@ describe('Concurrent schema reconcile', function () {
281
353
  _a.sent();
282
354
  return [3 /*break*/, 5];
283
355
  case 4:
284
- error_1 = _a.sent();
285
- duplicateError = error_1;
356
+ error_2 = _a.sent();
357
+ duplicateError = error_2;
286
358
  return [3 /*break*/, 5];
287
359
  case 5:
288
360
  expect(duplicateError).toBeDefined();
289
361
  expect(classifier(tableManager).isAlreadyExistsError(duplicateError)).toBe(true);
290
- // ...but the live schema (qty STRING(MAX)) does NOT match the intended definition (qty INT64),
291
- // so reconcile must RETHROW the original error rather than mask a genuine conflict.
292
- // (Bite: turn reconcile into a blanket swallow and this rejection disappears.)
362
+ warnSpy = spyOnReconcileWarn(tableManager);
293
363
  return [4 /*yield*/, expect(internals(tableManager).reconcileConcurrentSchemaChange([conflictIntegerTable()], duplicateError)).rejects.toBe(duplicateError)];
294
364
  case 6:
295
- // ...but the live schema (qty STRING(MAX)) does NOT match the intended definition (qty INT64),
296
- // so reconcile must RETHROW the original error rather than mask a genuine conflict.
297
- // (Bite: turn reconcile into a blanket swallow and this rejection disappears.)
298
365
  _a.sent();
366
+ conflictWarn = warnSpy.mock.calls.find(function (_a) {
367
+ var entry = _a[0];
368
+ return /\[schema reconcile\].*genuine conflict/.test(String(entry.message));
369
+ });
370
+ expect(conflictWarn).toBeDefined();
371
+ expect(String(conflictWarn[0].message)).toContain('db_test_reconcile_conflict');
299
372
  return [2 /*return*/];
300
373
  }
301
374
  });
302
375
  }); }, 60000);
303
376
  test('UNRELATED ERROR CLASS: a non-already-exists DDL error propagates unchanged', function () { return __awaiter(void 0, void 0, void 0, function () {
304
- var unrelatedError, error_2;
377
+ var unrelatedError, error_3;
305
378
  return __generator(this, function (_a) {
306
379
  switch (_a.label) {
307
380
  case 0:
@@ -318,8 +391,8 @@ describe('Concurrent schema reconcile', function () {
318
391
  _a.sent();
319
392
  return [3 /*break*/, 5];
320
393
  case 4:
321
- error_2 = _a.sent();
322
- unrelatedError = error_2;
394
+ error_3 = _a.sent();
395
+ unrelatedError = error_3;
323
396
  return [3 /*break*/, 5];
324
397
  case 5:
325
398
  expect(unrelatedError).toBeDefined();
@@ -1 +1 @@
1
- {"version":3,"file":"ConcurrentSchemaReconcile.test.js","sourceRoot":"","sources":["../../test/ConcurrentSchemaReconcile.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ConcurrentSchemaReconcile.test.js","sourceRoot":"","sources":["../../test/ConcurrentSchemaReconcile.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAA4G;AAC5G,kEAA6D;AAC7D,4DAA2D;AAC3D,gFAA+E;AAC/E,mCAAiC;AAEjC;;;;;;;;;;;;;GAaG;AAEH,IAAM,aAAa,GAAG;IACpB,SAAS,EAAE,gBAAgB;IAC3B,YAAY,EAAE,gBAAgB;IAC9B,YAAY,EAAE,MAAM;CACrB,CAAC;AAEF,IAAM,aAAa,GAAG,IAAI,iCAAa,CAAC,aAAa,CAAC,CAAC;AAUvD,uDAAuD;AACvD,IAAM,SAAS,GAAG;IAChB,OAAA,IAAI;QAAe,2BAAmB;QAAjC;YAAA,qEAKJ;YAJC,UAAI,GAAG,mBAAmB,CAAC;YAC3B,aAAO,GAAG,IAAA,sBAAiB,EAAe;gBACxC,IAAI,EAAE,IAAI,iBAAY,CAAC,MAAM,CAAC;aAC/B,CAAC,CAAC;;QACL,CAAC;QAAD,cAAC;IAAD,CAAC,AALI,CAAc,UAAK,GAKtB,EAAE;AALJ,CAKI,CAAC;AAEP,0FAA0F;AAC1F,IAAM,UAAU,GAAG;IACjB,OAAA,IAAI;QAAe,2BAAe;QAA7B;YAAA,qEAMJ;YALC,UAAI,GAAG,mBAAmB,CAAC;YAC3B,aAAO,GAAG,IAAA,sBAAiB,EAAW;gBACpC,IAAI,EAAE,IAAI,iBAAY,CAAC,MAAM,CAAC;gBAC9B,QAAQ,EAAE,IAAI,iBAAY,CAAC,UAAU,CAAC;aACvC,CAAC,CAAC;;QACL,CAAC;QAAD,cAAC;IAAD,CAAC,AANI,CAAc,UAAK,GAMtB,EAAE;AANJ,CAMI,CAAC;AAMP,sEAAsE;AACtE,IAAM,mBAAmB,GAAG;IAC1B,OAAA,IAAI;QAAe,2BAAkB;QAAhC;YAAA,qEAKJ;YAJC,UAAI,GAAG,4BAA4B,CAAC;YACpC,aAAO,GAAG,IAAA,sBAAiB,EAAc;gBACvC,GAAG,EAAE,IAAI,iBAAY,CAAC,KAAK,CAAC;aAC7B,CAAC,CAAC;;QACL,CAAC;QAAD,cAAC;IAAD,CAAC,AALI,CAAc,UAAK,GAKtB,EAAE;AALJ,CAKI,CAAC;AAEP,mFAAmF;AACnF,IAAM,oBAAoB,GAAG;IAC3B,OAAA,IAAI;QAAe,2BAAkB;QAAhC;YAAA,qEAKJ;YAJC,UAAI,GAAG,4BAA4B,CAAC;YACpC,aAAO,GAAG,IAAA,sBAAiB,EAAc;gBACvC,GAAG,EAAE,IAAI,kBAAa,CAAC,KAAK,CAAC;aAC9B,CAAC,CAAC;;QACL,CAAC;QAAD,cAAC;IAAD,CAAC,AALI,CAAc,UAAK,GAKtB,EAAE;AALJ,CAKI,CAAC;AASP,oGAAoG;AACpG,IAAM,SAAS,GAAG,UAAC,YAAiC,IAAK,OAAA,YAAgD,EAAhD,CAAgD,CAAC;AAE1G,4DAA4D;AAC5D,IAAM,UAAU,GAAG,UAAC,YAAiC;IACnD,OAAA,YAAY,CAAC,gBAAgF;AAA7F,CAA6F,CAAC;AAEhG;;;;;GAKG;AACH,IAAM,kBAAkB,GAAG,UAAC,YAAiC;IAC3D,OAAA,IAAI,CAAC,KAAK,CAAE,YAAsF,CAAC,MAAM,EAAE,MAAM,CAAC;AAAlH,CAAkH,CAAC;AAErH,QAAQ,CAAC,6BAA6B,EAAE;IACtC,IAAM,SAAS,GAAG,IAAA,mCAAgB,EAAC,aAAa,CAAC,CAAC;IAClD,IAAM,YAAY,GAAG,aAAa,CAAC,eAAe,EAAE,CAAC;IAErD,SAAS,CAAC;;;wBACR,qBAAM,uDAA0B,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAA;;oBAAjE,SAAiE,CAAC;;;;SACnE,EAAE,KAAK,CAAC,CAAC;IAEV,UAAU,CAAC;;;wBACT,qBAAM,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBAA5B,SAA4B,CAAC;oBAC7B,qBAAM,SAAS,CAAC,mBAAmB,EAAE,CAAC,EAAA;;oBAAtC,SAAsC,CAAC;;;;SACxC,EAAE,KAAK,CAAC,CAAC;IAEV,QAAQ,CAAC;;;wBACP,qBAAM,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBAA5B,SAA4B,CAAC;oBAC7B,qBAAM,SAAS,CAAC,mBAAmB,EAAE,CAAC,EAAA;;oBAAtC,SAAsC,CAAC;oBACvC,uDAA0B,CAAC,OAAO,EAAE,CAAC;;;;SACtC,EAAE,KAAK,CAAC,CAAC;IAEV,SAAS,CAAC;QACR,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kGAAkG,EAAE;;;;;gBACvG,+DAA+D;gBAC/D,qBAAM,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBADzC,+DAA+D;oBAC/D,SAAyC,CAAC;oBAC1C,qBAAM,YAAY,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,EAAA;;oBAA1C,SAA0C,CAAC;oBAMrC,OAAO,GAAG,aAAa,CAAC,eAAe,EAAE,CAAC;oBAC1C,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;oBACpG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,sBAAsB,CAAC,UAAO,KAAK;;;;wCAClE,qBAAM,qBAAqB,CAAC,KAAK,CAAC,EAAA;;oCAAnD,cAAc,GAAG,SAAkC;oCACzD,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC;oCAClC,sBAAO,cAAc,EAAC;;;yBACvB,CAAC,CAAC;oBACG,YAAY,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;oBAEjD,uFAAuF;oBACvF,6FAA6F;oBAC7F,qBAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAA;;oBAFtE,uFAAuF;oBACvF,6FAA6F;oBAC7F,SAAsE,CAAC;oBAIjE,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAC,EAAO;4BAAN,KAAK,QAAA;wBACxD,OAAA,0DAA0D,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAAtF,CAAsF,CACvF,CAAC;oBACF,MAAM,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;oBACpC,MAAM,CAAC,MAAM,CAAC,aAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;oBAGlD,qBAAM,YAAY,CAAC,cAAc,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAC,EAAA;;oBAAlF,cAAc,GAAG,SAAiE;oBACxF,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;oBACjD,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBAItD,YAAY,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;oBAChD,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;oBACxE,qBAAM,YAAY,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,EAAA;;oBAA1C,SAA0C,CAAC;oBAC3C,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;oBAClD,MAAM,CACJ,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAC,EAAO;4BAAN,KAAK,QAAA;wBAAM,OAAA,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAAlD,CAAkD,CAAC,CAChG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;;;;SACnB,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,8EAA8E,EAAE;;;;;gBACnF,qCAAqC;gBACrC,qBAAM,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBADzC,qCAAqC;oBACrC,SAAyC,CAAC;oBAIpC,OAAO,GAAG,aAAa,CAAC,eAAe,EAAE,CAAC;oBAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC,sBAAsB,CAAC;wBAAY,sBAAA,KAAK,EAAA;6BAAA,CAAC,CAAC;oBAE5F,8FAA8F;oBAC9F,0BAA0B;oBAC1B,qBAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAA;;oBAFrE,8FAA8F;oBAC9F,0BAA0B;oBAC1B,SAAqE,CAAC;oBAEtE,KAAA,MAAM,CAAA;oBAAC,qBAAM,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,EAAA;;oBAAlD,kBAAO,SAA2C,EAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;;;SAChE,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,qGAAqG,EAAE;;;;wBAC1G,qBAAM,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBAAzC,SAAyC,CAAC;;;;oBAKxC,qBAAM,aAAa,CAAC,eAAe,CAAC,+DAA+D,CAAC,EAAA;;oBAApG,SAAoG,CAAC;;;;oBAErG,cAAc,GAAG,OAAK,CAAC;;;oBAEzB,MAAM,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;oBACrC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAEjF,0FAA0F;oBAC1F,6FAA6F;oBAC7F,6FAA6F;oBAC7F,0FAA0F;oBAC1F,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC,sBAAsB,CAAC;wBAAY,sBAAA,KAAK,EAAA;6BAAA,CAAC,CAAC;oBAEjG,qBAAM,MAAM,CACV,SAAS,CAAC,YAAY,CAAC,CAAC,+BAA+B,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,cAAc,CAAC,CACvF,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAA;;oBAF1B,SAE0B,CAAC;;;;SAC5B,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,2FAA2F,EAAE;;;;;oBAI1F,cAAc,GAAG;wBACrB,IAAI,EAAE,CAAC;wBACP,OAAO,EAAE,qEAAqE;qBAC/E,CAAC;oBACF,qBAAM,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,+BAA+B,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAC/G,cAAc,CACf,EAAA;;oBAFD,SAEC,CAAC;;;;SACH,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,kGAAkG,EAAE;;;;;gBACvG,sCAAsC;gBACtC,qBAAM,YAAY,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC,EAAA;;oBADnD,sCAAsC;oBACtC,SAAmD,CAAC;;;;oBAMlD,qBAAM,aAAa,CAAC,eAAe,CAAC,iEAAiE,CAAC,EAAA;;oBAAtG,SAAsG,CAAC;;;;oBAEvG,cAAc,GAAG,OAAK,CAAC;;;oBAEzB,MAAM,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;oBACrC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAK3E,OAAO,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;oBACjD,qBAAM,MAAM,CACV,SAAS,CAAC,YAAY,CAAC,CAAC,+BAA+B,CAAC,CAAC,oBAAoB,EAAE,CAAC,EAAE,cAAc,CAAC,CAClG,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,EAAA;;oBAF9B,SAE8B,CAAC;oBAGzB,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAC,EAAO;4BAAN,KAAK,QAAA;wBAClD,OAAA,wCAAwC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAApE,CAAoE,CACrE,CAAC;oBACF,MAAM,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;oBACnC,MAAM,CAAC,MAAM,CAAC,YAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;;;;SAClF,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,4EAA4E,EAAE;;;;;gBACjF,8FAA8F;gBAC9F,qBAAM,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAA;;oBADzC,8FAA8F;oBAC9F,SAAyC,CAAC;;;;oBAKxC,qBAAM,aAAa,CAAC,eAAe,CAAC,sEAAsE,CAAC,EAAA;;oBAA3G,SAA2G,CAAC;;;;oBAE5G,cAAc,GAAG,OAAK,CAAC;;;oBAEzB,MAAM,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;oBACrC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAElF,uFAAuF;oBACvF,+FAA+F;oBAC/F,+FAA+F;oBAC/F,qBAAM,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,+BAA+B,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAC/G,cAAc,CACf,EAAA;;oBALD,uFAAuF;oBACvF,+FAA+F;oBAC/F,+FAA+F;oBAC/F,SAEC,CAAC;;;;SACH,EAAE,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,qFAAqF,EAAE;QAC1F,IAAM,eAAe,GAAG,UAAC,IAAwB,EAAE,OAAe;YAChE,OAAA,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,MAAA,EAAE,OAAO,SAAA,EAAE,CAAC;QAAhE,CAAgE,CAAC;QAEnE,+FAA+F;QAC/F,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,2DAA2D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnG,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,2DAA2D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnG,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,gDAAgD,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExF,wFAAwF;QACxF,MAAM,CACJ,eAAe,CACb,CAAC,EACD,8GAA8G,CAC/G,CACF,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,oEAAoE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7G,kDAAkD;QAClD,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,wDAAwD,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjG,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,uCAAuC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhF,wEAAwE;QACxE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC,CAAC,IAAI,CAC/G,KAAK,CACN,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proteinjs/db-driver-spanner",
3
- "version": "1.20.1",
3
+ "version": "1.20.3",
4
4
  "main": "./dist/generated/index.js",
5
5
  "types": "./dist/generated/index.d.ts",
6
6
  "exports": {
@@ -42,10 +42,10 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@google-cloud/spanner": "7.5.0",
45
- "@proteinjs/db": "^1.32.1",
45
+ "@proteinjs/db": "^1.32.3",
46
46
  "@proteinjs/db-query": "^1.7.0",
47
- "@proteinjs/db-spanner-common": "^1.3.9",
48
- "@proteinjs/db-transaction-context": "^0.5.9",
47
+ "@proteinjs/db-spanner-common": "^1.3.11",
48
+ "@proteinjs/db-transaction-context": "^0.5.11",
49
49
  "@proteinjs/logger": "^1.0.21",
50
50
  "@proteinjs/reflection": "^1.1.12",
51
51
  "@proteinjs/util": "^1.6.1"
@@ -63,5 +63,5 @@
63
63
  "ts-jest": "29.1.1",
64
64
  "typescript": "5.2.2"
65
65
  },
66
- "gitHead": "7f04d27c37019cc01b55a8e2d6bd4a178936dbdf"
66
+ "gitHead": "3fa64176929e1c9183cf3d998d9d629dcbb669b0"
67
67
  }
@@ -90,6 +90,15 @@ const internals = (tableManager: SpannerTableManager) => tableManager as unknown
90
90
  const classifier = (tableManager: SpannerTableManager) =>
91
91
  tableManager.schemaOperations as unknown as { isAlreadyExistsError(error: unknown): boolean };
92
92
 
93
+ /**
94
+ * Spy on THIS TableManager instance's own logger.warn. TableManager (@proteinjs/db) and this test
95
+ * (@proteinjs/db-driver-spanner) resolve separate physical @proteinjs/logger copies, so a
96
+ * Logger.prototype spy here would never intercept the reconcile's warns — spying the instance's
97
+ * method does, regardless of module identity.
98
+ */
99
+ const spyOnReconcileWarn = (tableManager: SpannerTableManager) =>
100
+ jest.spyOn((tableManager as unknown as { logger: { warn: (log: { message?: unknown }) => void } }).logger, 'warn');
101
+
93
102
  describe('Concurrent schema reconcile', () => {
94
103
  const dropTable = getDropTestTable(spannerDriver);
95
104
  const tableManager = spannerDriver.getTableManager();
@@ -129,20 +138,34 @@ describe('Concurrent schema reconcile', () => {
129
138
  delete columnMetadata['nickname'];
130
139
  return columnMetadata;
131
140
  });
141
+ const loserWarnSpy = spyOnReconcileWarn(loserTm);
132
142
 
133
143
  // OUTCOME: the loser's Db.init-equivalent does NOT reject — the duplicate DDL error is
134
144
  // reconciled to success. (Pre-fix, this rejects with "Duplicate column name" — the red run.)
135
145
  await expect(loserTm.loadTable(grownTable())).resolves.toBeUndefined();
136
146
 
147
+ // OBSERVABILITY: the tolerance fired LOUDLY (WARN), naming the table so an unexpected
148
+ // activation is never silent in prod.
149
+ const toleratedWarn = loserWarnSpy.mock.calls.find(([entry]) =>
150
+ /\[schema reconcile\] tolerated concurrent ALREADY_EXISTS/.test(String(entry.message))
151
+ );
152
+ expect(toleratedWarn).toBeDefined();
153
+ expect(String(toleratedWarn![0].message)).toContain('db_test_reconcile');
154
+
137
155
  // The column exists exactly once, with the intended type (StringColumn defaults to STRING(255)).
138
156
  const columnMetadata = await tableManager.schemaMetadata.getColumnMetadata(grownTable());
139
157
  expect(columnMetadata['nickname']).toBeDefined();
140
158
  expect(columnMetadata['nickname'].type).toBe('STRING(255)');
141
159
 
142
- // And the reconciled schema is truly up to date: a clean pass issues ZERO DDL.
160
+ // HAPPY PATH UNTOUCHED: a clean pass (DDL succeeds, nothing thrown) issues ZERO DDL and never
161
+ // reaches the reconcile path, so it emits no reconcile WARN.
162
+ const cleanWarnSpy = spyOnReconcileWarn(tableManager);
143
163
  const runUpdateSchemaSpy = jest.spyOn(spannerDriver, 'runUpdateSchema');
144
164
  await tableManager.loadTable(grownTable());
145
165
  expect(runUpdateSchemaSpy).not.toHaveBeenCalled();
166
+ expect(
167
+ cleanWarnSpy.mock.calls.filter(([entry]) => /\[schema reconcile\]/.test(String(entry.message)))
168
+ ).toHaveLength(0);
146
169
  }, 60000);
147
170
 
148
171
  test('two actors creating the SAME absent table both succeed; the table lands once', async () => {
@@ -161,6 +184,43 @@ describe('Concurrent schema reconcile', () => {
161
184
  expect(await tableManager.tableExists(baseTable())).toBe(true);
162
185
  }, 60000);
163
186
 
187
+ test('PROPAGATION LAG: a briefly-stale re-read retries and succeeds instead of false-negative re-throwing', async () => {
188
+ await tableManager.loadTable(baseTable());
189
+
190
+ // A REAL duplicate error — replaying an add of the already-present `name` column.
191
+ let duplicateError: unknown;
192
+ try {
193
+ await spannerDriver.runUpdateSchema('ALTER TABLE `db_test_reconcile` ADD COLUMN `name` STRING(255)');
194
+ } catch (error) {
195
+ duplicateError = error;
196
+ }
197
+ expect(duplicateError).toBeDefined();
198
+ expect(classifier(tableManager).isAlreadyExistsError(duplicateError)).toBe(true);
199
+
200
+ // Simulate brief INFORMATION_SCHEMA propagation lag on this connection: the FIRST re-read
201
+ // misses the table; the next sees the true schema. ALREADY_EXISTS guarantees the conflicting
202
+ // DDL committed — the object EXISTS — so the reconcile must ride out the stale read (bounded
203
+ // retry), not false-negative re-throw: a re-throw here IS the boot crash this fix closes.
204
+ jest.spyOn(tableManager.schemaMetadata, 'tableExists').mockImplementationOnce(async () => false);
205
+
206
+ await expect(
207
+ internals(tableManager).reconcileConcurrentSchemaChange([baseTable()], duplicateError)
208
+ ).resolves.toBeUndefined();
209
+ }, 60000);
210
+
211
+ test('BOUNDED RETRY: a definition that never becomes visible exhausts the retries and re-throws', async () => {
212
+ // `db_test_reconcile` is dropped in beforeEach and never created here — the claimed duplicate
213
+ // can never verify. The reconcile must give up after its bounded re-reads (not hang, not
214
+ // swallow) and surface the original error. (Bite: an unbounded retry would time this test out.)
215
+ const ghostDuplicate = {
216
+ code: 9,
217
+ message: '9 FAILED_PRECONDITION: Duplicate name in schema: db_test_reconcile.',
218
+ };
219
+ await expect(internals(tableManager).reconcileConcurrentSchemaChange([baseTable()], ghostDuplicate)).rejects.toBe(
220
+ ghostDuplicate
221
+ );
222
+ }, 60000);
223
+
164
224
  test('GENUINE CONFLICT: an already-exists error whose live definition differs from intent STILL throws', async () => {
165
225
  // Winner landed `qty` as STRING(MAX).
166
226
  await tableManager.loadTable(conflictStringTable());
@@ -179,9 +239,17 @@ describe('Concurrent schema reconcile', () => {
179
239
  // ...but the live schema (qty STRING(MAX)) does NOT match the intended definition (qty INT64),
180
240
  // so reconcile must RETHROW the original error rather than mask a genuine conflict.
181
241
  // (Bite: turn reconcile into a blanket swallow and this rejection disappears.)
242
+ const warnSpy = spyOnReconcileWarn(tableManager);
182
243
  await expect(
183
244
  internals(tableManager).reconcileConcurrentSchemaChange([conflictIntegerTable()], duplicateError)
184
245
  ).rejects.toBe(duplicateError);
246
+
247
+ // OBSERVABILITY: a genuine conflict is ALSO loud (WARN) before it re-throws.
248
+ const conflictWarn = warnSpy.mock.calls.find(([entry]) =>
249
+ /\[schema reconcile\].*genuine conflict/.test(String(entry.message))
250
+ );
251
+ expect(conflictWarn).toBeDefined();
252
+ expect(String(conflictWarn![0].message)).toContain('db_test_reconcile_conflict');
185
253
  }, 60000);
186
254
 
187
255
  test('UNRELATED ERROR CLASS: a non-already-exists DDL error propagates unchanged', async () => {