@b2bc-devkit/sheetorm 0.1.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.
- package/dist/npm/SheetOrm.d.ts +41 -0
- package/dist/npm/SheetOrm.d.ts.map +1 -0
- package/dist/npm/SheetOrm.js +41 -0
- package/dist/npm/SheetOrm.js.map +1 -0
- package/dist/npm/core/Decorators.d.ts +145 -0
- package/dist/npm/core/Decorators.d.ts.map +1 -0
- package/dist/npm/core/Decorators.js +226 -0
- package/dist/npm/core/Decorators.js.map +1 -0
- package/dist/npm/core/Record.d.ts +167 -0
- package/dist/npm/core/Record.d.ts.map +1 -0
- package/dist/npm/core/Record.js +298 -0
- package/dist/npm/core/Record.js.map +1 -0
- package/dist/npm/core/RecordConstructor.d.ts +20 -0
- package/dist/npm/core/RecordConstructor.d.ts.map +1 -0
- package/dist/npm/core/RecordConstructor.js +2 -0
- package/dist/npm/core/RecordConstructor.js.map +1 -0
- package/dist/npm/core/RecordStatic.d.ts +19 -0
- package/dist/npm/core/RecordStatic.d.ts.map +1 -0
- package/dist/npm/core/RecordStatic.js +2 -0
- package/dist/npm/core/RecordStatic.js.map +1 -0
- package/dist/npm/core/Registry.d.ts +100 -0
- package/dist/npm/core/Registry.d.ts.map +1 -0
- package/dist/npm/core/Registry.js +206 -0
- package/dist/npm/core/Registry.js.map +1 -0
- package/dist/npm/core/SheetRepository.d.ts +331 -0
- package/dist/npm/core/SheetRepository.d.ts.map +1 -0
- package/dist/npm/core/SheetRepository.js +1041 -0
- package/dist/npm/core/SheetRepository.js.map +1 -0
- package/dist/npm/core/cache/MemoryCache.d.ts +67 -0
- package/dist/npm/core/cache/MemoryCache.d.ts.map +1 -0
- package/dist/npm/core/cache/MemoryCache.js +112 -0
- package/dist/npm/core/cache/MemoryCache.js.map +1 -0
- package/dist/npm/core/types/Entity.d.ts +21 -0
- package/dist/npm/core/types/Entity.d.ts.map +1 -0
- package/dist/npm/core/types/Entity.js +2 -0
- package/dist/npm/core/types/Entity.js.map +1 -0
- package/dist/npm/core/types/FieldDefinition.d.ts +21 -0
- package/dist/npm/core/types/FieldDefinition.d.ts.map +1 -0
- package/dist/npm/core/types/FieldDefinition.js +2 -0
- package/dist/npm/core/types/FieldDefinition.js.map +1 -0
- package/dist/npm/core/types/FieldType.d.ts +12 -0
- package/dist/npm/core/types/FieldType.d.ts.map +1 -0
- package/dist/npm/core/types/FieldType.js +2 -0
- package/dist/npm/core/types/FieldType.js.map +1 -0
- package/dist/npm/core/types/Filter.d.ts +16 -0
- package/dist/npm/core/types/Filter.d.ts.map +1 -0
- package/dist/npm/core/types/Filter.js +2 -0
- package/dist/npm/core/types/Filter.js.map +1 -0
- package/dist/npm/core/types/FilterOperator.d.ts +16 -0
- package/dist/npm/core/types/FilterOperator.d.ts.map +1 -0
- package/dist/npm/core/types/FilterOperator.js +2 -0
- package/dist/npm/core/types/FilterOperator.js.map +1 -0
- package/dist/npm/core/types/GroupResult.d.ts +14 -0
- package/dist/npm/core/types/GroupResult.d.ts.map +1 -0
- package/dist/npm/core/types/GroupResult.js +2 -0
- package/dist/npm/core/types/GroupResult.js.map +1 -0
- package/dist/npm/core/types/ICacheProvider.d.ts +20 -0
- package/dist/npm/core/types/ICacheProvider.d.ts.map +1 -0
- package/dist/npm/core/types/ICacheProvider.js +2 -0
- package/dist/npm/core/types/ICacheProvider.js.map +1 -0
- package/dist/npm/core/types/ISheetAdapter.d.ts +54 -0
- package/dist/npm/core/types/ISheetAdapter.d.ts.map +1 -0
- package/dist/npm/core/types/ISheetAdapter.js +2 -0
- package/dist/npm/core/types/ISheetAdapter.js.map +1 -0
- package/dist/npm/core/types/ISpreadsheetAdapter.d.ts +34 -0
- package/dist/npm/core/types/ISpreadsheetAdapter.d.ts.map +1 -0
- package/dist/npm/core/types/ISpreadsheetAdapter.js +2 -0
- package/dist/npm/core/types/ISpreadsheetAdapter.js.map +1 -0
- package/dist/npm/core/types/IndexDefinition.d.ts +16 -0
- package/dist/npm/core/types/IndexDefinition.d.ts.map +1 -0
- package/dist/npm/core/types/IndexDefinition.js +2 -0
- package/dist/npm/core/types/IndexDefinition.js.map +1 -0
- package/dist/npm/core/types/LifecycleHooks.d.ts +32 -0
- package/dist/npm/core/types/LifecycleHooks.d.ts.map +1 -0
- package/dist/npm/core/types/LifecycleHooks.js +2 -0
- package/dist/npm/core/types/LifecycleHooks.js.map +1 -0
- package/dist/npm/core/types/PaginatedResult.d.ts +18 -0
- package/dist/npm/core/types/PaginatedResult.d.ts.map +1 -0
- package/dist/npm/core/types/PaginatedResult.js +2 -0
- package/dist/npm/core/types/PaginatedResult.js.map +1 -0
- package/dist/npm/core/types/QueryOptions.d.ts +21 -0
- package/dist/npm/core/types/QueryOptions.d.ts.map +1 -0
- package/dist/npm/core/types/QueryOptions.js +2 -0
- package/dist/npm/core/types/QueryOptions.js.map +1 -0
- package/dist/npm/core/types/SortClause.d.ts +10 -0
- package/dist/npm/core/types/SortClause.d.ts.map +1 -0
- package/dist/npm/core/types/SortClause.js +2 -0
- package/dist/npm/core/types/SortClause.js.map +1 -0
- package/dist/npm/core/types/SystemColumns.d.ts +16 -0
- package/dist/npm/core/types/SystemColumns.d.ts.map +1 -0
- package/dist/npm/core/types/SystemColumns.js +16 -0
- package/dist/npm/core/types/SystemColumns.js.map +1 -0
- package/dist/npm/core/types/TableSchema.d.ts +24 -0
- package/dist/npm/core/types/TableSchema.d.ts.map +1 -0
- package/dist/npm/core/types/TableSchema.js +2 -0
- package/dist/npm/core/types/TableSchema.js.map +1 -0
- package/dist/npm/index/IndexMeta.d.ts +16 -0
- package/dist/npm/index/IndexMeta.d.ts.map +1 -0
- package/dist/npm/index/IndexMeta.js +2 -0
- package/dist/npm/index/IndexMeta.js.map +1 -0
- package/dist/npm/index/IndexStore.d.ts +399 -0
- package/dist/npm/index/IndexStore.d.ts.map +1 -0
- package/dist/npm/index/IndexStore.js +1104 -0
- package/dist/npm/index/IndexStore.js.map +1 -0
- package/dist/npm/index.d.ts +115 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/index.js +367 -0
- package/dist/npm/index.js.map +1 -0
- package/dist/npm/query/Query.d.ts +176 -0
- package/dist/npm/query/Query.d.ts.map +1 -0
- package/dist/npm/query/Query.js +270 -0
- package/dist/npm/query/Query.js.map +1 -0
- package/dist/npm/query/QueryEngine.d.ts +140 -0
- package/dist/npm/query/QueryEngine.d.ts.map +1 -0
- package/dist/npm/query/QueryEngine.js +453 -0
- package/dist/npm/query/QueryEngine.js.map +1 -0
- package/dist/npm/storage/GoogleSheetAdapter.d.ts +120 -0
- package/dist/npm/storage/GoogleSheetAdapter.d.ts.map +1 -0
- package/dist/npm/storage/GoogleSheetAdapter.js +239 -0
- package/dist/npm/storage/GoogleSheetAdapter.js.map +1 -0
- package/dist/npm/storage/GoogleSpreadsheetAdapter.d.ts +55 -0
- package/dist/npm/storage/GoogleSpreadsheetAdapter.d.ts.map +1 -0
- package/dist/npm/storage/GoogleSpreadsheetAdapter.js +99 -0
- package/dist/npm/storage/GoogleSpreadsheetAdapter.js.map +1 -0
- package/dist/npm/testing/ParityCatalog.d.ts +38 -0
- package/dist/npm/testing/ParityCatalog.d.ts.map +1 -0
- package/dist/npm/testing/ParityCatalog.js +400 -0
- package/dist/npm/testing/ParityCatalog.js.map +1 -0
- package/dist/npm/testing/RuntimeBenchmark.d.ts +37 -0
- package/dist/npm/testing/RuntimeBenchmark.d.ts.map +1 -0
- package/dist/npm/testing/RuntimeBenchmark.js +449 -0
- package/dist/npm/testing/RuntimeBenchmark.js.map +1 -0
- package/dist/npm/testing/RuntimeParity.d.ts +62 -0
- package/dist/npm/testing/RuntimeParity.d.ts.map +1 -0
- package/dist/npm/testing/RuntimeParity.js +4030 -0
- package/dist/npm/testing/RuntimeParity.js.map +1 -0
- package/dist/npm/utils/Serialization.d.ts +111 -0
- package/dist/npm/utils/Serialization.d.ts.map +1 -0
- package/dist/npm/utils/Serialization.js +281 -0
- package/dist/npm/utils/Serialization.js.map +1 -0
- package/dist/npm/utils/SheetOrmLogger.d.ts +31 -0
- package/dist/npm/utils/SheetOrmLogger.d.ts.map +1 -0
- package/dist/npm/utils/SheetOrmLogger.js +42 -0
- package/dist/npm/utils/SheetOrmLogger.js.map +1 -0
- package/dist/npm/utils/Uuid.d.ts +29 -0
- package/dist/npm/utils/Uuid.d.ts.map +1 -0
- package/dist/npm/utils/Uuid.js +86 -0
- package/dist/npm/utils/Uuid.js.map +1 -0
- package/license.md +18 -0
- package/package.json +77 -0
- package/readme.md +672 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global singleton registry that manages the ORM runtime state.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Holds the single {@link ISpreadsheetAdapter} (defaults to GAS active spreadsheet).
|
|
6
|
+
* - Maintains a per-table {@link SheetRepository} cache so the same repo
|
|
7
|
+
* is reused for the lifetime of the script execution.
|
|
8
|
+
* - Creates and wires up the shared {@link IndexStore} used by all repos.
|
|
9
|
+
* - Keeps a class map so `Query.from("ClassName")` can resolve by name.
|
|
10
|
+
*
|
|
11
|
+
* @module Registry
|
|
12
|
+
*/
|
|
13
|
+
import { SheetRepository } from "./SheetRepository.js";
|
|
14
|
+
import { IndexStore } from "../index/IndexStore.js";
|
|
15
|
+
import { MemoryCache } from "./cache/MemoryCache.js";
|
|
16
|
+
import { GoogleSpreadsheetAdapter } from "../storage/GoogleSpreadsheetAdapter.js";
|
|
17
|
+
import { Decorators } from "./Decorators.js";
|
|
18
|
+
import { SheetOrmLogger } from "../utils/SheetOrmLogger.js";
|
|
19
|
+
/**
|
|
20
|
+
* Central registry for SheetORM.
|
|
21
|
+
*
|
|
22
|
+
* Accessed via `Registry.getInstance()`. Call `Registry.reset()` in
|
|
23
|
+
* tests to start with a clean slate.
|
|
24
|
+
*/
|
|
25
|
+
export class Registry {
|
|
26
|
+
constructor() {
|
|
27
|
+
/** The spreadsheet-level adapter (wraps GAS Spreadsheet or mock). */
|
|
28
|
+
this.adapter = null;
|
|
29
|
+
/** Optional entity data cache (defaults to MemoryCache). */
|
|
30
|
+
this.cache = null;
|
|
31
|
+
/** Shared secondary-index manager. */
|
|
32
|
+
this.indexStore = null;
|
|
33
|
+
/** tableName → SheetRepository cache. */
|
|
34
|
+
this.repos = new Map();
|
|
35
|
+
/** tableName → RecordStatic class map for lookup by table name. */
|
|
36
|
+
this.classesByTable = new Map();
|
|
37
|
+
/** className → RecordStatic class map for lookup by constructor name. */
|
|
38
|
+
this.classesByName = new Map();
|
|
39
|
+
}
|
|
40
|
+
/** Return (or create) the singleton Registry instance. */
|
|
41
|
+
static getInstance() {
|
|
42
|
+
if (!Registry.instance) {
|
|
43
|
+
Registry.instance = new Registry();
|
|
44
|
+
}
|
|
45
|
+
return Registry.instance;
|
|
46
|
+
}
|
|
47
|
+
/** Destroy the singleton — used by test suites to reset state between runs. */
|
|
48
|
+
static reset() {
|
|
49
|
+
Registry.instance = null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Configure the registry with a custom adapter and/or cache.
|
|
53
|
+
* Clears all previously created repos, class maps, and the index store.
|
|
54
|
+
*/
|
|
55
|
+
configure(options) {
|
|
56
|
+
SheetOrmLogger.log(`[Registry] configure (adapter=${options.adapter?.constructor.name ?? "default"})`);
|
|
57
|
+
this.adapter = options.adapter ?? null;
|
|
58
|
+
this.cache = options.cache ?? null;
|
|
59
|
+
this.indexStore = null;
|
|
60
|
+
this.repos.clear();
|
|
61
|
+
this.classesByTable.clear();
|
|
62
|
+
this.classesByName.clear();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Return the current adapter, falling back to a default
|
|
66
|
+
* GoogleSpreadsheetAdapter (active spreadsheet) if none was configured.
|
|
67
|
+
*/
|
|
68
|
+
getAdapter() {
|
|
69
|
+
if (!this.adapter) {
|
|
70
|
+
this.adapter = new GoogleSpreadsheetAdapter();
|
|
71
|
+
}
|
|
72
|
+
return this.adapter;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Lazily create the shared IndexStore.
|
|
76
|
+
* The IndexStore receives its **own** MemoryCache instance so that
|
|
77
|
+
* `cache.clear()` inside it does not wipe the entity data cache.
|
|
78
|
+
*/
|
|
79
|
+
ensureIndexStore() {
|
|
80
|
+
if (!this.indexStore) {
|
|
81
|
+
const adapter = this.getAdapter();
|
|
82
|
+
if (!this.cache)
|
|
83
|
+
this.cache = new MemoryCache();
|
|
84
|
+
// IndexStore gets its own cache instance so that invalidateCache() → cache.clear()
|
|
85
|
+
// does NOT contaminate the entity data cache used by SheetRepository.
|
|
86
|
+
this.indexStore = new IndexStore(adapter, new MemoryCache());
|
|
87
|
+
}
|
|
88
|
+
return this.indexStore;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Ensure the sheet tab for a given schema exists, and register
|
|
92
|
+
* any declared secondary indexes with the IndexStore.
|
|
93
|
+
*
|
|
94
|
+
* @param schema - The table schema (name, fields, indexes).
|
|
95
|
+
* @param indexStore - The shared IndexStore.
|
|
96
|
+
* @returns The sheet adapter and whether it was freshly created.
|
|
97
|
+
*/
|
|
98
|
+
ensureTable(schema, indexStore) {
|
|
99
|
+
const adapter = this.getAdapter();
|
|
100
|
+
SheetOrmLogger.log(`[Registry] ensureTable "${schema.tableName}" (indexes=${schema.indexes.length})`);
|
|
101
|
+
// Check if the sheet tab already exists
|
|
102
|
+
let sheet = adapter.getSheetByName(schema.tableName);
|
|
103
|
+
let created = false;
|
|
104
|
+
if (!sheet) {
|
|
105
|
+
sheet = adapter.insertSheet(schema.tableName);
|
|
106
|
+
created = true;
|
|
107
|
+
}
|
|
108
|
+
SheetOrmLogger.log(`[Registry] ensureTable "${schema.tableName}" → ${created ? "insertSheet (G4 new)" : "existing sheet"}`);
|
|
109
|
+
// L1 optimisation: headers for newly-created sheets are deferred —
|
|
110
|
+
// they will be written together with the first data flush in
|
|
111
|
+
// SheetRepository, saving one GAS API call (~700 ms).
|
|
112
|
+
if (!created) {
|
|
113
|
+
// Nothing to do — existing sheet already has headers from a prior execution.
|
|
114
|
+
}
|
|
115
|
+
// If no indexes are defined, skip index table creation
|
|
116
|
+
if (schema.indexes.length === 0)
|
|
117
|
+
return { sheet, created };
|
|
118
|
+
if (!schema.indexTableName) {
|
|
119
|
+
throw new Error(`Table schema "${schema.tableName}" defines indexes but has no indexTableName. ` +
|
|
120
|
+
"Legacy per-field _idx_* indexes were removed; use a combined index table name (e.g. idx_ClassName).");
|
|
121
|
+
}
|
|
122
|
+
// Create the combined index sheet and register each field index
|
|
123
|
+
indexStore.createCombinedIndex(schema.indexTableName);
|
|
124
|
+
for (const idx of schema.indexes) {
|
|
125
|
+
indexStore.registerIndex(schema.indexTableName, idx.field, idx.unique ?? false);
|
|
126
|
+
}
|
|
127
|
+
return { sheet, created };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Register a Record subclass so it can be looked up by table name or
|
|
131
|
+
* class name via `getClassByName()`.
|
|
132
|
+
*/
|
|
133
|
+
registerClass(ctor) {
|
|
134
|
+
if (!this.classesByTable.has(ctor.tableName)) {
|
|
135
|
+
this.classesByTable.set(ctor.tableName, ctor);
|
|
136
|
+
}
|
|
137
|
+
if (ctor.name && !this.classesByName.has(ctor.name)) {
|
|
138
|
+
this.classesByName.set(ctor.name, ctor);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Return (or create) the SheetRepository for a given Record subclass.
|
|
143
|
+
*
|
|
144
|
+
* On first call for a table name the method:
|
|
145
|
+
* 1. Registers the class in the class map.
|
|
146
|
+
* 2. Builds a {@link TableSchema} from decorator metadata.
|
|
147
|
+
* 3. Ensures the sheet tab exists (createSheet / insertSheet).
|
|
148
|
+
* 4. Creates a new SheetRepository with all optimisation flags
|
|
149
|
+
* (L1 deferred headers, K2 index skipping, B5 known row count).
|
|
150
|
+
*
|
|
151
|
+
* Subsequent calls return the cached repository instance.
|
|
152
|
+
*/
|
|
153
|
+
ensureRepository(ctor) {
|
|
154
|
+
const tableName = ctor.tableName;
|
|
155
|
+
// Return cached repo if it already exists
|
|
156
|
+
if (this.repos.has(tableName)) {
|
|
157
|
+
SheetOrmLogger.log(`[Registry] ensureRepository "${tableName}" → cache hit`);
|
|
158
|
+
return this.repos.get(tableName);
|
|
159
|
+
}
|
|
160
|
+
SheetOrmLogger.log(`[Registry] ensureRepository "${tableName}" → creating`);
|
|
161
|
+
this.registerClass(ctor);
|
|
162
|
+
const indexStore = this.ensureIndexStore();
|
|
163
|
+
// Build schema from decorator metadata
|
|
164
|
+
const indexes = Decorators.getIndexes(ctor);
|
|
165
|
+
const schema = {
|
|
166
|
+
tableName,
|
|
167
|
+
// K2: only populate indexTableName when the class has @Indexed fields.
|
|
168
|
+
// Record.indexTableName always returns a string (e.g. "idx_Cars"), but for classes
|
|
169
|
+
// without indexes this causes every update/delete to call getSheetByName() on a
|
|
170
|
+
// non-existent index sheet, wasting ~700 ms per API call.
|
|
171
|
+
indexTableName: indexes.length > 0 ? ctor.indexTableName : undefined,
|
|
172
|
+
fields: Decorators.getFields(ctor),
|
|
173
|
+
indexes,
|
|
174
|
+
};
|
|
175
|
+
// Create the sheet tab (or get existing) and register indexes
|
|
176
|
+
const { sheet, created } = this.ensureTable(schema, indexStore);
|
|
177
|
+
// Construct the repository with performance optimisation flags:
|
|
178
|
+
// - sheet: pre-resolved ISheetAdapter (B7 cache seed)
|
|
179
|
+
// - created ? 0 : undefined: B5 known row count (0 for new sheets)
|
|
180
|
+
// - created: L1 defer header write to first data flush
|
|
181
|
+
const repo = new SheetRepository(this.getAdapter(), schema, indexStore, this.cache, undefined, sheet, created ? 0 : undefined, created);
|
|
182
|
+
this.repos.set(tableName, repo);
|
|
183
|
+
return repo;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Look up a previously registered Record subclass by constructor name
|
|
187
|
+
* or table name.
|
|
188
|
+
*/
|
|
189
|
+
getClassByName(name) {
|
|
190
|
+
return this.classesByName.get(name) ?? this.classesByTable.get(name);
|
|
191
|
+
}
|
|
192
|
+
/** Return the shared IndexStore (creates it if needed). */
|
|
193
|
+
getIndexStore() {
|
|
194
|
+
return this.ensureIndexStore();
|
|
195
|
+
}
|
|
196
|
+
/** Flush both the entity data cache and the index store caches. */
|
|
197
|
+
clearCache() {
|
|
198
|
+
if (this.cache)
|
|
199
|
+
this.cache.clear();
|
|
200
|
+
if (this.indexStore)
|
|
201
|
+
this.indexStore.clearAllCaches();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/** Singleton instance (lazy-initialised). */
|
|
205
|
+
Registry.instance = null;
|
|
206
|
+
//# sourceMappingURL=Registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Registry.js","sourceRoot":"","sources":["../../../src/core/Registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main CRUD and query interface for a single entity type.
|
|
3
|
+
*
|
|
4
|
+
* Each `SheetRepository<T>` manages one Google Sheets tab, converting
|
|
5
|
+
* between in-memory {@link Entity} objects and sheet rows via
|
|
6
|
+
* {@link Serialization}. Inspired by the Repository pattern from
|
|
7
|
+
* common ORM architectures (Hibernate, TypeORM, etc.).
|
|
8
|
+
*
|
|
9
|
+
* Performance optimisations (referenced by codename in comments):
|
|
10
|
+
* - **B5** — Known row count passed from Registry avoids getLastRow().
|
|
11
|
+
* - **B7** — `sheetCache` memoises the ISheetAdapter for the tab.
|
|
12
|
+
* - **K1** — Reuses physicalRowCount across saves inside saveAll().
|
|
13
|
+
* - **K2** — Skips index sheet lookup when the class has no @Indexed fields.
|
|
14
|
+
* - **L1** — Defers header write to the first data flush (saves ~700 ms).
|
|
15
|
+
* - **L2** — Bulk delete rewrite for delete-only batch commits.
|
|
16
|
+
*
|
|
17
|
+
* @module SheetRepository
|
|
18
|
+
*/
|
|
19
|
+
import type { Entity } from "../core/types/Entity.js";
|
|
20
|
+
import type { ISpreadsheetAdapter } from "../core/types/ISpreadsheetAdapter.js";
|
|
21
|
+
import type { ISheetAdapter } from "../core/types/ISheetAdapter.js";
|
|
22
|
+
import type { TableSchema } from "../core/types/TableSchema.js";
|
|
23
|
+
import type { QueryOptions } from "../core/types/QueryOptions.js";
|
|
24
|
+
import type { PaginatedResult } from "../core/types/PaginatedResult.js";
|
|
25
|
+
import type { GroupResult } from "../core/types/GroupResult.js";
|
|
26
|
+
import type { LifecycleHooks } from "../core/types/LifecycleHooks.js";
|
|
27
|
+
import type { ICacheProvider } from "../core/types/ICacheProvider.js";
|
|
28
|
+
import { IndexStore } from "../index/IndexStore.js";
|
|
29
|
+
import { Query } from "../query/Query.js";
|
|
30
|
+
/**
|
|
31
|
+
* Repository providing CRUD, query, pagination, and batch operations
|
|
32
|
+
* for entities of type `T` stored in a single Google Sheet tab.
|
|
33
|
+
*
|
|
34
|
+
* @typeParam T - Entity type managed by this repository.
|
|
35
|
+
*/
|
|
36
|
+
export declare class SheetRepository<T extends Entity> {
|
|
37
|
+
private adapter;
|
|
38
|
+
private schema;
|
|
39
|
+
private indexStore;
|
|
40
|
+
private cache;
|
|
41
|
+
private hooks;
|
|
42
|
+
private headers;
|
|
43
|
+
private idColIdx;
|
|
44
|
+
private requiredFields;
|
|
45
|
+
private defaultableFields;
|
|
46
|
+
private dataCacheKey;
|
|
47
|
+
private fieldMap;
|
|
48
|
+
/** Fast-lookup map: entity ID → 1-based sheet row index for O(1) row access. */
|
|
49
|
+
private idToRowIndex;
|
|
50
|
+
/** Buffered operations when a batch is active (beginBatch/commitBatch). */
|
|
51
|
+
private batchBuffer;
|
|
52
|
+
/**
|
|
53
|
+
* Entity batch accumulator used by saveAll().
|
|
54
|
+
* Each entry stores the entity, its serialised row, 0-based data index, and
|
|
55
|
+
* whether it is a "create" or "update". Flushed via flushEntityBatch().
|
|
56
|
+
*/
|
|
57
|
+
private entityBatch;
|
|
58
|
+
/** Cached sheet reference for the duration of saveAll() — avoids 1000× getSheetByName(). */
|
|
59
|
+
private batchSheet;
|
|
60
|
+
/** Row count captured once at saveAll() start — avoids 1000× getLastRow(). */
|
|
61
|
+
private batchBaseRowCount;
|
|
62
|
+
/** Cached entity array used by updateCacheAfterSave in batch mode — avoids 1000× cache.get() log calls. */
|
|
63
|
+
private batchCachedData;
|
|
64
|
+
/** Indexed fields metadata, cached for the duration of saveAll() — avoids 1000× getIndexedFields() array alloc. */
|
|
65
|
+
private batchIndexedFields;
|
|
66
|
+
/** Physical sheet row count, tracked to avoid repeated getLastRow() API calls in non-batch save sequences. */
|
|
67
|
+
private physicalRowCount;
|
|
68
|
+
/** True when idToRowIndex was built from a complete sheet scan (bootstrap or loadAllEntities/rowIndexById). */
|
|
69
|
+
private idToRowIndexComplete;
|
|
70
|
+
/** Memoized sheet reference — avoids repeated getSheetByName() API calls within a session (B7). */
|
|
71
|
+
private sheetCache;
|
|
72
|
+
/** Memoized set of indexed field names — avoids repeated getIndexedFields() array allocations in find(). */
|
|
73
|
+
private indexedFieldNames;
|
|
74
|
+
/** L1: true when headers haven't been written to the sheet yet (new sheet from ensureTable). */
|
|
75
|
+
private headersDeferred;
|
|
76
|
+
/**
|
|
77
|
+
* Constructs a new repository for the given table schema.
|
|
78
|
+
*
|
|
79
|
+
* @param adapter - Spreadsheet adapter providing sheet management.
|
|
80
|
+
* @param schema - Table schema (name, fields, indexes).
|
|
81
|
+
* @param indexStore - Shared IndexStore for secondary indexes.
|
|
82
|
+
* @param cache - Optional cache provider for in-memory row caching.
|
|
83
|
+
* @param hooks - Optional lifecycle hooks (onValidate, beforeSave, afterSave, beforeDelete, afterDelete).
|
|
84
|
+
* @param initialSheet - Pre-resolved sheet adapter (B7 optimisation).
|
|
85
|
+
* @param initialRowCount - Pre-fetched row count (B5 optimisation).
|
|
86
|
+
* @param headersDeferred - True if the sheet was just created and headers still need writing (L1).
|
|
87
|
+
*/
|
|
88
|
+
constructor(adapter: ISpreadsheetAdapter, schema: TableSchema, indexStore: IndexStore, cache?: ICacheProvider, hooks?: LifecycleHooks<T>, initialSheet?: ISheetAdapter, initialRowCount?: number, headersDeferred?: boolean);
|
|
89
|
+
/**
|
|
90
|
+
* Save (create or update) an entity.
|
|
91
|
+
*
|
|
92
|
+
* When a batch is active (see {@link beginBatch}), the operation is buffered
|
|
93
|
+
* and deferred until {@link commitBatch} is called. Otherwise delegates
|
|
94
|
+
* immediately to {@link doSave}.
|
|
95
|
+
*
|
|
96
|
+
* @param partial - Partial entity with optional `__id`.
|
|
97
|
+
* @returns The saved entity with system columns populated.
|
|
98
|
+
*/
|
|
99
|
+
save(partial: Partial<T> & {
|
|
100
|
+
__id?: string;
|
|
101
|
+
}): T;
|
|
102
|
+
/**
|
|
103
|
+
* Internal save implementation — resolves existence, validates, applies
|
|
104
|
+
* defaults, and writes to the sheet or buffers into an entity batch.
|
|
105
|
+
*
|
|
106
|
+
* @param partial - Partial entity data with optional `__id`.
|
|
107
|
+
* @returns Fully populated entity with system columns.
|
|
108
|
+
*/
|
|
109
|
+
private doSave;
|
|
110
|
+
/**
|
|
111
|
+
* Save multiple entities in a single optimised batch.
|
|
112
|
+
*
|
|
113
|
+
* 1. Captures the sheet reference and row count once (K1, B7).
|
|
114
|
+
* 2. Calls {@link doSave} for each entity — rows are buffered instead of
|
|
115
|
+
* written individually.
|
|
116
|
+
* 3. Flushes all buffered rows via {@link flushEntityBatch} (single API call).
|
|
117
|
+
* 4. Flushes index writes via {@link IndexStore.flushIndexBatch}.
|
|
118
|
+
*
|
|
119
|
+
* On error the batch state is fully reset and the cache is invalidated.
|
|
120
|
+
*
|
|
121
|
+
* @param entities - Array of partial entities to save.
|
|
122
|
+
* @returns Array of fully populated saved entities.
|
|
123
|
+
*/
|
|
124
|
+
saveAll(entities: Array<Partial<T>>): T[];
|
|
125
|
+
/**
|
|
126
|
+
* Find an entity by its primary key (`__id`).
|
|
127
|
+
*
|
|
128
|
+
* Uses a fast path when idToRowIndex + cache are populated, falling back
|
|
129
|
+
* to a full {@link loadAllEntities} scan otherwise.
|
|
130
|
+
*
|
|
131
|
+
* @param id - Entity `__id` value.
|
|
132
|
+
* @returns The matching entity or `null` if not found.
|
|
133
|
+
*/
|
|
134
|
+
findById(id: string): T | null;
|
|
135
|
+
/**
|
|
136
|
+
* Find entities matching query options (filter, sort, paginate, group).
|
|
137
|
+
*
|
|
138
|
+
* When a `search` operator targets an `@Indexed` field and a combined index
|
|
139
|
+
* sheet exists, the n-gram search index is used to narrow candidates before
|
|
140
|
+
* the full filter pipeline runs (Solr-like optimisation).
|
|
141
|
+
*
|
|
142
|
+
* @param options - Optional query options (where, whereGroups, orderBy, offset, limit).
|
|
143
|
+
* @returns Array of matching entities.
|
|
144
|
+
*/
|
|
145
|
+
find(options?: QueryOptions): T[];
|
|
146
|
+
/**
|
|
147
|
+
* Find the first entity matching query options.
|
|
148
|
+
*
|
|
149
|
+
* Delegates to {@link find} with `limit: 1`.
|
|
150
|
+
*
|
|
151
|
+
* @param options - Optional query options.
|
|
152
|
+
* @returns The first matching entity or `null`.
|
|
153
|
+
*/
|
|
154
|
+
findOne(options?: QueryOptions): T | null;
|
|
155
|
+
/**
|
|
156
|
+
* Delete an entity by ID.
|
|
157
|
+
*
|
|
158
|
+
* When a batch is active, the delete is queued and `true` is returned
|
|
159
|
+
* immediately; actual removal happens on {@link commitBatch}.
|
|
160
|
+
*
|
|
161
|
+
* @param id - Entity `__id` to delete.
|
|
162
|
+
* @returns `true` if the entity was found and deleted (or queued).
|
|
163
|
+
*/
|
|
164
|
+
delete(id: string): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Internal delete implementation.
|
|
167
|
+
*
|
|
168
|
+
* 1. Runs `beforeDelete` lifecycle hook (can veto deletion by returning `false`).
|
|
169
|
+
* 2. Resolves the row index via in-memory cache or sheet scan.
|
|
170
|
+
* 3. Removes from secondary indexes.
|
|
171
|
+
* 4. Deletes the sheet row and adjusts `idToRowIndex`.
|
|
172
|
+
* 5. Updates entity cache and runs `afterDelete` hook.
|
|
173
|
+
*
|
|
174
|
+
* @param id - Entity `__id` to delete.
|
|
175
|
+
* @returns `true` if the entity was found and deleted.
|
|
176
|
+
*/
|
|
177
|
+
private doDelete;
|
|
178
|
+
/**
|
|
179
|
+
* Delete all entities matching a query (or all entities if no options given).
|
|
180
|
+
*
|
|
181
|
+
* Uses bulk write (replaceAllData) for 3+ deletions — two API calls instead
|
|
182
|
+
* of N individual deleteRow() calls. For 1–2 deletions, individual deletes
|
|
183
|
+
* are cheaper due to lower overhead.
|
|
184
|
+
*
|
|
185
|
+
* @param options - Optional query options to select entities to delete.
|
|
186
|
+
* @returns Number of entities deleted.
|
|
187
|
+
*/
|
|
188
|
+
deleteAll(options?: QueryOptions): number;
|
|
189
|
+
/**
|
|
190
|
+
* Count entities matching a query.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Optional query options (only `where`/`whereGroups` are meaningful).
|
|
193
|
+
* @returns Total count of matching entities.
|
|
194
|
+
*/
|
|
195
|
+
count(options?: QueryOptions): number;
|
|
196
|
+
/**
|
|
197
|
+
* Paginated select — applies optional filters, then paginates.
|
|
198
|
+
*
|
|
199
|
+
* @param offset - 0-based offset.
|
|
200
|
+
* @param limit - Maximum number of results.
|
|
201
|
+
* @param options - Optional query options applied before pagination.
|
|
202
|
+
* @returns {@link PaginatedResult} with `data`, `total`, `offset`, and `limit`.
|
|
203
|
+
*/
|
|
204
|
+
select(offset: number, limit: number, options?: QueryOptions): PaginatedResult<T>;
|
|
205
|
+
/**
|
|
206
|
+
* Group entities by a field value.
|
|
207
|
+
*
|
|
208
|
+
* @param field - Field name to group by.
|
|
209
|
+
* @param options - Optional query options applied before grouping.
|
|
210
|
+
* @returns Array of {@link GroupResult} objects.
|
|
211
|
+
*/
|
|
212
|
+
groupBy(field: string, options?: QueryOptions): GroupResult<T>[];
|
|
213
|
+
/**
|
|
214
|
+
* Create a fluent {@link Query} builder for this repository.
|
|
215
|
+
*
|
|
216
|
+
* @returns A new Query instance backed by a snapshot of all current entities.
|
|
217
|
+
*/
|
|
218
|
+
query(): Query<T>;
|
|
219
|
+
/**
|
|
220
|
+
* Start buffering save/delete operations for later atomic commit.
|
|
221
|
+
*
|
|
222
|
+
* Call {@link commitBatch} to apply all buffered operations, or
|
|
223
|
+
* {@link rollbackBatch} to discard them.
|
|
224
|
+
*/
|
|
225
|
+
beginBatch(): void;
|
|
226
|
+
/**
|
|
227
|
+
* Commit all buffered operations from {@link beginBatch}.
|
|
228
|
+
*
|
|
229
|
+
* L2 optimisation: if the buffer contains only deletes, a bulk rewrite
|
|
230
|
+
* (replaceAllData) is used instead of N individual deleteRow() calls.
|
|
231
|
+
*/
|
|
232
|
+
commitBatch(): void;
|
|
233
|
+
/**
|
|
234
|
+
* Commit a delete-only batch via bulk replaceAllData.
|
|
235
|
+
*
|
|
236
|
+
* Falls back to per-ID deletes for tiny (≤2) or duplicate-heavy batches
|
|
237
|
+
* to preserve semantics and avoid unnecessary full-sheet rewrites.
|
|
238
|
+
*
|
|
239
|
+
* @param ids - Array of entity IDs to delete.
|
|
240
|
+
*/
|
|
241
|
+
private commitDeleteBatch;
|
|
242
|
+
/**
|
|
243
|
+
* Discard all buffered operations without applying them.
|
|
244
|
+
*/
|
|
245
|
+
rollbackBatch(): void;
|
|
246
|
+
/**
|
|
247
|
+
* Check whether batch mode is currently active.
|
|
248
|
+
*
|
|
249
|
+
* @returns `true` when {@link beginBatch} was called but not yet committed or rolled back.
|
|
250
|
+
*/
|
|
251
|
+
isBatchActive(): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Return the memoised ISheetAdapter for this table, resolving it once
|
|
254
|
+
* from the spreadsheet adapter and caching it for subsequent calls (B7).
|
|
255
|
+
*
|
|
256
|
+
* @throws Error if the sheet doesn't exist.
|
|
257
|
+
*/
|
|
258
|
+
private getSheet;
|
|
259
|
+
/**
|
|
260
|
+
* Load all entities from the sheet, deserialise them, and populate the cache.
|
|
261
|
+
*
|
|
262
|
+
* Returns the cached array on a cache hit. On a cache miss, reads all rows
|
|
263
|
+
* from the sheet, converts them via {@link Serialization.rowToEntity},
|
|
264
|
+
* builds {@link idToRowIndex}, and stores the result.
|
|
265
|
+
*
|
|
266
|
+
* @throws Error if called during an active entity batch (saveAll).
|
|
267
|
+
* @returns Array of all entities in the table.
|
|
268
|
+
*/
|
|
269
|
+
private loadAllEntities;
|
|
270
|
+
/**
|
|
271
|
+
* Find the 0-based data row index for an entity by its `__id` via a full
|
|
272
|
+
* sheet scan. Rebuilds {@link idToRowIndex} as a side-effect.
|
|
273
|
+
*
|
|
274
|
+
* @param sheet - The sheet adapter to read from.
|
|
275
|
+
* @param id - Entity `__id` to search for.
|
|
276
|
+
* @returns 0-based row index, or `null` if not found.
|
|
277
|
+
*/
|
|
278
|
+
private rowIndexById;
|
|
279
|
+
/**
|
|
280
|
+
* Add a newly-created entity to all relevant secondary indexes.
|
|
281
|
+
*
|
|
282
|
+
* In batch mode, uses pre-cached {@link batchIndexedFields} to avoid
|
|
283
|
+
* repeated `getIndexedFields()` allocations.
|
|
284
|
+
*
|
|
285
|
+
* @param entity - The entity to index.
|
|
286
|
+
*/
|
|
287
|
+
private addToIndexes;
|
|
288
|
+
/**
|
|
289
|
+
* Flush all buffered entity rows to the sheet in a single API call.
|
|
290
|
+
*
|
|
291
|
+
* Called at the end of {@link saveAll}. Sorts buffered entries by
|
|
292
|
+
* `dataIndex` to build a contiguous row array, then writes them via
|
|
293
|
+
* `sheet.updateRows()` (or `writeAllRowsWithHeaders` for the L1 path).
|
|
294
|
+
*
|
|
295
|
+
* @param sheet - The sheet adapter to write to.
|
|
296
|
+
*/
|
|
297
|
+
private flushEntityBatch;
|
|
298
|
+
/** Shallow-clone an entity to prevent external mutation of cached data. */
|
|
299
|
+
private cloneEntity;
|
|
300
|
+
/** Shallow-clone an array of entities. */
|
|
301
|
+
private cloneEntities;
|
|
302
|
+
/**
|
|
303
|
+
* Update the entity cache in place after a save (create or update).
|
|
304
|
+
*
|
|
305
|
+
* In batch mode, reuses {@link batchCachedData} to avoid repeated
|
|
306
|
+
* `cache.get()` calls that would trigger verbose logging overhead.
|
|
307
|
+
*
|
|
308
|
+
* @param entity - The saved entity.
|
|
309
|
+
* @param isNew - Whether this was a create (append) or update (replace).
|
|
310
|
+
*/
|
|
311
|
+
private updateCacheAfterSave;
|
|
312
|
+
/**
|
|
313
|
+
* Remove a deleted entity from the entity cache.
|
|
314
|
+
*
|
|
315
|
+
* Note: {@link idToRowIndex} is updated separately in {@link doDelete}.
|
|
316
|
+
* This method only handles the entity array cache.
|
|
317
|
+
*
|
|
318
|
+
* @param id - The `__id` of the deleted entity.
|
|
319
|
+
*/
|
|
320
|
+
private updateCacheAfterDelete;
|
|
321
|
+
/**
|
|
322
|
+
* Check whether a field name has an `@Indexed` decorator.
|
|
323
|
+
*
|
|
324
|
+
* Uses the pre-built {@link indexedFieldNames} set for O(1) lookup.
|
|
325
|
+
*
|
|
326
|
+
* @param fieldName - Name of the field to check.
|
|
327
|
+
* @returns `true` if the field is indexed.
|
|
328
|
+
*/
|
|
329
|
+
private isIndexedField;
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=SheetRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SheetRepository.d.ts","sourceRoot":"","sources":["../../../src/core/SheetRepository.ts"],"names":[],"mappings":"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"}
|