@rainbow-o23/n3 1.0.47 → 1.0.49

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/README.md CHANGED
@@ -398,44 +398,6 @@ Autonomous transactions take precedence over the transaction name, meaning that
398
398
  specified by the transaction name will be ignored. If you need to use the transaction name, you must nest the pipeline steps within
399
399
  transactional step sets, and ensure that the datasource name and transaction name remain the same.
400
400
 
401
- ### By Entity (Deprecated, not recommended)
402
-
403
- #### Load Entity by ID
404
-
405
- ##### Constructor Parameters
406
-
407
- | Name | Type | Default Value | Comments |
408
- |------------|--------|---------------|----------------------|
409
- | entityName | string | | TypeOrm entity name. |
410
-
411
- ##### Request and Response
412
-
413
- ```typescript
414
- // request
415
- export type TypeOrmIdType = string | number | bigint;
416
- // response
417
- export type TypeOrmEntityToLoad = Undefinable<DeepPartial<ObjectLiteral>>;
418
- ```
419
-
420
- #### Save Entity
421
-
422
- ##### Constructor Parameters
423
-
424
- | Name | Type | Default Value | Comments |
425
- |------------------------|----------------------------------------|---------------|----------------------|
426
- | entityName | string | | TypeOrm entity name. |
427
- | fillIdBySnowflake | boolean | false | |
428
- | uniquenessCheckSnippet | ScriptFuncOrBody\<UniquenessCheckFunc> | | |
429
-
430
- ##### Request and Response
431
-
432
- ```typescript
433
- // request
434
- export type EntityToSave = DeepPartial<ObjectLiteral>;
435
- // response
436
- export type EntityToSave = DeepPartial<ObjectLiteral>;
437
- ```
438
-
439
401
  ### By SQL
440
402
 
441
403
  #### Environment Parameters
@@ -526,6 +488,34 @@ export interface TypeOrmLoadBasis extends TypeOrmBasis {
526
488
  Array<TypeOrmEntityToLoad>;
527
489
  ```
528
490
 
491
+ #### Load Many by SQL, Use Cursor
492
+
493
+ ##### Environment Parameters
494
+
495
+ | Name | Type | Default Value | Comments |
496
+ |-------------------------|--------|---------------|-------------|
497
+ | `typeorm.DB.fetch.size` | number | 20 | Fetch size. |
498
+
499
+ ##### Request and Response
500
+
501
+ ```typescript
502
+ // request
503
+ export interface TypeOrmLoadBasis extends TypeOrmBasis {
504
+ params?: Array<TypeOrmEntityValue> | TypeOrmEntityToSave;
505
+ }
506
+
507
+ // response
508
+ Array<any>;
509
+ ```
510
+
511
+ By specifying `fetchSize`, each batch of data retrieved will execute sub-steps. Before executing the sub-steps, the data to be passed to it
512
+ will be calculated using the `streamTo` function. If `streamTo` is not specified, the batch of data retrieved itself will be passed to the
513
+ sub-steps. If the sub-steps is not specified, all retrieved data will be merged and returned.
514
+
515
+ Therefore, the number of times the sub-step is executed is related to the quantity of data and the `fetchSize`. Meanwhile, each time the
516
+ sub-step is invoked, the context will include a `$$typeOrmCursorRound` variable indicating the current batch (starting from 0), and a
517
+ `$typeOrmCursorEnd` variable indicating whether it is the last batch.
518
+
529
519
  #### Save by SQL
530
520
 
531
521
  ##### Request and Response
package/index.cjs CHANGED
@@ -25,6 +25,7 @@ const ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL = 'O03-00017';
25
25
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS = 'O03-00018';
26
26
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL = 'O03-00019';
27
27
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION = 'O03-00020';
28
+ const ERR_TYPEORM_STREAM = 'O03-00021';
28
29
  n1.ErrorCodes.ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY;
29
30
  n1.ErrorCodes.ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY;
30
31
  n1.ErrorCodes.ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND = ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND;
@@ -45,6 +46,7 @@ n1.ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL = ERR_PIPELINE_SNIPPET_CANN
45
46
  n1.ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS = ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS;
46
47
  n1.ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL = ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL;
47
48
  n1.ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION = ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION;
49
+ n1.ErrorCodes.ERR_TYPEORM_STREAM = ERR_TYPEORM_STREAM;
48
50
 
49
51
  class AbstractTypeOrmDataSource {
50
52
  _name;
@@ -392,7 +394,7 @@ class Utils {
392
394
  suppressOutputPathCheck: false,
393
395
  skipLibCheck: true,
394
396
  skipDefaultLibCheck: true,
395
- moduleResolution: ts.ModuleResolutionKind.Node16
397
+ moduleResolution: ts.ModuleResolutionKind.NodeNext
396
398
  }
397
399
  });
398
400
  snippet = transpiled.outputText;
@@ -2216,6 +2218,122 @@ class TypeOrmLoadManyBySQLPipelineStep extends AbstractTypeOrmLoadBySQLPipelineS
2216
2218
  }
2217
2219
  }
2218
2220
 
2221
+ class TypeOrmLoadManyBySQLUseCursorPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2222
+ _fetchSize;
2223
+ _streamToSnippet;
2224
+ _streamToFunc;
2225
+ _stepBuilders;
2226
+ constructor(options) {
2227
+ super(options);
2228
+ const config = this.getConfig();
2229
+ this._fetchSize = options.fetchSize ?? config.getNumber(`typeorm.${this.getDataSourceName()}.fetch.size`, 20);
2230
+ this._streamToSnippet = options.streamTo;
2231
+ this._streamToFunc = Utils.createAsyncFunction(this.getStreamToSnippet(), {
2232
+ createDefault: () => (async ($factor) => $factor),
2233
+ getVariableNames: () => this.generateVariableNames(),
2234
+ error: (e) => {
2235
+ this.getLogger().error(`Failed on create function for snippet[${this.getStreamToSnippet()}].`);
2236
+ throw e;
2237
+ }
2238
+ });
2239
+ this._stepBuilders = options.steps;
2240
+ }
2241
+ getFetchSize() {
2242
+ return this._fetchSize;
2243
+ }
2244
+ getStreamToSnippet() {
2245
+ return this._streamToSnippet;
2246
+ }
2247
+ generateVariableNames() {
2248
+ return [this.getFetchDataVariableName(), this.getRequestVariableName(), ...this.getHelpersVariableNames()];
2249
+ }
2250
+ getStepBuilders() {
2251
+ return this._stepBuilders ?? [];
2252
+ }
2253
+ async doPerform(basis, request) {
2254
+ const { sql, params } = this.getSql(basis, basis?.params);
2255
+ return await this.autoTrans(async (runner) => {
2256
+ const results = [];
2257
+ const rows = [];
2258
+ let cursorRound = 0;
2259
+ const pipe = async ({ resolve, reject, end }) => {
2260
+ if (!end && rows.length < this.getFetchSize()) {
2261
+ return;
2262
+ }
2263
+ try {
2264
+ const contentForSub = await this._streamToFunc([...rows], request, this.getHelpers(), this.getHelpers());
2265
+ rows.length = 0;
2266
+ let resultContent;
2267
+ if (this.getStepBuilders().length === 0) {
2268
+ resultContent = contentForSub;
2269
+ }
2270
+ else {
2271
+ const sets = new PipelineStepSets({
2272
+ ...this.buildStepOptions(), name: this.getName(), steps: this.getStepBuilders()
2273
+ });
2274
+ const { content: _, $context, ...rest } = request;
2275
+ const contextForSub = { ...$context, $typeOrmCursorRound: cursorRound, $typeOrmCursorEnd: end };
2276
+ const requestForSub = { ...rest, $context: contextForSub, content: contentForSub };
2277
+ const result = await sets.perform(requestForSub);
2278
+ const { content } = result;
2279
+ resultContent = content;
2280
+ }
2281
+ cursorRound = cursorRound + 1;
2282
+ if (resultContent == null || resultContent == n1.PIPELINE_STEP_RETURN_NULL) {
2283
+ }
2284
+ else if (Array.isArray(resultContent)) {
2285
+ results.push(...resultContent);
2286
+ }
2287
+ else {
2288
+ results.push(resultContent);
2289
+ }
2290
+ }
2291
+ catch (e) {
2292
+ reject(e);
2293
+ }
2294
+ if (end) {
2295
+ resolve(results);
2296
+ }
2297
+ };
2298
+ const close = async (readable) => {
2299
+ try {
2300
+ readable?.destroy();
2301
+ }
2302
+ catch (e) {
2303
+ this.getLogger().error(e);
2304
+ }
2305
+ };
2306
+ const read = async ({ resolve, reject }) => {
2307
+ const readable = await runner.stream(sql, params, async () => {
2308
+ await close(readable);
2309
+ await pipe({ resolve, reject, end: true });
2310
+ }, async (e) => {
2311
+ await close(readable);
2312
+ reject(e);
2313
+ });
2314
+ readable.on('data', async (data) => {
2315
+ readable.pause();
2316
+ rows.push(data);
2317
+ await pipe({
2318
+ resolve, reject: async (e) => {
2319
+ await close(readable);
2320
+ reject(e);
2321
+ }, end: false
2322
+ });
2323
+ readable.resume();
2324
+ });
2325
+ };
2326
+ return new Promise((resolve, reject) => read({ resolve, reject }));
2327
+ }, request);
2328
+ }
2329
+ getFetchDataVariableName() {
2330
+ return '$factor';
2331
+ }
2332
+ getRequestVariableName() {
2333
+ return '$request';
2334
+ }
2335
+ }
2336
+
2219
2337
  class TypeOrmSaveBySQLPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2220
2338
  async doPerform(basis, request) {
2221
2339
  const { sql, params } = this.getSql(basis, basis?.values);
@@ -2355,6 +2473,7 @@ exports.ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND = ERR_TYPEORM_DATASOURCE_TYPE_NOT_
2355
2473
  exports.ERR_TYPEORM_ENTITY_NOT_FOUND = ERR_TYPEORM_ENTITY_NOT_FOUND;
2356
2474
  exports.ERR_TYPEORM_SQL_NOT_EMPTY = ERR_TYPEORM_SQL_NOT_EMPTY;
2357
2475
  exports.ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY = ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY;
2476
+ exports.ERR_TYPEORM_STREAM = ERR_TYPEORM_STREAM;
2358
2477
  exports.ERR_TYPEORM_TRANSACTION_NOT_FOUND = ERR_TYPEORM_TRANSACTION_NOT_FOUND;
2359
2478
  exports.EachPipelineStepSets = EachPipelineStepSets;
2360
2479
  exports.FetchPipelineStep = FetchPipelineStep;
@@ -2377,6 +2496,7 @@ exports.TypeOrmBySnippetPipelineStep = TypeOrmBySnippetPipelineStep;
2377
2496
  exports.TypeOrmDataSourceHelper = TypeOrmDataSourceHelper;
2378
2497
  exports.TypeOrmDataSourceManager = TypeOrmDataSourceManager;
2379
2498
  exports.TypeOrmLoadManyBySQLPipelineStep = TypeOrmLoadManyBySQLPipelineStep;
2499
+ exports.TypeOrmLoadManyBySQLUseCursorPipelineStep = TypeOrmLoadManyBySQLUseCursorPipelineStep;
2380
2500
  exports.TypeOrmLoadOneBySQLPipelineStep = TypeOrmLoadOneBySQLPipelineStep;
2381
2501
  exports.TypeOrmParsedSQLCache = TypeOrmParsedSQLCache;
2382
2502
  exports.TypeOrmSaveBySQLPipelineStep = TypeOrmSaveBySQLPipelineStep;
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ErrorCodes, UncatchableError, AbstractPipelineStep, CatchableError, ExposedUncatchableError, ERR_UNKNOWN, PipelineRepository, StepHelpersUtils } from '@rainbow-o23/n1';
1
+ import { ErrorCodes, UncatchableError, AbstractPipelineStep, CatchableError, ExposedUncatchableError, ERR_UNKNOWN, PipelineRepository, StepHelpersUtils, PIPELINE_STEP_RETURN_NULL } from '@rainbow-o23/n1';
2
2
  import { DataSource } from 'typeorm';
3
3
  import ts, { ScriptTarget, JsxEmit, ModuleKind, ModuleResolutionKind } from 'typescript';
4
4
  import fetch from 'node-fetch';
@@ -23,6 +23,7 @@ const ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL = 'O03-00017';
23
23
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS = 'O03-00018';
24
24
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL = 'O03-00019';
25
25
  const ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION = 'O03-00020';
26
+ const ERR_TYPEORM_STREAM = 'O03-00021';
26
27
  ErrorCodes.ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY;
27
28
  ErrorCodes.ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY;
28
29
  ErrorCodes.ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND = ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND;
@@ -43,6 +44,7 @@ ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL = ERR_PIPELINE_SNIPPET_CANNOT_
43
44
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS = ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS;
44
45
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL = ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL;
45
46
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION = ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION;
47
+ ErrorCodes.ERR_TYPEORM_STREAM = ERR_TYPEORM_STREAM;
46
48
 
47
49
  class AbstractTypeOrmDataSource {
48
50
  _name;
@@ -390,7 +392,7 @@ class Utils {
390
392
  suppressOutputPathCheck: false,
391
393
  skipLibCheck: true,
392
394
  skipDefaultLibCheck: true,
393
- moduleResolution: ModuleResolutionKind.Node16
395
+ moduleResolution: ModuleResolutionKind.NodeNext
394
396
  }
395
397
  });
396
398
  snippet = transpiled.outputText;
@@ -2214,6 +2216,122 @@ class TypeOrmLoadManyBySQLPipelineStep extends AbstractTypeOrmLoadBySQLPipelineS
2214
2216
  }
2215
2217
  }
2216
2218
 
2219
+ class TypeOrmLoadManyBySQLUseCursorPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2220
+ _fetchSize;
2221
+ _streamToSnippet;
2222
+ _streamToFunc;
2223
+ _stepBuilders;
2224
+ constructor(options) {
2225
+ super(options);
2226
+ const config = this.getConfig();
2227
+ this._fetchSize = options.fetchSize ?? config.getNumber(`typeorm.${this.getDataSourceName()}.fetch.size`, 20);
2228
+ this._streamToSnippet = options.streamTo;
2229
+ this._streamToFunc = Utils.createAsyncFunction(this.getStreamToSnippet(), {
2230
+ createDefault: () => (async ($factor) => $factor),
2231
+ getVariableNames: () => this.generateVariableNames(),
2232
+ error: (e) => {
2233
+ this.getLogger().error(`Failed on create function for snippet[${this.getStreamToSnippet()}].`);
2234
+ throw e;
2235
+ }
2236
+ });
2237
+ this._stepBuilders = options.steps;
2238
+ }
2239
+ getFetchSize() {
2240
+ return this._fetchSize;
2241
+ }
2242
+ getStreamToSnippet() {
2243
+ return this._streamToSnippet;
2244
+ }
2245
+ generateVariableNames() {
2246
+ return [this.getFetchDataVariableName(), this.getRequestVariableName(), ...this.getHelpersVariableNames()];
2247
+ }
2248
+ getStepBuilders() {
2249
+ return this._stepBuilders ?? [];
2250
+ }
2251
+ async doPerform(basis, request) {
2252
+ const { sql, params } = this.getSql(basis, basis?.params);
2253
+ return await this.autoTrans(async (runner) => {
2254
+ const results = [];
2255
+ const rows = [];
2256
+ let cursorRound = 0;
2257
+ const pipe = async ({ resolve, reject, end }) => {
2258
+ if (!end && rows.length < this.getFetchSize()) {
2259
+ return;
2260
+ }
2261
+ try {
2262
+ const contentForSub = await this._streamToFunc([...rows], request, this.getHelpers(), this.getHelpers());
2263
+ rows.length = 0;
2264
+ let resultContent;
2265
+ if (this.getStepBuilders().length === 0) {
2266
+ resultContent = contentForSub;
2267
+ }
2268
+ else {
2269
+ const sets = new PipelineStepSets({
2270
+ ...this.buildStepOptions(), name: this.getName(), steps: this.getStepBuilders()
2271
+ });
2272
+ const { content: _, $context, ...rest } = request;
2273
+ const contextForSub = { ...$context, $typeOrmCursorRound: cursorRound, $typeOrmCursorEnd: end };
2274
+ const requestForSub = { ...rest, $context: contextForSub, content: contentForSub };
2275
+ const result = await sets.perform(requestForSub);
2276
+ const { content } = result;
2277
+ resultContent = content;
2278
+ }
2279
+ cursorRound = cursorRound + 1;
2280
+ if (resultContent == null || resultContent == PIPELINE_STEP_RETURN_NULL) {
2281
+ }
2282
+ else if (Array.isArray(resultContent)) {
2283
+ results.push(...resultContent);
2284
+ }
2285
+ else {
2286
+ results.push(resultContent);
2287
+ }
2288
+ }
2289
+ catch (e) {
2290
+ reject(e);
2291
+ }
2292
+ if (end) {
2293
+ resolve(results);
2294
+ }
2295
+ };
2296
+ const close = async (readable) => {
2297
+ try {
2298
+ readable?.destroy();
2299
+ }
2300
+ catch (e) {
2301
+ this.getLogger().error(e);
2302
+ }
2303
+ };
2304
+ const read = async ({ resolve, reject }) => {
2305
+ const readable = await runner.stream(sql, params, async () => {
2306
+ await close(readable);
2307
+ await pipe({ resolve, reject, end: true });
2308
+ }, async (e) => {
2309
+ await close(readable);
2310
+ reject(e);
2311
+ });
2312
+ readable.on('data', async (data) => {
2313
+ readable.pause();
2314
+ rows.push(data);
2315
+ await pipe({
2316
+ resolve, reject: async (e) => {
2317
+ await close(readable);
2318
+ reject(e);
2319
+ }, end: false
2320
+ });
2321
+ readable.resume();
2322
+ });
2323
+ };
2324
+ return new Promise((resolve, reject) => read({ resolve, reject }));
2325
+ }, request);
2326
+ }
2327
+ getFetchDataVariableName() {
2328
+ return '$factor';
2329
+ }
2330
+ getRequestVariableName() {
2331
+ return '$request';
2332
+ }
2333
+ }
2334
+
2217
2335
  class TypeOrmSaveBySQLPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2218
2336
  async doPerform(basis, request) {
2219
2337
  const { sql, params } = this.getSql(basis, basis?.values);
@@ -2324,4 +2442,4 @@ class TypeOrmTransactionalPipelineStepSets extends PipelineStepSets {
2324
2442
  }
2325
2443
  }
2326
2444
 
2327
- export { AbstractFragmentaryPipelineStep, AbstractTypeOrmBySQLPipelineStep, AbstractTypeOrmDataSource, AbstractTypeOrmLoadBySQLPipelineStep, AbstractTypeOrmPipelineStep, AsyncPipelineStepSets, BetterSqlite3TypeOrmDatasource, ConditionalPipelineStepSets, DEFAULT_TRANSACTION_NAME, DeletePropertyPipelineStep, ERR_EACH_FRAGMENT_NOT_ANY_ARRAY, ERR_FETCH_ERROR, ERR_PIPELINE_REF_NOT_EMPTY, ERR_PIPELINE_REF_NOT_FOUND, ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL, ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION, ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL, ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS, ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY, ERR_PIPELINE_STEP_METHOD_NOT_SUPPORTED, ERR_PIPELINE_STEP_REF_NOT_EMPTY, ERR_PIPELINE_STEP_REF_NOT_FOUND, ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY, ERR_TYPEORM_DATASOURCE_CREATOR_NOT_FOUND, ERR_TYPEORM_DATASOURCE_NOT_FOUND, ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND, ERR_TYPEORM_ENTITY_NOT_FOUND, ERR_TYPEORM_SQL_NOT_EMPTY, ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY, ERR_TYPEORM_TRANSACTION_NOT_FOUND, EachPipelineStepSets, FetchPipelineStep, GetPropertyPipelineStep, HttpAbortErrorCode, HttpUnknownErrorCode, MssqlTypeOrmDatasource, MysqlTypeOrmDatasource, OracleTypeOrmDatasource, ParallelPipelineStepSets, ParsedSqlSegmentType, PgsqlTypeOrmDatasource, PipelineStepSets, RefPipelinePipelineStep, RefStepPipelineStep, RoutesPipelineStepSets, SnippetPipelineStep, SnowflakePipelineStep, SupportedDataSourceTypes, TypeOrmBulkSaveBySQLPipelineStep, TypeOrmBySnippetPipelineStep, TypeOrmDataSourceHelper, TypeOrmDataSourceManager, TypeOrmLoadManyBySQLPipelineStep, TypeOrmLoadOneBySQLPipelineStep, TypeOrmParsedSQLCache, TypeOrmSaveBySQLPipelineStep, TypeOrmTransactionalPipelineStepSets, Utils };
2445
+ export { AbstractFragmentaryPipelineStep, AbstractTypeOrmBySQLPipelineStep, AbstractTypeOrmDataSource, AbstractTypeOrmLoadBySQLPipelineStep, AbstractTypeOrmPipelineStep, AsyncPipelineStepSets, BetterSqlite3TypeOrmDatasource, ConditionalPipelineStepSets, DEFAULT_TRANSACTION_NAME, DeletePropertyPipelineStep, ERR_EACH_FRAGMENT_NOT_ANY_ARRAY, ERR_FETCH_ERROR, ERR_PIPELINE_REF_NOT_EMPTY, ERR_PIPELINE_REF_NOT_FOUND, ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL, ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION, ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL, ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS, ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY, ERR_PIPELINE_STEP_METHOD_NOT_SUPPORTED, ERR_PIPELINE_STEP_REF_NOT_EMPTY, ERR_PIPELINE_STEP_REF_NOT_FOUND, ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY, ERR_TYPEORM_DATASOURCE_CREATOR_NOT_FOUND, ERR_TYPEORM_DATASOURCE_NOT_FOUND, ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND, ERR_TYPEORM_ENTITY_NOT_FOUND, ERR_TYPEORM_SQL_NOT_EMPTY, ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY, ERR_TYPEORM_STREAM, ERR_TYPEORM_TRANSACTION_NOT_FOUND, EachPipelineStepSets, FetchPipelineStep, GetPropertyPipelineStep, HttpAbortErrorCode, HttpUnknownErrorCode, MssqlTypeOrmDatasource, MysqlTypeOrmDatasource, OracleTypeOrmDatasource, ParallelPipelineStepSets, ParsedSqlSegmentType, PgsqlTypeOrmDatasource, PipelineStepSets, RefPipelinePipelineStep, RefStepPipelineStep, RoutesPipelineStepSets, SnippetPipelineStep, SnowflakePipelineStep, SupportedDataSourceTypes, TypeOrmBulkSaveBySQLPipelineStep, TypeOrmBySnippetPipelineStep, TypeOrmDataSourceHelper, TypeOrmDataSourceManager, TypeOrmLoadManyBySQLPipelineStep, TypeOrmLoadManyBySQLUseCursorPipelineStep, TypeOrmLoadOneBySQLPipelineStep, TypeOrmParsedSQLCache, TypeOrmSaveBySQLPipelineStep, TypeOrmTransactionalPipelineStepSets, Utils };
@@ -19,3 +19,4 @@ export declare const ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL: O23ReservedErrorCod
19
19
  export declare const ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS: O23ReservedErrorCode;
20
20
  export declare const ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL: O23ReservedErrorCode;
21
21
  export declare const ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION: O23ReservedErrorCode;
22
+ export declare const ERR_TYPEORM_STREAM: O23ReservedErrorCode;
@@ -5,6 +5,7 @@ export * from './abstract-typeorm-by-sql-step';
5
5
  export * from './abstract-typeorm-load-by-sql-step';
6
6
  export * from './typeorm-load-one-by-sql-step';
7
7
  export * from './typeorm-load-many-by-sql-step';
8
+ export * from './typeorm-load-many-by-sql-use-cursor-step';
8
9
  export * from './typeorm-save-by-sql-step';
9
10
  export * from './typeorm-bulk-save-by-sql-step';
10
11
  export * from './typeorm-transactional-step-sets';
@@ -0,0 +1,25 @@
1
+ import { PipelineStepBuilder, PipelineStepData, PipelineStepHelpers, PipelineStepPayload, Undefinable } from '@rainbow-o23/n1';
2
+ import { ScriptFuncOrBody } from '../step';
3
+ import { AbstractTypeOrmBySQLPipelineStep, TypeOrmBySQLPipelineStepOptions } from './abstract-typeorm-by-sql-step';
4
+ import { TypeOrmLoadBasis } from './abstract-typeorm-load-by-sql-step';
5
+ export type StreamToSubSteps = any;
6
+ export type StreamToFunc<In> = ($factor: Array<any>, $request: PipelineStepData<In>, $helpers: PipelineStepHelpers, $: PipelineStepHelpers) => Promise<StreamToSubSteps>;
7
+ export interface TypeOrmLoadManyBySQLUseCursorPipelineStepOptions<In = PipelineStepPayload, Out = PipelineStepPayload, InFragment = TypeOrmLoadBasis, OutFragment = Out> extends TypeOrmBySQLPipelineStepOptions<In, Out, InFragment, OutFragment> {
8
+ fetchSize?: number;
9
+ streamTo?: ScriptFuncOrBody<StreamToFunc<In>>;
10
+ steps?: Array<PipelineStepBuilder>;
11
+ }
12
+ export declare class TypeOrmLoadManyBySQLUseCursorPipelineStep<In = PipelineStepPayload, Out = PipelineStepPayload, InFragment = Undefinable<TypeOrmLoadBasis>, OutFragment = Out> extends AbstractTypeOrmBySQLPipelineStep<In, Out, Undefinable<TypeOrmLoadBasis>, OutFragment> {
13
+ private readonly _fetchSize;
14
+ private readonly _streamToSnippet;
15
+ private readonly _streamToFunc;
16
+ private readonly _stepBuilders;
17
+ constructor(options: TypeOrmLoadManyBySQLUseCursorPipelineStepOptions<In, Out, InFragment, OutFragment>);
18
+ protected getFetchSize(): number;
19
+ getStreamToSnippet(): ScriptFuncOrBody<StreamToFunc<In>>;
20
+ protected generateVariableNames(): Array<string>;
21
+ protected getStepBuilders(): Array<PipelineStepBuilder>;
22
+ protected doPerform(basis: Undefinable<TypeOrmLoadBasis>, request: PipelineStepData<In>): Promise<Undefinable<OutFragment>>;
23
+ protected getFetchDataVariableName(): string;
24
+ protected getRequestVariableName(): string;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-o23/n3",
3
- "version": "1.0.47",
3
+ "version": "1.0.49",
4
4
  "description": "o23 pipelines",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
@@ -21,7 +21,7 @@
21
21
  "url": "https://github.com/InsureMO/rainbow-o23/issues"
22
22
  },
23
23
  "dependencies": {
24
- "@rainbow-o23/n1": "1.0.47",
24
+ "@rainbow-o23/n1": "1.0.49",
25
25
  "node-fetch": "2.6.7",
26
26
  "typeorm": "^0.3.20",
27
27
  "typescript": "5.5.4"
@@ -21,6 +21,7 @@ export const ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL: O23ReservedErrorCode = 'O03
21
21
  export const ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS: O23ReservedErrorCode = 'O03-00018';
22
22
  export const ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL: O23ReservedErrorCode = 'O03-00019';
23
23
  export const ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION: O23ReservedErrorCode = 'O03-00020';
24
+ export const ERR_TYPEORM_STREAM: O23ReservedErrorCode = 'O03-00021';
24
25
 
25
26
  ErrorCodes.ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY;
26
27
  ErrorCodes.ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY = ERR_PIPELINE_STEP_CONDITIONAL_SNIPPET_NOT_EMPTY;
@@ -43,3 +44,4 @@ ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_GLOBAL = ERR_PIPELINE_SNIPPET_CANNOT_
43
44
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS = ERR_PIPELINE_SNIPPET_CANNOT_USE_PROCESS;
44
45
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL = ERR_PIPELINE_SNIPPET_CANNOT_USE_EVAL;
45
46
  ErrorCodes.ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION = ERR_PIPELINE_SNIPPET_CANNOT_USE_FUNCTION;
47
+ ErrorCodes.ERR_TYPEORM_STREAM = ERR_TYPEORM_STREAM;
@@ -70,7 +70,7 @@ export class Utils {
70
70
  suppressOutputPathCheck: false,
71
71
  skipLibCheck: true,
72
72
  skipDefaultLibCheck: true,
73
- moduleResolution: ModuleResolutionKind.Node16 // default use node 16
73
+ moduleResolution: ModuleResolutionKind.NodeNext // default use node next
74
74
  }
75
75
  });
76
76
  snippet = transpiled.outputText;
@@ -8,6 +8,7 @@ export * from './abstract-typeorm-by-sql-step';
8
8
  export * from './abstract-typeorm-load-by-sql-step';
9
9
  export * from './typeorm-load-one-by-sql-step';
10
10
  export * from './typeorm-load-many-by-sql-step';
11
+ export * from './typeorm-load-many-by-sql-use-cursor-step';
11
12
 
12
13
  export * from './typeorm-save-by-sql-step';
13
14
  export * from './typeorm-bulk-save-by-sql-step';
@@ -0,0 +1,162 @@
1
+ import {
2
+ PIPELINE_STEP_RETURN_NULL,
3
+ PipelineStepBuilder,
4
+ PipelineStepData,
5
+ PipelineStepHelpers,
6
+ PipelineStepPayload,
7
+ Undefinable
8
+ } from '@rainbow-o23/n1';
9
+ import {ReadStream} from 'fs';
10
+ import {PipelineStepSets, ScriptFuncOrBody, Utils} from '../step';
11
+ import {AbstractTypeOrmBySQLPipelineStep, TypeOrmBySQLPipelineStepOptions} from './abstract-typeorm-by-sql-step';
12
+ import {TypeOrmLoadBasis} from './abstract-typeorm-load-by-sql-step';
13
+
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ export type StreamToSubSteps = any;
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export type StreamToFunc<In> = ($factor: Array<any>, $request: PipelineStepData<In>, $helpers: PipelineStepHelpers, $: PipelineStepHelpers) => Promise<StreamToSubSteps>;
18
+
19
+ export interface TypeOrmLoadManyBySQLUseCursorPipelineStepOptions<In = PipelineStepPayload, Out = PipelineStepPayload, InFragment = TypeOrmLoadBasis, OutFragment = Out>
20
+ extends TypeOrmBySQLPipelineStepOptions<In, Out, InFragment, OutFragment> {
21
+ fetchSize?: number;
22
+ streamTo?: ScriptFuncOrBody<StreamToFunc<In>>;
23
+ steps?: Array<PipelineStepBuilder>;
24
+ }
25
+
26
+ export class TypeOrmLoadManyBySQLUseCursorPipelineStep<In = PipelineStepPayload, Out = PipelineStepPayload, InFragment = Undefinable<TypeOrmLoadBasis>, OutFragment = Out>
27
+ extends AbstractTypeOrmBySQLPipelineStep<In, Out, Undefinable<TypeOrmLoadBasis>, OutFragment> {
28
+ private readonly _fetchSize: number;
29
+ private readonly _streamToSnippet: ScriptFuncOrBody<StreamToFunc<In>>;
30
+ private readonly _streamToFunc: StreamToFunc<In>;
31
+ private readonly _stepBuilders: Array<PipelineStepBuilder>;
32
+
33
+ public constructor(options: TypeOrmLoadManyBySQLUseCursorPipelineStepOptions<In, Out, InFragment, OutFragment>) {
34
+ super(options);
35
+ const config = this.getConfig();
36
+ this._fetchSize = options.fetchSize ?? config.getNumber(`typeorm.${this.getDataSourceName()}.fetch.size`, 20);
37
+ this._streamToSnippet = options.streamTo;
38
+ this._streamToFunc = Utils.createAsyncFunction(this.getStreamToSnippet(), {
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ createDefault: () => (async ($factor: Array<any>) => $factor),
41
+ getVariableNames: () => this.generateVariableNames(),
42
+ error: (e: Error) => {
43
+ this.getLogger().error(`Failed on create function for snippet[${this.getStreamToSnippet()}].`);
44
+ throw e;
45
+ }
46
+ });
47
+ this._stepBuilders = options.steps;
48
+ }
49
+
50
+ protected getFetchSize(): number {
51
+ return this._fetchSize;
52
+ }
53
+
54
+ public getStreamToSnippet(): ScriptFuncOrBody<StreamToFunc<In>> {
55
+ return this._streamToSnippet;
56
+ }
57
+
58
+ protected generateVariableNames(): Array<string> {
59
+ return [this.getFetchDataVariableName(), this.getRequestVariableName(), ...this.getHelpersVariableNames()];
60
+ }
61
+
62
+ protected getStepBuilders(): Array<PipelineStepBuilder> {
63
+ return this._stepBuilders ?? [];
64
+ }
65
+
66
+ protected async doPerform(basis: Undefinable<TypeOrmLoadBasis>, request: PipelineStepData<In>): Promise<Undefinable<OutFragment>> {
67
+ const {sql, params} = this.getSql(basis, basis?.params);
68
+ return await this.autoTrans<OutFragment>(async (runner) => {
69
+ const results = [];
70
+ const rows = [];
71
+ let cursorRound = 0;
72
+ const pipe = async ({resolve, reject, end}) => {
73
+ if (!end && rows.length < this.getFetchSize()) {
74
+ // not end, and size not meet the fresh required
75
+ // do nothing, wait for next
76
+ return;
77
+ }
78
+ try {
79
+ // get data from cache
80
+ const contentForSub = await this._streamToFunc([...rows], request, this.getHelpers(), this.getHelpers());
81
+ // clear cache
82
+ rows.length = 0;
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ let resultContent: any;
85
+ if (this.getStepBuilders().length === 0) {
86
+ // no sub step, use content as result
87
+ resultContent = contentForSub;
88
+ } else {
89
+ // create a step sets to run
90
+ const sets = new PipelineStepSets({
91
+ ...this.buildStepOptions(), name: this.getName(), steps: this.getStepBuilders()
92
+ });
93
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
94
+ const {content: _, $context, ...rest} = request;
95
+ // pass a cursor end indicator to sub steps
96
+ const contextForSub = {...$context, $typeOrmCursorRound: cursorRound, $typeOrmCursorEnd: end};
97
+ const requestForSub = {...rest, $context: contextForSub, content: contentForSub};
98
+ const result = await sets.perform(requestForSub);
99
+ const {content} = result;
100
+ resultContent = content;
101
+ }
102
+ cursorRound = cursorRound + 1;
103
+ if (resultContent == null || resultContent == PIPELINE_STEP_RETURN_NULL) {
104
+ // ignore
105
+ } else if (Array.isArray(resultContent)) {
106
+ results.push(...resultContent);
107
+ } else {
108
+ results.push(resultContent);
109
+ }
110
+ } catch (e) {
111
+ reject(e);
112
+ }
113
+ if (end) {
114
+ resolve(results);
115
+ }
116
+ };
117
+ const close = async (readable: ReadStream) => {
118
+ // never throw exception from this function
119
+ try {
120
+ readable?.destroy();
121
+ } catch (e) {
122
+ // ignore this error
123
+ this.getLogger().error(e);
124
+ }
125
+ };
126
+ const read = async ({resolve, reject}) => {
127
+ const readable = await runner.stream(sql, params, async () => {
128
+ // on end
129
+ await close(readable);
130
+ await pipe({resolve, reject, end: true});
131
+ }, async (e: Error) => {
132
+ // on error
133
+ await close(readable);
134
+ reject(e);
135
+ });
136
+ readable.on('data', async (data) => {
137
+ readable.pause();
138
+ rows.push(data);
139
+ await pipe({
140
+ resolve, reject: async (e: Error) => {
141
+ await close(readable);
142
+ reject(e);
143
+ }, end: false
144
+ });
145
+ readable.resume();
146
+ });
147
+ };
148
+ return new Promise<OutFragment>((resolve, reject) => read({resolve, reject}));
149
+ }, request);
150
+ }
151
+
152
+ /**
153
+ * override this method when want to use another variable name rather than "$factor"
154
+ */
155
+ protected getFetchDataVariableName(): string {
156
+ return '$factor';
157
+ }
158
+
159
+ protected getRequestVariableName(): string {
160
+ return '$request';
161
+ }
162
+ }
@@ -0,0 +1,55 @@
1
+ import {createConfig, createLogger} from '@rainbow-o23/n1';
2
+ import {TypeOrmDataSourceHelper, TypeOrmLoadManyBySQLUseCursorPipelineStep} from '../../src';
3
+
4
+ const logger = createLogger();
5
+ const config = createConfig(logger);
6
+
7
+ describe('TypeORM Cursor Suite', () => {
8
+ beforeAll(async () => {
9
+ process.env.CFG_TYPEORM_TEST_HOST = 'localhost';
10
+ process.env.CFG_TYPEORM_TEST_USERNAME = 'o23';
11
+ process.env.CFG_TYPEORM_TEST_PASSWORD = 'o23';
12
+ const type = 'pg' + 'sql';
13
+ if (type === 'mysql') {
14
+ process.env.CFG_TYPEORM_TEST_TYPE = 'mysql';
15
+ process.env.CFG_TYPEORM_TEST_PORT = '3306';
16
+ process.env.CFG_TYPEORM_TEST_DATABASE = 'o23';
17
+ } else if (type === 'pgsql') {
18
+ process.env.CFG_TYPEORM_TEST_TYPE = 'pgsql';
19
+ process.env.CFG_TYPEORM_TEST_PORT = '5432';
20
+ process.env.CFG_TYPEORM_TEST_DATABASE = 'postgres';
21
+ process.env.CFG_TYPEORM_TEST_SCHEMA = 'o23';
22
+ } else if (type === 'mssql') {
23
+ process.env.CFG_TYPEORM_TEST_TYPE = 'mssql';
24
+ process.env.CFG_TYPEORM_TEST_PORT = '1433';
25
+ process.env.CFG_TYPEORM_TEST_PASSWORD = 'o23O23o23!';
26
+ process.env.CFG_TYPEORM_TEST_DATABASE = 'o23';
27
+ process.env.CFG_TYPEORM_TEST_SCHEMA = 'dbo';
28
+ process.env.CFG_TYPEORM_TEST_TRUST_SERVER_CERTIFICATE = 'true';
29
+ } else {
30
+ process.env.CFG_TYPEORM_TEST_TYPE = 'oracle';
31
+ process.env.CFG_TYPEORM_TEST_HOST = '127.0.0.1';
32
+ process.env.CFG_TYPEORM_TEST_PORT = '1521';
33
+ process.env.CFG_TYPEORM_TEST_SERVICE_NAME = 'orcl';
34
+ }
35
+ // process.env.CFG_TYPEORM_TEST_LOGGING = 'true';
36
+ await new TypeOrmDataSourceHelper(config).create({});
37
+ // const repo = (await TypeOrmDataSourceManager.findDataSource('TEST', config)).getDataSource().getRepository(TestTable);
38
+ });
39
+
40
+ test('TypeORM load many using cursor #1', async () => {
41
+ // noinspection SqlResolve
42
+ const step = new TypeOrmLoadManyBySQLUseCursorPipelineStep<any, any>({
43
+ config, logger, dataSourceName: 'TEST', sql: 'SELECT * FROM T_O23_DB_CHANGE_LOG',
44
+ autonomous: true
45
+ });
46
+ const request = {content: (void 0)};
47
+ const response = await step.perform(request);
48
+ expect(response.content).not.toBeNull();
49
+ console.log(response.content);
50
+ });
51
+
52
+ afterAll((done) => {
53
+ done();
54
+ });
55
+ });
@@ -70,10 +70,10 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
70
70
  logger,
71
71
  dataSourceName: 'TEST',
72
72
  sql: 'SELECT ID id, CONTENT content FROM T_TEST_TABLE WHERE ID = ?',
73
- fromRequest: ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
73
+ fromRequest: async ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
74
74
  return {params: [$factor.idToLoad]} as TypeOrmBasis;
75
75
  },
76
- toResponse: ($result: TestTable, _$request: PipelineStepData) => {
76
+ toResponse: async ($result: TestTable, _$request: PipelineStepData) => {
77
77
  expect($result.id).toBe(1);
78
78
  expect($result.content).toBe('hello world!');
79
79
  return {loadedById: $result};
@@ -87,10 +87,10 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
87
87
  logger,
88
88
  dataSourceName: 'TEST',
89
89
  sql: 'INSERT INTO T_TEST_TABLE(ID, CONTENT) VALUES (?, ?)',
90
- fromRequest: ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
90
+ fromRequest: async ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
91
91
  return {values: [$factor.item3.id, $factor.item3.content]};
92
92
  },
93
- toResponse: ($result: TypeOrmIdOfInserted, _$request: PipelineStepData) => {
93
+ toResponse: async ($result: TypeOrmIdOfInserted, _$request: PipelineStepData) => {
94
94
  expect($result).toBe(3);
95
95
  return {insertedId: $result};
96
96
  },
@@ -104,10 +104,10 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
104
104
  dataSourceName: 'TEST',
105
105
  autonomous: true,
106
106
  sql: 'SELECT ID id, CONTENT content FROM T_TEST_TABLE WHERE ID = ?',
107
- fromRequest: ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
107
+ fromRequest: async ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
108
108
  return {params: [$factor.item3.id]};
109
109
  },
110
- toResponse: ($result: Undefinable<TestTable>, $request: PipelineStepData) => {
110
+ toResponse: async ($result: Undefinable<TestTable>, $request: PipelineStepData) => {
111
111
  expect($result).toBeUndefined();
112
112
  return $request.content;
113
113
  }
@@ -116,10 +116,10 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
116
116
  {
117
117
  create: async ({config, logger}) => new TypeOrmSaveBySQLPipelineStep({
118
118
  config, logger, dataSourceName: 'TEST', sql: 'UPDATE T_TEST_TABLE SET CONTENT = ? WHERE ID = ?',
119
- fromRequest: ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
119
+ fromRequest: async ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
120
120
  return {values: [$factor.item3ChangeTo.content, $factor.item3ChangeTo.id]};
121
121
  },
122
- toResponse: ($result: TypeOrmCountOfAffected, _$request: PipelineStepData) => {
122
+ toResponse: async ($result: TypeOrmCountOfAffected, _$request: PipelineStepData) => {
123
123
  // DON'T KNOW WHY THIS IS 3, SEEMS SHOULD BE 1 ACCORDING TO BETTER-SQLITE3 DOCUMENT
124
124
  // BUT CURRENTLY IT RETURNS COUNT OF THIS TABLE, NOT IMPACTED ROW COUNT
125
125
  expect($result).toBe(3);
@@ -134,14 +134,14 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
134
134
  logger,
135
135
  dataSourceName: 'TEST',
136
136
  sql: 'INSERT INTO T_TEST_TABLE(ID, CONTENT) VALUES (?, ?)',
137
- fromRequest: ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
137
+ fromRequest: async ($factor: TransactionalRequest, _$request: PipelineStepData<TransactionalRequest>) => {
138
138
  return {
139
139
  items: [
140
140
  [$factor.item4.id, $factor.item4.content], [$factor.item5.id, $factor.item5.content]
141
141
  ]
142
142
  };
143
143
  },
144
- toResponse: ($result: TypeOrmIdsOfInserted, _$request: PipelineStepData) => {
144
+ toResponse: async ($result: TypeOrmIdsOfInserted, _$request: PipelineStepData) => {
145
145
  return {insertedIds: $result};
146
146
  },
147
147
  mergeRequest: true
@@ -150,7 +150,7 @@ class TransactionalTestStepSets extends TypeOrmTransactionalPipelineStepSets {
150
150
  {
151
151
  create: async ({config, logger}) => new TypeOrmLoadManyBySQLPipelineStep({
152
152
  config, logger, dataSourceName: 'TEST', sql: 'SELECT ID id, CONTENT content FROM T_TEST_TABLE',
153
- toResponse: ($result: Array<TestTable>, _$request: PipelineStepData) => {
153
+ toResponse: async ($result: Array<TestTable>, _$request: PipelineStepData) => {
154
154
  return {all: $result};
155
155
  },
156
156
  mergeRequest: true
@@ -1,50 +0,0 @@
1
- import {createConfig, createLogger} from '@rainbow-o23/n1';
2
- import {Column, Entity, PrimaryColumn} from 'typeorm';
3
- import {TypeOrmDataSourceHelper, TypeOrmDataSourceManager, TypeOrmLoadEntityByIdPipelineStep} from '../../src';
4
-
5
- const logger = createLogger();
6
- const config = createConfig(logger);
7
-
8
- // decorators are leading syntax errors in ide, since the test folder is not included in tsconfig.json
9
- // but the tricky thing is, once test folder included into tsconfig.json, d.ts files will be created in src folder
10
- // which cause currently use ts-ignore to avoid this syntax errors
11
- // @ts-ignore
12
- @Entity({name: 'T_TEST_TABLE'})
13
- export class TestTable {
14
- // @ts-ignore
15
- @PrimaryColumn('bigint', {name: 'ID'})
16
- id: number;
17
- // @ts-ignore
18
- @Column('varchar', {name: 'CONTENT'})
19
- content: string;
20
- }
21
-
22
- describe('TypeORM Entity Suite', () => {
23
- beforeAll(async () => {
24
- process.env.CFG_TYPEORM_TEST_TYPE = 'better-sqlite3';
25
- process.env.CFG_TYPEORM_TEST_SYNCHRONIZE = 'true';
26
- // in memory, kept in global cache, to make sure always use same one.
27
- process.env.CFG_TYPEORM_TEST_KEPT_ON_GLOBAL = 'true';
28
- await new TypeOrmDataSourceHelper(config).create({
29
- 'TEST': [TestTable]
30
- });
31
- const repo = (await TypeOrmDataSourceManager.findDataSource('TEST', config)).getDataSource().getRepository(TestTable);
32
- await repo.insert({id: 1, content: 'hello world!'});
33
- });
34
-
35
- test('TypeORM load entity by id Pipeline Step Test #1', async () => {
36
- const step = new TypeOrmLoadEntityByIdPipelineStep({
37
- config, logger, dataSourceName: 'TEST', entityName: 'TestTable',
38
- autonomous: true
39
- });
40
- const request = {content: 1};
41
- const response = await step.perform(request);
42
- expect(response.content).not.toBeNull();
43
- expect(response.content.id).toBe(1);
44
- expect(response.content.content).toBe('hello world!');
45
- });
46
-
47
- afterAll((done) => {
48
- done();
49
- });
50
- });