@proteinjs/db-driver-spanner 1.23.4 → 1.24.0

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/generated/index.js +1 -1
  3. package/dist/generated/index.js.map +1 -1
  4. package/dist/generated/test/index.d.ts.map +1 -1
  5. package/dist/generated/test/index.js +15 -1
  6. package/dist/generated/test/index.js.map +1 -1
  7. package/dist/src/SpannerDriver.d.ts +13 -0
  8. package/dist/src/SpannerDriver.d.ts.map +1 -1
  9. package/dist/src/SpannerDriver.js +38 -2
  10. package/dist/src/SpannerDriver.js.map +1 -1
  11. package/dist/src/SpannerSchemaOperations.d.ts.map +1 -1
  12. package/dist/src/SpannerSchemaOperations.js +4 -1
  13. package/dist/src/SpannerSchemaOperations.js.map +1 -1
  14. package/dist/test/ColumnEncryption.test.d.ts +2 -0
  15. package/dist/test/ColumnEncryption.test.d.ts.map +1 -0
  16. package/dist/test/ColumnEncryption.test.js +482 -0
  17. package/dist/test/ColumnEncryption.test.js.map +1 -0
  18. package/dist/test/EncryptedSearch.test.d.ts +2 -0
  19. package/dist/test/EncryptedSearch.test.d.ts.map +1 -0
  20. package/dist/test/EncryptedSearch.test.js +455 -0
  21. package/dist/test/EncryptedSearch.test.js.map +1 -0
  22. package/dist/test/EncryptionLifecycleWalker.test.d.ts +2 -0
  23. package/dist/test/EncryptionLifecycleWalker.test.d.ts.map +1 -0
  24. package/dist/test/EncryptionLifecycleWalker.test.js +408 -0
  25. package/dist/test/EncryptionLifecycleWalker.test.js.map +1 -0
  26. package/dist/test/EncryptionPerf.test.d.ts +2 -0
  27. package/dist/test/EncryptionPerf.test.d.ts.map +1 -0
  28. package/dist/test/EncryptionPerf.test.js +278 -0
  29. package/dist/test/EncryptionPerf.test.js.map +1 -0
  30. package/dist/test/EncryptionSortAndUnique.test.d.ts +2 -0
  31. package/dist/test/EncryptionSortAndUnique.test.d.ts.map +1 -0
  32. package/dist/test/EncryptionSortAndUnique.test.js +229 -0
  33. package/dist/test/EncryptionSortAndUnique.test.js.map +1 -0
  34. package/dist/test/Float64Params.test.d.ts +2 -0
  35. package/dist/test/Float64Params.test.d.ts.map +1 -0
  36. package/dist/test/Float64Params.test.js +242 -0
  37. package/dist/test/Float64Params.test.js.map +1 -0
  38. package/dist/test/index.d.ts +1 -0
  39. package/dist/test/index.d.ts.map +1 -1
  40. package/dist/test/index.js +1 -0
  41. package/dist/test/index.js.map +1 -1
  42. package/dist/test/util/columnEncryptionTestHarness.d.ts +23 -0
  43. package/dist/test/util/columnEncryptionTestHarness.d.ts.map +1 -0
  44. package/dist/test/util/columnEncryptionTestHarness.js +136 -0
  45. package/dist/test/util/columnEncryptionTestHarness.js.map +1 -0
  46. package/dist/test/util/columnEncryptionTestTables.d.ts +75 -0
  47. package/dist/test/util/columnEncryptionTestTables.d.ts.map +1 -0
  48. package/dist/test/util/columnEncryptionTestTables.js +124 -0
  49. package/dist/test/util/columnEncryptionTestTables.js.map +1 -0
  50. package/dist/test/util/serviceUpdateVerbsTestTables.d.ts +2 -2
  51. package/generated/index.ts +1 -1
  52. package/generated/test/index.ts +15 -1
  53. package/package.json +6 -6
  54. package/src/SpannerDriver.ts +38 -2
  55. package/src/SpannerSchemaOperations.ts +4 -1
  56. package/test/ColumnEncryption.test.ts +252 -0
  57. package/test/EncryptedSearch.test.ts +247 -0
  58. package/test/EncryptionLifecycleWalker.test.ts +223 -0
  59. package/test/EncryptionPerf.test.ts +156 -0
  60. package/test/EncryptionSortAndUnique.test.ts +130 -0
  61. package/test/Float64Params.test.ts +131 -0
  62. package/test/index.ts +1 -0
  63. package/test/util/columnEncryptionTestHarness.ts +54 -0
  64. package/test/util/columnEncryptionTestTables.ts +115 -0
@@ -0,0 +1,54 @@
1
+ import { DataEncryptionKeyTable, EncryptedColumns, Table, TableManager } from '@proteinjs/db';
2
+ import { cascadeDeleteTestTables } from '@proteinjs/db/test';
3
+ import { SpannerDriver } from '@proteinjs/db-driver-spanner';
4
+
5
+ /**
6
+ * Schema loading for the column-encryption suites. `Db.delete` consults the reverse-cascade
7
+ * edge index over the WHOLE static table registry, and dynamic-reference edges are
8
+ * target-agnostic — so a delete from ANY table queries every registered table holding a
9
+ * `reverseCascadeDelete` dynamic-reference column (the cascade-delete test tables). A
10
+ * single-file run must therefore create those alongside the suite's own tables, plus the
11
+ * framework's data-key table. Serial `loadTable` (never batch `loadTables`): the registry
12
+ * deliberately holds same-name table pairs for schema-change tests, which a batch create
13
+ * would collide on.
14
+ *
15
+ * @internal This module is intended to be used only in tests.
16
+ */
17
+ export const loadColumnEncryptionTestSchema = async (
18
+ tableManager: TableManager,
19
+ suiteTables: Table<any>[]
20
+ ): Promise<void> => {
21
+ const tables: Table<any>[] = [
22
+ ...Object.values(cascadeDeleteTestTables),
23
+ new DataEncryptionKeyTable(),
24
+ ...suiteTables,
25
+ ];
26
+ for (const table of tables) {
27
+ await tableManager.loadTable(table);
28
+ }
29
+ };
30
+
31
+ /**
32
+ * Clean-slate purge of a suite's tables (rows + their derived token tables) in beforeAll:
33
+ * a prior run killed mid-flight (or a teardown starved out by shared-emulator contention)
34
+ * leaves seeded rows behind, and exact-match search assertions must never depend on a
35
+ * previous process having exited cleanly.
36
+ */
37
+ export const purgeColumnEncryptionTestRows = async (
38
+ spannerDriver: SpannerDriver,
39
+ suiteTables: Table<any>[]
40
+ ): Promise<void> => {
41
+ const encryptedColumns = new EncryptedColumns();
42
+ const tables: Table<any>[] = [];
43
+ for (const table of suiteTables) {
44
+ tables.push(table);
45
+ const tokenTable = encryptedColumns.tokenTableFor(table);
46
+ if (tokenTable) {
47
+ tables.push(tokenTable);
48
+ }
49
+ }
50
+
51
+ for (const table of tables) {
52
+ await spannerDriver.runDml(() => ({ sql: `DELETE FROM \`${table.name}\` WHERE TRUE` }));
53
+ }
54
+ };
@@ -0,0 +1,115 @@
1
+ import { Record, StringColumn, Table, withRecordColumns } from '@proteinjs/db';
2
+
3
+ /**
4
+ * Tables for the column-encryption suites (`ColumnEncryption.test.ts`,
5
+ * `EncryptedSearch.test.ts`, `EncryptionSortAndUnique.test.ts`,
6
+ * `EncryptionLifecycleWalker.test.ts`, `EncryptionPerf.test.ts`).
7
+ *
8
+ * Defined here rather than in the test files so the reflection build registers them as
9
+ * `Table` loadables — the driver's statement generation and the framework's derived
10
+ * token-table subqueries resolve tables through `tableByName`.
11
+ */
12
+
13
+ /** Core seam suite: contains + equality + opaque encrypted + plaintext metadata. */
14
+ export interface EncNote extends Record {
15
+ scope: string;
16
+ title?: string | null; // encrypted + contains search
17
+ label?: string | null; // encrypted + equality lookup
18
+ body?: string | null; // encrypted, never queried by value
19
+ status?: string | null; // plaintext metadata
20
+ }
21
+
22
+ export class EncNoteTable extends Table<EncNote> {
23
+ name = 'db_test_enc_note';
24
+ columns: Table<EncNote>['columns'] = withRecordColumns<EncNote>({
25
+ scope: new StringColumn('scope', {}, 36),
26
+ title: new StringColumn('title', { encrypted: { searchable: 'contains' } }),
27
+ label: new StringColumn('label', { encrypted: { searchable: 'equality' } }),
28
+ body: new StringColumn('body', { encrypted: {} }, 'MAX'),
29
+ status: new StringColumn('status', { encrypted: false }),
30
+ });
31
+ }
32
+
33
+ /** Search-exactness suite: one contains column beside plaintext metadata. */
34
+ export interface EncSearchDoc extends Record {
35
+ scope: string;
36
+ title?: string | null; // encrypted + contains
37
+ name?: string | null; // encrypted + equality
38
+ kind?: string | null; // plaintext metadata
39
+ }
40
+
41
+ export class EncSearchDocTable extends Table<EncSearchDoc> {
42
+ name = 'db_test_enc_search_doc';
43
+ columns: Table<EncSearchDoc>['columns'] = withRecordColumns<EncSearchDoc>({
44
+ scope: new StringColumn('scope', {}, 36),
45
+ title: new StringColumn('title', { encrypted: { searchable: 'contains' } }),
46
+ name: new StringColumn('name', { encrypted: { searchable: 'equality' } }),
47
+ kind: new StringColumn('kind', { encrypted: false }),
48
+ });
49
+ }
50
+
51
+ /** sortKey suite: the declared bounded-reveal native ORDER BY. */
52
+ export interface EncSortedItem extends Record {
53
+ scope: string;
54
+ title?: string | null; // encrypted + sortKey(3)
55
+ }
56
+
57
+ export class EncSortedItemTable extends Table<EncSortedItem> {
58
+ name = 'db_test_enc_sorted_item';
59
+ columns: Table<EncSortedItem>['columns'] = withRecordColumns<EncSortedItem>({
60
+ scope: new StringColumn('scope', {}, 36),
61
+ title: new StringColumn('title', { encrypted: { searchable: 'contains', sortKey: { revealPrefix: 3 } } }),
62
+ });
63
+ }
64
+
65
+ /** Uniqueness suite: unique moves onto the equality fingerprint. */
66
+ export interface EncUniqueTag extends Record {
67
+ scope: string;
68
+ name?: string | null; // encrypted + equality, unique
69
+ }
70
+
71
+ export class EncUniqueTagTable extends Table<EncUniqueTag> {
72
+ name = 'db_test_enc_unique_tag';
73
+ columns: Table<EncUniqueTag>['columns'] = withRecordColumns<EncUniqueTag>({
74
+ scope: new StringColumn('scope', {}, 36),
75
+ name: new StringColumn('name', { unique: { unique: true }, encrypted: { searchable: 'equality' } }),
76
+ });
77
+ }
78
+
79
+ /** Lifecycle-walker suite: encrypt / retokenize / decrypt / rotate transitions. */
80
+ export interface EncWalkRow extends Record {
81
+ scope: string;
82
+ title?: string | null; // encrypted + contains
83
+ body?: string | null; // encrypted, no search
84
+ }
85
+
86
+ export class EncWalkRowTable extends Table<EncWalkRow> {
87
+ name = 'db_test_enc_walk_row';
88
+ columns: Table<EncWalkRow>['columns'] = withRecordColumns<EncWalkRow>({
89
+ scope: new StringColumn('scope', {}, 36),
90
+ title: new StringColumn('title', { encrypted: { searchable: 'contains' } }),
91
+ body: new StringColumn('body', { encrypted: {} }, 'MAX'),
92
+ });
93
+ }
94
+
95
+ /** Perf suite: encrypted-at-rest body vs a plaintext twin, 1k-row reads. */
96
+ export interface EncPerfRow extends Record {
97
+ scope: string;
98
+ body?: string | null;
99
+ }
100
+
101
+ export class EncPerfRowTable extends Table<EncPerfRow> {
102
+ name = 'db_test_enc_perf_row';
103
+ columns: Table<EncPerfRow>['columns'] = withRecordColumns<EncPerfRow>({
104
+ scope: new StringColumn('scope', {}, 36),
105
+ body: new StringColumn('body', { encrypted: {} }, 'MAX'),
106
+ });
107
+ }
108
+
109
+ export class PlainPerfRowTable extends Table<EncPerfRow> {
110
+ name = 'db_test_plain_perf_row';
111
+ columns: Table<EncPerfRow>['columns'] = withRecordColumns<EncPerfRow>({
112
+ scope: new StringColumn('scope', {}, 36),
113
+ body: new StringColumn('body', { encrypted: false }, 'MAX'),
114
+ });
115
+ }