@rainbow-o23/n3 1.0.46 → 1.0.48

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
@@ -526,6 +526,28 @@ export interface TypeOrmLoadBasis extends TypeOrmBasis {
526
526
  Array<TypeOrmEntityToLoad>;
527
527
  ```
528
528
 
529
+ #### Load Many by SQL, Use Cursor
530
+
531
+ ##### Request and Response
532
+
533
+ ```typescript
534
+ // request
535
+ export interface TypeOrmLoadBasis extends TypeOrmBasis {
536
+ params?: Array<TypeOrmEntityValue> | TypeOrmEntityToSave;
537
+ }
538
+
539
+ // response
540
+ Array<any>;
541
+ ```
542
+
543
+ By specifying `fetchSize`, each batch of data retrieved will execute sub-steps. Before executing the sub-steps, the data to be passed to it
544
+ will be calculated using the `streamTo` function. If `streamTo` is not specified, the batch of data retrieved itself will be passed to the
545
+ sub-steps. If the sub-steps is not specified, all retrieved data will be merged and returned.
546
+
547
+ Therefore, the number of times the sub-step is executed is related to the quantity of data and the `fetchSize`. Meanwhile, each time the
548
+ sub-step is invoked, the context will include a `$$typeOrmCursorRound` variable indicating the current batch (starting from 0), and a
549
+ `$typeOrmCursorEnd` variable indicating whether it is the last batch.
550
+
529
551
  #### Save by SQL
530
552
 
531
553
  ##### 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,124 @@ 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?.close((e) => {
2301
+ this.getLogger().error(e);
2302
+ });
2303
+ }
2304
+ catch (e) {
2305
+ this.getLogger().error(e);
2306
+ }
2307
+ };
2308
+ const read = async ({ resolve, reject }) => {
2309
+ const readable = await runner.stream(sql, params, async () => {
2310
+ await close(readable);
2311
+ await pipe({ resolve, reject, end: true });
2312
+ }, async (e) => {
2313
+ await close(readable);
2314
+ reject(e);
2315
+ });
2316
+ readable.on('data', async (data) => {
2317
+ rows.push(data);
2318
+ await pipe({
2319
+ resolve, reject: async (e) => {
2320
+ await close(readable);
2321
+ reject(e);
2322
+ }, end: false
2323
+ });
2324
+ readable.read();
2325
+ });
2326
+ readable.read();
2327
+ };
2328
+ return new Promise((resolve, reject) => read({ resolve, reject }));
2329
+ }, request);
2330
+ }
2331
+ getFetchDataVariableName() {
2332
+ return '$factor';
2333
+ }
2334
+ getRequestVariableName() {
2335
+ return '$request';
2336
+ }
2337
+ }
2338
+
2219
2339
  class TypeOrmSaveBySQLPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2220
2340
  async doPerform(basis, request) {
2221
2341
  const { sql, params } = this.getSql(basis, basis?.values);
@@ -2355,6 +2475,7 @@ exports.ERR_TYPEORM_DATASOURCE_TYPE_NOT_FOUND = ERR_TYPEORM_DATASOURCE_TYPE_NOT_
2355
2475
  exports.ERR_TYPEORM_ENTITY_NOT_FOUND = ERR_TYPEORM_ENTITY_NOT_FOUND;
2356
2476
  exports.ERR_TYPEORM_SQL_NOT_EMPTY = ERR_TYPEORM_SQL_NOT_EMPTY;
2357
2477
  exports.ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY = ERR_TYPEORM_STEP_SNIPPET_NOT_EMPTY;
2478
+ exports.ERR_TYPEORM_STREAM = ERR_TYPEORM_STREAM;
2358
2479
  exports.ERR_TYPEORM_TRANSACTION_NOT_FOUND = ERR_TYPEORM_TRANSACTION_NOT_FOUND;
2359
2480
  exports.EachPipelineStepSets = EachPipelineStepSets;
2360
2481
  exports.FetchPipelineStep = FetchPipelineStep;
@@ -2377,6 +2498,7 @@ exports.TypeOrmBySnippetPipelineStep = TypeOrmBySnippetPipelineStep;
2377
2498
  exports.TypeOrmDataSourceHelper = TypeOrmDataSourceHelper;
2378
2499
  exports.TypeOrmDataSourceManager = TypeOrmDataSourceManager;
2379
2500
  exports.TypeOrmLoadManyBySQLPipelineStep = TypeOrmLoadManyBySQLPipelineStep;
2501
+ exports.TypeOrmLoadManyBySQLUseCursorPipelineStep = TypeOrmLoadManyBySQLUseCursorPipelineStep;
2380
2502
  exports.TypeOrmLoadOneBySQLPipelineStep = TypeOrmLoadOneBySQLPipelineStep;
2381
2503
  exports.TypeOrmParsedSQLCache = TypeOrmParsedSQLCache;
2382
2504
  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,124 @@ 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?.close((e) => {
2299
+ this.getLogger().error(e);
2300
+ });
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
+ rows.push(data);
2316
+ await pipe({
2317
+ resolve, reject: async (e) => {
2318
+ await close(readable);
2319
+ reject(e);
2320
+ }, end: false
2321
+ });
2322
+ readable.read();
2323
+ });
2324
+ readable.read();
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
+
2217
2337
  class TypeOrmSaveBySQLPipelineStep extends AbstractTypeOrmBySQLPipelineStep {
2218
2338
  async doPerform(basis, request) {
2219
2339
  const { sql, params } = this.getSql(basis, basis?.values);
@@ -2324,4 +2444,4 @@ class TypeOrmTransactionalPipelineStepSets extends PipelineStepSets {
2324
2444
  }
2325
2445
  }
2326
2446
 
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 };
2447
+ 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.46",
3
+ "version": "1.0.48",
4
4
  "description": "o23 pipelines",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
@@ -21,9 +21,9 @@
21
21
  "url": "https://github.com/InsureMO/rainbow-o23/issues"
22
22
  },
23
23
  "dependencies": {
24
- "@rainbow-o23/n1": "1.0.46",
24
+ "@rainbow-o23/n1": "1.0.48",
25
25
  "node-fetch": "2.6.7",
26
- "typeorm": "^0.3.17",
26
+ "typeorm": "^0.3.20",
27
27
  "typescript": "5.5.4"
28
28
  },
29
29
  "devDependencies": {
@@ -36,17 +36,17 @@
36
36
  "@types/events": "^3.0.1",
37
37
  "@types/node": "18.16.12",
38
38
  "@types/node-fetch": "2.6.4",
39
- "@typescript-eslint/eslint-plugin": "^7.18.0",
40
- "@typescript-eslint/parser": "^7.18.0",
41
- "better-sqlite3": "^9.0.0",
39
+ "@typescript-eslint/eslint-plugin": "^8.13.0",
40
+ "@typescript-eslint/parser": "^8.13.0",
41
+ "better-sqlite3": "^11.5.0",
42
42
  "eslint": "^9.8.0",
43
- "mssql": "^10.0.1",
44
- "mysql2": "^3.9.8",
45
- "oracledb": "^6.2.0",
46
- "pg": "^8.11.3",
47
- "pg-query-stream": "^4.5.3",
43
+ "mssql": "^11.0.1",
44
+ "mysql2": "^3.11.4",
45
+ "oracledb": "^6.6.0",
46
+ "pg": "^8.13.1",
47
+ "pg-query-stream": "^4.7.1",
48
48
  "reflect-metadata": "^0.2.2",
49
- "rollup": "^3.7.0",
49
+ "rollup": "^3.29.5",
50
50
  "rollup-plugin-tslint": "^0.2.2",
51
51
  "rollup-plugin-typescript2": "^0.34.1",
52
52
  "tslib": "^2.4.1"
@@ -74,7 +74,6 @@
74
74
  "testEnvironment": "node"
75
75
  },
76
76
  "volta": {
77
- "node": "20.17.0",
78
- "yarn": "1.22.21"
77
+ "extends": "../package.json"
79
78
  }
80
79
  }
@@ -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;
@@ -213,7 +213,6 @@ export abstract class AbstractFragmentaryPipelineStep<In = PipelineStepPayload,
213
213
  };
214
214
  }
215
215
  } else if (typeof funcOrSnippet === 'string') {
216
- // eslint-disable-next-line @typescript-eslint/ban-types
217
216
  const func = Utils.createAsyncFunction(funcOrSnippet, {
218
217
  createDefault: async () => {
219
218
  throw new UncatchableError(ERR_PIPELINE_STEP_SNIPPET_NOT_EMPTY, 'Cannot create perform func on empty snippet.');
@@ -8,6 +8,7 @@ import {
8
8
  import {AbstractFragmentaryPipelineStep, FragmentaryPipelineStepOptions} from './abstract-fragmentary-pipeline-step';
9
9
  import {Utils} from './utils';
10
10
 
11
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
11
12
  export interface PipelineStepSetsContext {
12
13
  }
13
14
 
@@ -7,7 +7,7 @@ import {
7
7
  } from '@rainbow-o23/n1';
8
8
 
9
9
  export type ScriptFunctionBody = string;
10
- // eslint-disable-next-line @typescript-eslint/ban-types
10
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
11
11
  export type ScriptFuncOrBody<F = Function> = F | ScriptFunctionBody;
12
12
 
13
13
  export interface ErrorHandleOptions<In, InFragment, E extends Error = Error> {
@@ -43,7 +43,7 @@ const AvoidProxyObjects = [
43
43
  ];
44
44
 
45
45
  export class Utils {
46
- // eslint-disable-next-line @typescript-eslint/ban-types
46
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
47
47
  public static createFunction<F = Function>(snippet: ScriptFuncOrBody<F>, creators: {
48
48
  createDefault: () => Undefinable<F> | never;
49
49
  getVariableNames: () => Array<string>;
@@ -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;
@@ -105,7 +105,7 @@ export class Utils {
105
105
  }
106
106
  }
107
107
 
108
- // eslint-disable-next-line @typescript-eslint/ban-types
108
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
109
109
  public static createSyncFunction<F = Function>(snippet: ScriptFuncOrBody<F>, creators: {
110
110
  createDefault: () => Undefinable<F> | never;
111
111
  getVariableNames: () => Array<string>;
@@ -114,7 +114,7 @@ export class Utils {
114
114
  return Utils.createFunction(snippet, {...creators});
115
115
  }
116
116
 
117
- // eslint-disable-next-line @typescript-eslint/ban-types
117
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
118
118
  public static createAsyncFunction<F = Function>(snippet: ScriptFuncOrBody<F>, creators: {
119
119
  createDefault: () => Undefinable<F> | never;
120
120
  getVariableNames: () => Array<string>;
@@ -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,165 @@
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?.close((e) => {
121
+ // ignore this error
122
+ this.getLogger().error(e);
123
+ });
124
+ } catch (e) {
125
+ // ignore this error
126
+ this.getLogger().error(e);
127
+ }
128
+ };
129
+ const read = async ({resolve, reject}) => {
130
+ const readable = await runner.stream(sql, params, async () => {
131
+ // on end
132
+ await close(readable);
133
+ await pipe({resolve, reject, end: true});
134
+ }, async (e: Error) => {
135
+ // on error
136
+ await close(readable);
137
+ reject(e);
138
+ });
139
+ readable.on('data', async (data) => {
140
+ rows.push(data);
141
+ await pipe({
142
+ resolve, reject: async (e: Error) => {
143
+ await close(readable);
144
+ reject(e);
145
+ }, end: false
146
+ });
147
+ readable.read();
148
+ });
149
+ readable.read();
150
+ };
151
+ return new Promise<OutFragment>((resolve, reject) => read({resolve, reject}));
152
+ }, request);
153
+ }
154
+
155
+ /**
156
+ * override this method when want to use another variable name rather than "$factor"
157
+ */
158
+ protected getFetchDataVariableName(): string {
159
+ return '$factor';
160
+ }
161
+
162
+ protected getRequestVariableName(): string {
163
+ return '$request';
164
+ }
165
+ }
@@ -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
- });