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,532 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import
3
+ {
4
+ Column,
5
+ Entity,
6
+ PrimaryGeneratedColumn,
7
+ } from 'typeorm';
8
+ import { Memory } from '../../src/core/memory';
9
+ import { createGoogleSheetsDataSource, type GoogleSheetsRow } from '../../src';
10
+
11
+
12
+ describe(
13
+ 'Google Sheets API Performance',
14
+ () =>
15
+ {
16
+ @Entity('performance_users')
17
+ class PerformanceUser
18
+ {
19
+ @PrimaryGeneratedColumn()
20
+ id!: number;
21
+
22
+ @Column()
23
+ name!: string;
24
+
25
+ @Column()
26
+ email!: string;
27
+ }
28
+
29
+ async function createDataSource(
30
+ rows: GoogleSheetsRow[] = [],
31
+ )
32
+ {
33
+ const client =
34
+ new Memory({
35
+ performance_users: rows,
36
+ });
37
+
38
+ await client.insertHeaders(
39
+ 'performance_users',
40
+ [
41
+ 'id',
42
+ 'name',
43
+ 'email',
44
+ ],
45
+ );
46
+
47
+ const dataSource =
48
+ createGoogleSheetsDataSource({
49
+ type: 'google-sheets',
50
+ client,
51
+ entities: [
52
+ PerformanceUser,
53
+ ],
54
+ });
55
+
56
+ await dataSource.initialize();
57
+
58
+ return {
59
+ client,
60
+ dataSource,
61
+ };
62
+ }
63
+
64
+ test('should insert 100 rows within acceptable time',
65
+ async () =>
66
+ {
67
+ const {
68
+ client,
69
+ dataSource,
70
+ } =
71
+ await createDataSource();
72
+
73
+ try
74
+ {
75
+ const repository =
76
+ dataSource.getRepository(
77
+ PerformanceUser,
78
+ );
79
+
80
+ const users =
81
+ Array.from(
82
+ {
83
+ length: 1000,
84
+ },
85
+ (_, index) => ({
86
+ name:
87
+ `User ${index + 1} `,
88
+ email:
89
+ `user${index + 1} @example.com`,
90
+ }),
91
+ );
92
+
93
+ const start =
94
+ performance.now();
95
+
96
+ await repository.insert(
97
+ users,
98
+ );
99
+
100
+ const elapsed =
101
+ performance.now() -
102
+ start;
103
+
104
+ const rows =
105
+ await client.getRows(
106
+ 'performance_users',
107
+ );
108
+
109
+ expect(rows)
110
+ .toHaveLength(1000);
111
+
112
+ expect(elapsed)
113
+ .toBeLessThan(5000);
114
+ }
115
+ finally
116
+ {
117
+ if (dataSource.isInitialized)
118
+ {
119
+ await dataSource.destroy();
120
+ }
121
+ }
122
+ },
123
+ );
124
+
125
+ test(
126
+ 'should read 100 rows within acceptable time',
127
+ async () =>
128
+ {
129
+ const rows =
130
+ Array.from(
131
+ {
132
+ length: 100,
133
+ },
134
+ (_, index) => ({
135
+ id: index + 1,
136
+ name:
137
+ `User ${index + 1} `,
138
+ email:
139
+ `user${index + 1} @example.com`,
140
+ }),
141
+ );
142
+
143
+ const {
144
+ dataSource,
145
+ } =
146
+ await createDataSource(rows);
147
+
148
+ try
149
+ {
150
+ const repository =
151
+ dataSource.getRepository(
152
+ PerformanceUser,
153
+ );
154
+
155
+ const start =
156
+ performance.now();
157
+
158
+ const users =
159
+ await repository.find();
160
+
161
+ const elapsed =
162
+ performance.now() -
163
+ start;
164
+
165
+ expect(users)
166
+ .toHaveLength(100);
167
+
168
+ expect(elapsed)
169
+ .toBeLessThan(300);
170
+ }
171
+ finally
172
+ {
173
+ if (dataSource.isInitialized)
174
+ {
175
+ await dataSource.destroy();
176
+ }
177
+ }
178
+ },
179
+ );
180
+
181
+ test('should insert 1000 rows within acceptable time',
182
+ async () =>
183
+ {
184
+ const {
185
+ client,
186
+ dataSource,
187
+ } =
188
+ await createDataSource();
189
+
190
+ try
191
+ {
192
+ const repository =
193
+ dataSource.getRepository(
194
+ PerformanceUser,
195
+ );
196
+
197
+ const users =
198
+ Array.from(
199
+ {
200
+ length: 1000,
201
+ },
202
+ (_, index) => ({
203
+ name:
204
+ `User ${index + 1} `,
205
+ email:
206
+ `user${index + 1} @example.com`,
207
+ }),
208
+ );
209
+
210
+ const start =
211
+ performance.now();
212
+
213
+ await repository.insert(
214
+ users,
215
+ );
216
+
217
+ const elapsed =
218
+ performance.now() -
219
+ start;
220
+
221
+ const rows =
222
+ await client.getRows(
223
+ 'performance_users',
224
+ );
225
+
226
+ expect(rows)
227
+ .toHaveLength(1000);
228
+
229
+ expect(elapsed)
230
+ .toBeLessThan(1000);
231
+ }
232
+ finally
233
+ {
234
+ if (dataSource.isInitialized)
235
+ {
236
+ await dataSource.destroy();
237
+ }
238
+ }
239
+ },
240
+ );
241
+
242
+ test(
243
+ 'should read 1000 rows within acceptable time',
244
+ async () =>
245
+ {
246
+ const rows =
247
+ Array.from(
248
+ {
249
+ length: 1000,
250
+ },
251
+ (_, index) => ({
252
+ id: index + 1,
253
+ name:
254
+ `User ${index + 1} `,
255
+ email:
256
+ `user${index + 1} @example.com`,
257
+ }),
258
+ );
259
+
260
+ const {
261
+ dataSource,
262
+ } =
263
+ await createDataSource(rows);
264
+
265
+ try
266
+ {
267
+ const repository =
268
+ dataSource.getRepository(
269
+ PerformanceUser,
270
+ );
271
+
272
+ const start =
273
+ performance.now();
274
+
275
+ const users =
276
+ await repository.find();
277
+
278
+ const elapsed =
279
+ performance.now() -
280
+ start;
281
+
282
+ expect(users)
283
+ .toHaveLength(1000);
284
+
285
+ expect(elapsed)
286
+ .toBeLessThan(1000);
287
+ }
288
+ finally
289
+ {
290
+ if (dataSource.isInitialized)
291
+ {
292
+ await dataSource.destroy();
293
+ }
294
+ }
295
+ },
296
+ );
297
+
298
+ test('should insert 10000 rows within acceptable time',
299
+ async () =>
300
+ {
301
+ const {
302
+ client,
303
+ dataSource,
304
+ } =
305
+ await createDataSource();
306
+
307
+ try
308
+ {
309
+ const repository =
310
+ dataSource.getRepository(
311
+ PerformanceUser,
312
+ );
313
+
314
+ const users =
315
+ Array.from(
316
+ {
317
+ length: 10000,
318
+ },
319
+ (_, index) => ({
320
+ name:
321
+ `User ${index + 1} `,
322
+ email:
323
+ `user${index + 1} @example.com`,
324
+ }),
325
+ );
326
+
327
+ const start =
328
+ performance.now();
329
+
330
+ await repository.insert(
331
+ users,
332
+ );
333
+
334
+ const elapsed =
335
+ performance.now() -
336
+ start;
337
+
338
+ const rows =
339
+ await client.getRows(
340
+ 'performance_users',
341
+ );
342
+
343
+ expect(rows)
344
+ .toHaveLength(10000);
345
+
346
+ expect(elapsed)
347
+ .toBeLessThan(3000);
348
+ }
349
+ finally
350
+ {
351
+ if (dataSource.isInitialized)
352
+ {
353
+ await dataSource.destroy();
354
+ }
355
+ }
356
+ },
357
+ );
358
+
359
+ test(
360
+ 'should read 10000 rows within acceptable time',
361
+ async () =>
362
+ {
363
+ const rows =
364
+ Array.from(
365
+ {
366
+ length: 10000,
367
+ },
368
+ (_, index) => ({
369
+ id: index + 1,
370
+ name:
371
+ `User ${index + 1} `,
372
+ email:
373
+ `user${index + 1} @example.com`,
374
+ }),
375
+ );
376
+
377
+ const {
378
+ dataSource,
379
+ } =
380
+ await createDataSource(rows);
381
+
382
+ try
383
+ {
384
+ const repository =
385
+ dataSource.getRepository(
386
+ PerformanceUser,
387
+ );
388
+
389
+ const start =
390
+ performance.now();
391
+
392
+ const users =
393
+ await repository.find();
394
+
395
+ const elapsed =
396
+ performance.now() -
397
+ start;
398
+
399
+ expect(users)
400
+ .toHaveLength(10000);
401
+
402
+ expect(elapsed)
403
+ .toBeLessThan(3000);
404
+ }
405
+ finally
406
+ {
407
+ if (dataSource.isInitialized)
408
+ {
409
+ await dataSource.destroy();
410
+ }
411
+ }
412
+ },
413
+ );
414
+
415
+ test('should insert 100000 rows within acceptable time',
416
+ async () =>
417
+ {
418
+ const {
419
+ client,
420
+ dataSource,
421
+ } =
422
+ await createDataSource();
423
+
424
+ try
425
+ {
426
+ const repository =
427
+ dataSource.getRepository(
428
+ PerformanceUser,
429
+ );
430
+
431
+ const users =
432
+ Array.from(
433
+ {
434
+ length: 100000,
435
+ },
436
+ (_, index) => ({
437
+ name:
438
+ `User ${index + 1} `,
439
+ email:
440
+ `user${index + 1} @example.com`,
441
+ }),
442
+ );
443
+
444
+ const start =
445
+ performance.now();
446
+
447
+ await repository.insert(
448
+ users,
449
+ );
450
+
451
+ const elapsed =
452
+ performance.now() -
453
+ start;
454
+
455
+ const rows =
456
+ await client.getRows(
457
+ 'performance_users',
458
+ );
459
+
460
+ expect(rows)
461
+ .toHaveLength(100000);
462
+
463
+ expect(elapsed)
464
+ .toBeLessThan(5000);
465
+ }
466
+ finally
467
+ {
468
+ if (dataSource.isInitialized)
469
+ {
470
+ await dataSource.destroy();
471
+ }
472
+ }
473
+ },
474
+ );
475
+
476
+ test(
477
+ 'should read 100000 rows within acceptable time',
478
+ async () =>
479
+ {
480
+ const rows =
481
+ Array.from(
482
+ {
483
+ length: 100000,
484
+ },
485
+ (_, index) => ({
486
+ id: index + 1,
487
+ name:
488
+ `User ${index + 1} `,
489
+ email:
490
+ `user${index + 1} @example.com`,
491
+ }),
492
+ );
493
+
494
+ const {
495
+ dataSource,
496
+ } =
497
+ await createDataSource(rows);
498
+
499
+ try
500
+ {
501
+ const repository =
502
+ dataSource.getRepository(
503
+ PerformanceUser,
504
+ );
505
+
506
+ const start =
507
+ performance.now();
508
+
509
+ const users =
510
+ await repository.find();
511
+
512
+ const elapsed =
513
+ performance.now() -
514
+ start;
515
+
516
+ expect(users)
517
+ .toHaveLength(100000);
518
+
519
+ expect(elapsed)
520
+ .toBeLessThan(5000);
521
+ }
522
+ finally
523
+ {
524
+ if (dataSource.isInitialized)
525
+ {
526
+ await dataSource.destroy();
527
+ }
528
+ }
529
+ },
530
+ );
531
+ },
532
+ );
@@ -0,0 +1,34 @@
1
+ import { createGoogleSheetsDataSource, GoogleSheetsConsume } from '../src/index';
2
+ import type {
3
+ GoogleSheetsDataSourceOptions,
4
+ GoogleSheetsClient,
5
+ GoogleSheetsRow,
6
+ } from '../src/index';
7
+
8
+ import { describe, expect, test } from 'bun:test';
9
+
10
+ describe('public API', () =>
11
+ {
12
+ test('exports public runtime API', () =>
13
+ {
14
+ expect(createGoogleSheetsDataSource).toBeFunction();
15
+ expect(GoogleSheetsConsume).toBeFunction();
16
+ });
17
+
18
+ test('exports public types', () =>
19
+ {
20
+ const client: GoogleSheetsClient =
21
+ {} as GoogleSheetsClient;
22
+
23
+ const options:
24
+ GoogleSheetsDataSourceOptions =
25
+ {} as GoogleSheetsDataSourceOptions;
26
+
27
+ const row: GoogleSheetsRow =
28
+ {} as GoogleSheetsRow;
29
+
30
+ expect(client).toBeDefined();
31
+ expect(options).toBeDefined();
32
+ expect(row).toBeDefined();
33
+ });
34
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+
4
+ "compilerOptions": {
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+
8
+ "noEmit": false,
9
+
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "sourceMap": true,
13
+
14
+ "outDir": "./dist",
15
+ "rootDir": "./src",
16
+
17
+ "allowImportingTsExtensions": false
18
+ },
19
+ "include": ["src/**/*.ts"],
20
+ "exclude": ["node_modules", "test"]
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+ "types": ["bun"],
11
+
12
+ // Bundler mode
13
+ "moduleResolution": "bundler",
14
+ "allowImportingTsExtensions": true,
15
+ "verbatimModuleSyntax": true,
16
+ "noEmit": true,
17
+
18
+ // Best practices
19
+ "strict": true,
20
+ "skipLibCheck": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "noUncheckedIndexedAccess": true,
23
+ "noImplicitOverride": true,
24
+
25
+ // Some stricter flags (disabled by default)
26
+ "noUnusedLocals": false,
27
+ "noUnusedParameters": false,
28
+ "noPropertyAccessFromIndexSignature": false,
29
+ "experimentalDecorators": true,
30
+ "emitDecoratorMetadata": true
31
+ },
32
+ "include": ["src/**/*.ts", "test/**/*.ts"],
33
+ "exclude": ["node_modules", "dist"]
34
+ }