tantan-typeorm-gs 1.0.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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/bun.lock +300 -0
  4. package/docs/authentication.md +118 -0
  5. package/docs/configuration.md +680 -0
  6. package/docs/contributing.md +177 -0
  7. package/docs/crud.md +351 -0
  8. package/docs/custom-client.md +165 -0
  9. package/docs/development.md +243 -0
  10. package/docs/entities.md +502 -0
  11. package/docs/find-options.md +296 -0
  12. package/docs/google-cloud.md +101 -0
  13. package/docs/installation.md +51 -0
  14. package/docs/integration-testing.md +178 -0
  15. package/docs/limitations.md +223 -0
  16. package/docs/pagination.md +384 -0
  17. package/docs/performance.md +171 -0
  18. package/docs/security.md +153 -0
  19. package/docs/sorting.md +0 -0
  20. package/docs/supported-features.md +310 -0
  21. package/docs/synchronization.md +203 -0
  22. package/package.json +43 -0
  23. package/src/client/index.ts +589 -0
  24. package/src/core/data-source.ts +47 -0
  25. package/src/core/driver.ts +290 -0
  26. package/src/core/error.ts +144 -0
  27. package/src/core/memory.ts +152 -0
  28. package/src/core/query/interpreter.ts +949 -0
  29. package/src/core/query/runner.ts +1297 -0
  30. package/src/core/query/types.ts +155 -0
  31. package/src/core/schema-builder.ts +64 -0
  32. package/src/core/types.ts +113 -0
  33. package/src/core/utils.ts +13 -0
  34. package/src/index.ts +3 -0
  35. package/tantan-typeorm-gs.code-workspace +8 -0
  36. package/test/base/0001-data-source.test.ts +252 -0
  37. package/test/base/0002-operator.test.ts +616 -0
  38. package/test/base/0003-select.test.ts +281 -0
  39. package/test/base/0004-aggregate.test.ts +213 -0
  40. package/test/base/0005-transcation.test.ts +1566 -0
  41. package/test/base/0006-relation.test.ts +1611 -0
  42. package/test/base/0007-logging.test.ts +182 -0
  43. package/test/base/0008-soft-delete.test.ts +649 -0
  44. package/test/google-sheets/0001-client.test.ts +1705 -0
  45. package/test/google-sheets/0002-worksheet-management.test.ts +408 -0
  46. package/test/google-sheets/0003-data-source.test.ts +1935 -0
  47. package/test/google-sheets/0004-transactions.test.ts +952 -0
  48. package/test/google-sheets/0005-operator.test.ts +1124 -0
  49. package/test/google-sheets/0006-object-criteria.test.ts +283 -0
  50. package/test/google-sheets/0007-performance.test.ts +532 -0
  51. package/test/public-api.test.ts +34 -0
  52. package/tsconfig.build.json +21 -0
  53. package/tsconfig.json +34 -0
@@ -0,0 +1,171 @@
1
+ ## Performance Considerations
2
+
3
+ Google Sheets is an API-based spreadsheet service rather than a database engine.
4
+
5
+ The performance of the driver therefore depends on several factors, including worksheet size, number of API requests, operation type, and network latency.
6
+
7
+ ### Avoid Treating Google Sheets as a Large Database
8
+
9
+ The driver is intended for workloads where Google Sheets is an appropriate data store.
10
+
11
+ For large datasets or high-frequency database workloads, a relational database is generally more appropriate.
12
+
13
+ Operations such as:
14
+
15
+ ```ts id="8m2q5v"
16
+ const users = await repository.find();
17
+ ```
18
+
19
+ may require processing a significant number of worksheet rows.
20
+
21
+ Applications should avoid loading an entire large worksheet when only a small subset of data is required.
22
+
23
+ ### Use Filtering
24
+
25
+ When only specific records are required, use `where` conditions:
26
+
27
+ ```ts id="4x7n1c"
28
+ const users = await repository.find({
29
+ where: {
30
+ status: "active"
31
+ }
32
+ });
33
+ ```
34
+
35
+ This avoids unnecessarily returning unrelated records to the application.
36
+
37
+ ### Use Pagination
38
+
39
+ For user-facing lists, combine filtering, sorting, and pagination:
40
+
41
+ ```ts id="9p3k6w"
42
+ const page = 1;
43
+ const pageSize = 20;
44
+
45
+ const users = await repository.find({
46
+ where: {
47
+ status: "active"
48
+ },
49
+
50
+ order: {
51
+ id: "ASC"
52
+ },
53
+
54
+ skip: (page - 1) * pageSize,
55
+
56
+ take: pageSize
57
+ });
58
+ ```
59
+
60
+ Pagination limits the number of records returned to the application at once.
61
+
62
+ However, `skip` and `take` should not be considered equivalent to indexed database pagination.
63
+
64
+ ### Prefer Batch Operations
65
+
66
+ When multiple records need to be modified, use repository operations that allow the driver to process multiple rows together.
67
+
68
+ For example:
69
+
70
+ ```ts id="6v4m8q"
71
+ await repository.insert([
72
+ {
73
+ name: "Budi"
74
+ },
75
+ {
76
+ name: "Andi"
77
+ },
78
+ {
79
+ name: "Citra"
80
+ }
81
+ ]);
82
+ ```
83
+
84
+ The Google Sheets API client supports batching compatible operations to reduce unnecessary API requests.
85
+
86
+ ### Minimize API Requests
87
+
88
+ The default `GoogleSheetsApiClient` communicates with Google Sheets through the Google Sheets API.
89
+
90
+ Network requests generally have significantly higher overhead than in-memory operations.
91
+
92
+ Applications should therefore avoid unnecessarily repeating operations such as:
93
+
94
+ ```ts id="1c5x7m"
95
+ await repository.find();
96
+ await repository.find();
97
+ await repository.find();
98
+ ```
99
+
100
+ when the same result can safely be reused by the application.
101
+
102
+ ### Custom Client for Specialized Workloads
103
+
104
+ Applications with specialized performance requirements can provide a custom `GoogleSheetsClient`.
105
+
106
+ A custom client can implement application-specific strategies such as:
107
+
108
+ - caching
109
+ - request batching
110
+ - retry handling
111
+ - request deduplication
112
+ - custom transport behavior
113
+
114
+ The driver remains independent of those implementation details.
115
+
116
+ ### Performance Baseline
117
+
118
+ The project's automated performance tests include a basic baseline using `Memory`.
119
+
120
+ The current baseline tested:
121
+
122
+ | Operation | Dataset | Result |
123
+ | --------- | ---------: | --------: |
124
+ | Insert | 1,000 rows | ~25.64 ms |
125
+ | Read | 1,000 rows | ~10.96 ms |
126
+
127
+ These measurements are useful as regression indicators for the driver implementation.
128
+
129
+ They **must not** be interpreted as Google Sheets API production performance benchmarks.
130
+
131
+ The test uses an in-memory fake client and therefore does not include network latency, Google API processing time, authentication, quotas, or real spreadsheet behavior.
132
+
133
+ ### Performance Testing
134
+
135
+ Performance tests can be run independently from the normal test suite:
136
+
137
+ ```bash id="2q8n4x"
138
+ bun test test/google-sheets/0007-performance.test.ts
139
+ ```
140
+
141
+ The tests currently use a relatively loose regression threshold rather than guaranteeing a specific execution time.
142
+
143
+ This is intentional because execution time can vary between development machines and CI environments.
144
+
145
+ ### When to Consider a Database
146
+
147
+ Consider using a relational database instead when the workload requires:
148
+
149
+ - large datasets
150
+ - high-frequency reads and writes
151
+ - complex queries
152
+ - low-latency database operations
153
+ - transactions
154
+ - concurrent write-heavy workloads
155
+ - database indexes and query planning
156
+
157
+ Google Sheets is better suited when human spreadsheet access, simplicity, and integration with Google Workspace are important requirements.
158
+
159
+ ### Summary
160
+
161
+ For better performance:
162
+
163
+ 1. Query only the data that is needed.
164
+ 2. Use filtering with `where`.
165
+ 3. Use deterministic sorting with pagination.
166
+ 4. Prefer batch operations for multiple records.
167
+ 5. Minimize unnecessary API requests.
168
+ 6. Use a custom client when application-specific caching or transport behavior is required.
169
+ 7. Use a relational database when the workload exceeds the practical characteristics of a spreadsheet.
170
+
171
+ Performance should be evaluated using the application's actual workload rather than relying solely on the driver's local baseline tests.
@@ -0,0 +1,153 @@
1
+ ## Security
2
+
3
+ The Google Sheets driver requires access to a Google Cloud service account and a target spreadsheet.
4
+
5
+ Security therefore depends on protecting both the authentication credentials and the spreadsheet itself.
6
+
7
+ ### Protect Service Account Credentials
8
+
9
+ The default Google Sheets client requires:
10
+
11
+ ```ts
12
+ credentials: {
13
+ clientEmail: '...',
14
+ privateKey: '...',
15
+ }
16
+ ```
17
+
18
+ The `privateKey` is sensitive and must be protected.
19
+
20
+ Do not:
21
+
22
+ - commit service account credentials to source control
23
+ - expose the private key in client-side code
24
+ - include credentials in public repositories
25
+ - log the private key
26
+ - send credentials to untrusted services
27
+
28
+ Environment variables are recommended for local and server deployments:
29
+
30
+ ```env id="7k2p4m"
31
+ GOOGLE_SHEETS_CLIENT_EMAIL=...
32
+ GOOGLE_SHEETS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
33
+ ```
34
+
35
+ The application can then load these values when creating the data source.
36
+
37
+ ### Spreadsheet Access
38
+
39
+ The service account must have access to the target spreadsheet.
40
+
41
+ Access should follow the principle of least privilege:
42
+
43
+ - grant access only to the spreadsheets required by the application
44
+ - avoid sharing unrelated spreadsheets
45
+ - remove access when the service account is no longer needed
46
+ - review spreadsheet sharing permissions periodically
47
+
48
+ The driver does not bypass Google Sheets permissions. Access is ultimately controlled by Google.
49
+
50
+ ### Spreadsheet ID
51
+
52
+ The spreadsheet ID identifies the target spreadsheet:
53
+
54
+ ```ts id="3q8v1n"
55
+ const dataSource = createGoogleSheetsDataSource({
56
+ type: "google-sheets",
57
+
58
+ spreadsheetId: process.env.GOOGLE_SHEETS_SPREADSHEET_ID!
59
+
60
+ // ...
61
+ });
62
+ ```
63
+
64
+ The spreadsheet ID is generally not considered a secret by itself.
65
+
66
+ However, it should still be treated as application configuration because it identifies the resource the application intends to access.
67
+
68
+ ### Private Key Formatting
69
+
70
+ When the private key is stored in an environment variable, escaped newline characters may need to be converted to actual newline characters:
71
+
72
+ ```ts id="6m4x9p"
73
+ const privateKey = process.env.GOOGLE_SHEETS_PRIVATE_KEY!.replace(/\\n/g, "\n");
74
+ ```
75
+
76
+ This should be done before passing the key to the Google authentication client when the deployment environment stores the key with escaped newlines.
77
+
78
+ ### Do Not Log Credentials
79
+
80
+ Application logging should never include:
81
+
82
+ ```text id="1v7c5q"
83
+ clientEmail
84
+ privateKey
85
+ access tokens
86
+ authorization headers
87
+ ```
88
+
89
+ If query or API logging is enabled for debugging, ensure that sensitive authentication information is not included in the logged output.
90
+
91
+ ### Custom Client Security
92
+
93
+ A custom `GoogleSheetsClient` becomes part of the application's security boundary.
94
+
95
+ For example, a custom client may implement:
96
+
97
+ - authentication
98
+ - caching
99
+ - request logging
100
+ - retry handling
101
+ - alternative transports
102
+
103
+ These implementations must follow the same security requirements as the default client.
104
+
105
+ In particular, custom logging should not expose credentials or authorization data.
106
+
107
+ ### Production Credentials
108
+
109
+ For production deployments:
110
+
111
+ - store credentials in a secure secret-management system when available
112
+ - restrict service-account permissions
113
+ - rotate credentials according to the organization's security policy
114
+ - avoid storing private keys directly in source code
115
+ - restrict access to deployment configuration
116
+
117
+ The exact secret-management mechanism depends on the deployment environment.
118
+
119
+ ### Synchronization Security
120
+
121
+ `Synchronize` and `dropSchema` can modify worksheet structure.
122
+
123
+ They should therefore be treated as privileged configuration in production.
124
+
125
+ Do not enable destructive schema operations in production unless the application intentionally requires them and the consequences are understood.
126
+
127
+ ### Data Sensitivity
128
+
129
+ The driver does not encrypt spreadsheet data at the application layer.
130
+
131
+ If sensitive information is stored in Google Sheets, the application should consider:
132
+
133
+ - who can access the spreadsheet
134
+ - which service accounts have access
135
+ - whether the data should be stored in a spreadsheet at all
136
+ - whether additional application-level encryption is required
137
+
138
+ Google Sheets should not automatically be considered an appropriate storage location for highly sensitive data.
139
+
140
+ ### Security Summary
141
+
142
+ The main security responsibilities are:
143
+
144
+ 1. Protect the service account private key.
145
+ 2. Keep credentials out of source control.
146
+ 3. Restrict spreadsheet permissions.
147
+ 4. Avoid logging authentication information.
148
+ 5. Treat custom clients as part of the security boundary.
149
+ 6. Use secure secret storage in production.
150
+ 7. Be careful with `synchronize` and `dropSchema`.
151
+ 8. Evaluate whether sensitive data belongs in Google Sheets.
152
+
153
+ The driver provides the integration layer, while authentication, authorization, credential management, and data classification remain application and infrastructure responsibilities.
File without changes
@@ -0,0 +1,310 @@
1
+ ## Supported Features
2
+
3
+ The Google Sheets driver supports a subset of TypeORM features that are applicable to Google Sheets.
4
+
5
+ The following table summarizes the currently supported functionality.
6
+
7
+ ### Data Source
8
+
9
+ | Feature | Status |
10
+ | --------------------------- | --------- |
11
+ | Google Sheets data source | Supported |
12
+ | Custom Google Sheets client | Supported |
13
+ | Multiple entities | Supported |
14
+ | Entity subscribers | Supported |
15
+ | Entity lifecycle hooks | Supported |
16
+ | Synchronization | Supported |
17
+ | Logging configuration | Supported |
18
+
19
+ ### CRUD
20
+
21
+ | Operation | Status |
22
+ | ------------------- | --------- |
23
+ | `insert()` | Supported |
24
+ | `save()` | Supported |
25
+ | `find()` | Supported |
26
+ | `findOne()` | Supported |
27
+ | `update()` | Supported |
28
+ | `delete()` | Supported |
29
+ | `remove()` | Supported |
30
+ | `softDelete()` | Supported |
31
+ | `restore()` | Supported |
32
+ | `softRemove()` | Supported |
33
+ | Multiple-row insert | Supported |
34
+ | Multiple-row update | Supported |
35
+ | Multiple-row delete | Supported |
36
+
37
+ `save()` supports normal entity persistence and column-based foreign-key values.
38
+
39
+ Nested relation persistence and cascade persistence are not fully supported. See [Limitations](#limitations) for details.
40
+
41
+ ### Find Options
42
+
43
+ | Feature | Status |
44
+ | ------------------------------- | --------- |
45
+ | `where` | Supported |
46
+ | OR conditions using `where: []` | Supported |
47
+ | `order` | Supported |
48
+ | Multiple-field ordering | Supported |
49
+ | `skip` | Supported |
50
+ | `take` | Supported |
51
+ | `findAndCount()` | Supported |
52
+ | `count()` | Supported |
53
+ | `findOne()` with `where` | Supported |
54
+ | `findOne()` with `order` | Supported |
55
+ | `withDeleted` | Supported |
56
+
57
+ ### Primary Keys
58
+
59
+ | Feature | Status |
60
+ | ------------------------------- | ------------- |
61
+ | `@PrimaryColumn()` | Supported |
62
+ | `@PrimaryGeneratedColumn()` | Supported |
63
+ | Increment generated IDs | Supported |
64
+ | UUID generated IDs | Supported |
65
+ | Explicit generated primary key | Supported |
66
+ | Duplicate primary key detection | Supported |
67
+ | Missing primary key detection | Supported |
68
+ | `identity` generation strategy | Not supported |
69
+ | `rowid` generation strategy | Not supported |
70
+
71
+ When an explicit generated primary key is supplied, the driver preserves the supplied value and checks for duplicates.
72
+
73
+ ### Data Types
74
+
75
+ The driver uses TypeORM entity metadata to interpret worksheet values and hydrate them into the expected entity types.
76
+
77
+ | Type | Status |
78
+ | --------- | --------- |
79
+ | `string` | Supported |
80
+ | `number` | Supported |
81
+ | `boolean` | Supported |
82
+ | `Date` | Supported |
83
+ | `uuid` | Supported |
84
+ | `int` | Supported |
85
+ | `null` | Supported |
86
+
87
+ Google Sheets commonly returns cell values as strings. The driver performs type conversion based on the corresponding TypeORM column metadata.
88
+
89
+ For example:
90
+
91
+ ```ts
92
+ id: 1
93
+ age: 30
94
+ active: true
95
+ createdAt: new Date(...)
96
+ ```
97
+
98
+ are hydrated as their corresponding TypeScript runtime values rather than being returned as raw worksheet strings.
99
+
100
+ ### Entity Metadata
101
+
102
+ | Feature | Status |
103
+ | -------------------------- | -------------------------------------------- |
104
+ | Entity metadata resolution | Supported |
105
+ | Custom worksheet names | Supported |
106
+ | Custom column names | Supported |
107
+ | Naming strategies | Supported through TypeORM-generated metadata |
108
+ | Create date columns | Supported |
109
+ | Update date columns | Supported |
110
+ | Delete date columns | Supported |
111
+ | Relation metadata | Supported |
112
+ | Relation loading | Supported |
113
+
114
+ ### Relations
115
+
116
+ Basic relation metadata, relation loading, and supported JOIN operations are supported.
117
+
118
+ For example:
119
+
120
+ ```ts
121
+ id: 1
122
+ ```
123
+
124
+ ```ts
125
+ const post = await repository.findOne({
126
+ where: {
127
+ id: 1
128
+ },
129
+
130
+ relations: {
131
+ author: true
132
+ }
133
+ });
134
+ ```
135
+
136
+ Relations can also be represented through explicit foreign-key columns:
137
+
138
+ ```ts
139
+ post.userId = user.id;
140
+
141
+ await postRepository.save(post);
142
+ ```
143
+
144
+ However, Google Sheets does not provide database-level relational features such as foreign-key constraints or referential integrity.
145
+
146
+ Nested relation persistence and cascade operations are not fully supported.
147
+
148
+ ### Soft Delete
149
+
150
+ Soft-delete operations using TypeORM delete-date metadata are supported.
151
+
152
+ For example:
153
+
154
+ ```ts
155
+ @DeleteDateColumn({
156
+ nullable: true,
157
+ })
158
+ deletedAt!: Date | null;
159
+ ```
160
+
161
+ The driver supports:
162
+
163
+ * `softDelete()`
164
+ * `softRemove()`
165
+ * `restore()`
166
+ * filtering soft-deleted rows from normal queries
167
+ * `withDeleted`
168
+ * soft-delete filtering when loading supported relations
169
+
170
+ Soft deletion remains an application-level operation because Google Sheets does not provide database-level soft-delete semantics.
171
+
172
+ ### Lifecycle Hooks
173
+
174
+ The driver supports relevant TypeORM entity lifecycle hooks, including:
175
+
176
+ ```text
177
+ @BeforeInsert
178
+ @AfterInsert
179
+
180
+ @BeforeUpdate
181
+ @AfterUpdate
182
+
183
+ @BeforeRemove
184
+ @AfterRemove
185
+
186
+ @AfterLoad
187
+ ```
188
+
189
+ Entity subscribers are also supported.
190
+
191
+ ### Query Runner
192
+
193
+ The driver provides a `QueryRunner` implementation for supported Google Sheets operations.
194
+
195
+ Supported query operations include the operations implemented by the Google Sheets query interpreter and query runner.
196
+
197
+ Unsupported operations are rejected by the driver rather than silently executed with potentially incorrect semantics.
198
+
199
+ ### Batch Operations
200
+
201
+ The Google Sheets API client supports batching compatible operations to reduce the number of API requests.
202
+
203
+ This includes:
204
+
205
+ * multiple-row reads
206
+ * multiple-row inserts
207
+ * multiple-row updates
208
+ * multiple-row deletes
209
+
210
+ Non-contiguous updates may require separate API requests when the underlying ranges cannot be combined safely.
211
+
212
+ ### Transactions
213
+
214
+ Database transactions are **not supported**.
215
+
216
+ Google Sheets does not provide transactional semantics equivalent to a relational database.
217
+
218
+ Applications should not rely on:
219
+
220
+ ```ts
221
+ dataSource.transaction(...)
222
+ ```
223
+
224
+ for atomic multi-operation behavior.
225
+
226
+ See [Limitations](#limitations) for details.
227
+
228
+ ### Migrations
229
+
230
+ Migration-related configuration is exposed through the data source options, but traditional relational database migrations are not supported as a full database migration mechanism.
231
+
232
+ Schema changes should instead be handled through worksheet synchronization and the schema-management capabilities provided by the driver.
233
+
234
+ ### Synchronization
235
+
236
+ Schema synchronization is supported for worksheet structures.
237
+
238
+ The driver can:
239
+
240
+ * create missing worksheets
241
+ * create worksheet headers
242
+ * add missing columns to existing worksheets
243
+
244
+ Synchronization operates on worksheet structure rather than relational database schema objects.
245
+
246
+ ### Logging
247
+
248
+ TypeORM logging configuration is supported.
249
+
250
+ For example:
251
+
252
+ ```ts
253
+ const dataSource = new DataSource({
254
+ type: 'google-sheets',
255
+
256
+ logging: [
257
+ 'query',
258
+ 'error',
259
+ 'schema',
260
+ ],
261
+ });
262
+ ```
263
+
264
+ The driver integrates with TypeORM's logger for supported query, error, and schema operations.
265
+
266
+ ### Custom Client
267
+
268
+ Applications can provide a custom `GoogleSheetsClient` implementation instead of using the default Google Sheets API client.
269
+
270
+ This can be useful for:
271
+
272
+ * testing
273
+ * custom transport implementations
274
+ * alternative data sources
275
+ * controlling API behavior
276
+
277
+ ### Feature Compatibility Principle
278
+
279
+ TypeORM exposes a large API surface because it supports many relational database systems.
280
+
281
+ The presence of a TypeORM option does not automatically mean that the Google Sheets driver supports that option.
282
+
283
+ Applications should rely on the capabilities documented by this driver and its tests rather than assuming full relational-database compatibility.
284
+
285
+ ### Summary
286
+
287
+ The driver currently provides:
288
+
289
+ ```text
290
+ TypeORM Repository
291
+ │
292
+ ├── CRUD
293
+ ├── Find Options
294
+ ├── Sorting
295
+ ├── Pagination
296
+ ├── Type Conversion
297
+ ├── Generated IDs
298
+ ├── Soft Delete
299
+ ├── Lifecycle Hooks
300
+ ├── Subscribers
301
+ ├── Relations / Relation Loading
302
+ ├── Synchronization
303
+ ├── Logging
304
+ └── Custom Client
305
+ │
306
+ ▼
307
+ Google Sheets
308
+ ```
309
+
310
+ Features that depend on relational-database guarantees, such as transactions, foreign-key enforcement, database-level cascades, and full relational persistence semantics, are outside the capabilities of Google Sheets.