remult 0.25.8-exp.0 → 0.25.8-exp.10

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 (73) hide show
  1. package/esm/graphql.js +2 -2
  2. package/esm/migrations/compare-migration-snapshots.js +1 -1
  3. package/esm/migrations/generate-migrations.js +21 -5
  4. package/esm/migrations/migrate.js +35 -14
  5. package/esm/migrations/update-migrations-ts-file.js +2 -2
  6. package/esm/postgres/postgres-data-provider.js +12 -3
  7. package/esm/remult-knex/index.js +6 -2
  8. package/esm/remult-mongo.js +2 -2
  9. package/esm/remult-sql-js.js +5 -0
  10. package/esm/server/expressBridge.js +130 -29
  11. package/esm/server/initAsyncHooks.js +75 -1
  12. package/esm/src/CompoundIdField.js +8 -2
  13. package/esm/src/context.js +6 -16
  14. package/esm/src/data-api.js +56 -25
  15. package/esm/src/data-providers/rest-data-provider.js +17 -15
  16. package/esm/src/data-providers/sql-database.js +7 -3
  17. package/esm/src/data-providers/web-sql-data-provider.js +1 -9
  18. package/esm/src/filter/filter-interfaces.js +31 -0
  19. package/esm/src/isOfType.js +1 -1
  20. package/esm/src/remult3/Fields.js +70 -18
  21. package/esm/src/remult3/RepositoryImplementation.js +14 -9
  22. package/esm/src/remult3/addValidator.js +15 -0
  23. package/esm/src/remult3/remult3.js +14 -63
  24. package/esm/src/server-action.js +2 -2
  25. package/esm/src/validators.js +6 -3
  26. package/esm/src/valueConverters.js +1 -1
  27. package/graphql.js +2 -4
  28. package/migrations/compare-migration-snapshots.js +8 -9
  29. package/migrations/generate-migrations.d.ts +17 -4
  30. package/migrations/generate-migrations.js +24 -6
  31. package/migrations/migrate.d.ts +13 -2
  32. package/migrations/migrate.js +73 -51
  33. package/migrations/migration-types.d.ts +20 -0
  34. package/migrations/update-migrations-ts-file.js +26 -26
  35. package/package.json +1 -1
  36. package/postgres/postgres-data-provider.d.ts +5 -2
  37. package/postgres/postgres-data-provider.js +12 -3
  38. package/remult-knex/index.d.ts +3 -3
  39. package/remult-knex/index.js +6 -2
  40. package/remult-mongo.d.ts +2 -2
  41. package/remult-mongo.js +2 -2
  42. package/remult-sql-js.d.ts +2 -0
  43. package/remult-sql-js.js +14 -0
  44. package/server/expressBridge.d.ts +21 -0
  45. package/server/expressBridge.js +140 -32
  46. package/server/initAsyncHooks.d.ts +16 -0
  47. package/server/initAsyncHooks.js +128 -2
  48. package/src/CompoundIdField.js +8 -2
  49. package/src/column-interfaces.d.ts +9 -3
  50. package/src/context.d.ts +7 -5
  51. package/src/context.js +11 -28
  52. package/src/data-api.d.ts +12 -8
  53. package/src/data-api.js +115 -75
  54. package/src/data-providers/rest-data-provider.js +26 -15
  55. package/src/data-providers/sql-database.d.ts +3 -5
  56. package/src/data-providers/sql-database.js +5 -2
  57. package/src/data-providers/web-sql-data-provider.d.ts +1 -2
  58. package/src/data-providers/web-sql-data-provider.js +4 -8
  59. package/src/filter/filter-interfaces.js +64 -12
  60. package/src/isOfType.js +1 -1
  61. package/src/remult3/Fields.d.ts +36 -0
  62. package/src/remult3/Fields.js +81 -19
  63. package/src/remult3/RepositoryImplementation.d.ts +9 -13
  64. package/src/remult3/RepositoryImplementation.js +64 -54
  65. package/src/remult3/addValidator.d.ts +2 -0
  66. package/src/remult3/addValidator.js +20 -0
  67. package/src/remult3/remult3.d.ts +10 -16
  68. package/src/remult3/remult3.js +14 -63
  69. package/src/server-action.js +2 -2
  70. package/src/sql-command.d.ts +1 -0
  71. package/src/validators.d.ts +1 -0
  72. package/src/validators.js +10 -4
  73. package/src/valueConverters.js +1 -1
package/esm/graphql.js CHANGED
@@ -904,7 +904,7 @@ export function translateWhereToRestBody(fields, { where }) {
904
904
  }
905
905
  }
906
906
  if (where.OR) {
907
- result.OR = where.OR.map((where) => translateWhereToRestBody(fields, { where }));
907
+ result.OR = where.OR.map((where) => translateWhereToRestBody(fields, { where }).where);
908
908
  }
909
- return result;
909
+ return { where: result };
910
910
  }
@@ -28,8 +28,8 @@ export async function compareMigrationSnapshot({ entities, snapshot, migrationBu
28
28
  }
29
29
  }
30
30
  }
31
- return snapshot;
32
31
  }
32
+ return snapshot;
33
33
  }
34
34
  export function emptySnapshot() {
35
35
  return {
@@ -4,12 +4,25 @@ import { compareMigrationSnapshot, emptySnapshot, } from './compare-migration-sn
4
4
  import { updateMigrationsFile } from './update-migrations-ts-file.js';
5
5
  import { DefaultMigrationBuilder, } from './migration-types.js';
6
6
  import { isOfType } from '../src/isOfType.js';
7
+ import { initDataProvider } from '../server/initDataProvider.js';
8
+ /**
9
+ * Generates migration scripts based on changes in entities.
10
+ *
11
+ * @param options - Configuration options for generating migrations.
12
+ * @param options.entities - An array of entity classes to be included in the migration.
13
+ * @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
14
+ * @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/server/migrations'.
15
+ * @param options.snapshotFile - (Optional) The path to the file where the snapshot of the last known state will be stored. Default is 'migrations-snapshot.json' in the `migrationsFolder`.
16
+ * @param options.migrationsTSFile - (Optional) The path to the TypeScript file where the generated migrations will be written. Default is 'migrations.ts' in the `migrationsFolder`.
17
+ * @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is true.
18
+ * @see [Migrations](http://remult.dev/docs/migrations.html)
19
+ */
7
20
  export async function generateMigrations(options) {
8
- const migrationDir = options.migrationsDir || path.join(process.cwd(), 'src/server/migrations');
9
- const snapshotFileName = options.snapshotFileName ||
10
- path.join(migrationDir, 'migrations-snapshot.json');
11
- const migrationsTSFilename = options.migrationsTSFilename || path.join(migrationDir, 'migrations.ts');
12
- const dataProvider = await options.dataProvider;
21
+ const migrationDir = options.migrationsFolder ||
22
+ path.join(process.cwd(), 'src/server/migrations');
23
+ const snapshotFileName = options.snapshotFile || path.join(migrationDir, 'migrations-snapshot.json');
24
+ const migrationsTSFilename = options.migrationsTSFile || path.join(migrationDir, 'migrations.ts');
25
+ const dataProvider = await initDataProvider(options.dataProvider);
13
26
  for (const p of [snapshotFileName, migrationsTSFilename]) {
14
27
  if (!fs.existsSync(path.dirname(p))) {
15
28
  fs.mkdirSync(path.dirname(p), { recursive: true });
@@ -44,4 +57,7 @@ export async function generateMigrations(options) {
44
57
  `async (${hasSql ? '{sql}' : ''})=>{\n${steps.join('\n')}\n}`,
45
58
  ]);
46
59
  fs.writeFileSync(snapshotFileName, JSON.stringify(snapshot, null, 2));
60
+ if (options.endConnection !== false && isOfType(dataProvider, 'end')) {
61
+ await dataProvider.end();
62
+ }
47
63
  }
@@ -1,12 +1,21 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import { Entity, IdEntity, Fields, remult, Remult, } from '../index.js';
3
+ import { initDataProvider } from '../server/initDataProvider.js';
3
4
  import { doTransaction } from '../src/context.js';
4
- import { cast } from '../src/isOfType.js';
5
+ import { cast, isOfType } from '../src/isOfType.js';
6
+ /**
7
+ * Applies migration scripts to update the database schema.
8
+ *
9
+ * @param options - Configuration options for applying migrations.
10
+ * @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
11
+ * @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
12
+ * @param options.migrationsTable - (Optional) The name of the table that tracks applied migrations. Default is '__remult_migrations_version'.
13
+ * @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is true.
14
+ * @see [Migrations](http://remult.dev/docs/migrations.html)
15
+ */
5
16
  export async function migrate(options) {
6
- let migrationTableName = options.migrationTableName || '__remult_migration_version';
7
- const dataProvider = options.dataProvider
8
- ? await options.dataProvider
9
- : remult.dataProvider;
17
+ let migrationTableName = options.migrationsTable || '__remult_migrations_version';
18
+ const dataProvider = await initDataProvider(options.dataProvider);
10
19
  const prev = remult.dataProvider;
11
20
  remult.dataProvider = dataProvider;
12
21
  try {
@@ -36,15 +45,24 @@ export async function migrate(options) {
36
45
  throw new Error('Migration step number must be a non-negative integer');
37
46
  if (v.version >= step)
38
47
  continue;
39
- console.info('Executing migration step', step);
40
- await doTransaction(remult, async (dp) => {
41
- const utils = {
42
- sql: async (sql) => {
43
- await cast(dp, 'execute').execute(sql);
44
- },
45
- };
46
- await action(utils);
47
- });
48
+ console.info('Executing migration step ' + step);
49
+ console.time('Completed migration step ' + step);
50
+ try {
51
+ await doTransaction(remult, async (dp) => {
52
+ const utils = {
53
+ sql: async (sql) => {
54
+ await cast(dp, 'execute').execute(sql);
55
+ },
56
+ };
57
+ await action(utils);
58
+ });
59
+ console.timeEnd('Completed migration step ' + step);
60
+ }
61
+ catch (err) {
62
+ console.error('Failed to execute migration step ' + step);
63
+ console.error(err);
64
+ throw err;
65
+ }
48
66
  v.version = step;
49
67
  await v.save();
50
68
  }
@@ -52,4 +70,7 @@ export async function migrate(options) {
52
70
  finally {
53
71
  remult.dataProvider = prev;
54
72
  }
73
+ if (options.endConnection !== false && isOfType(dataProvider, 'end')) {
74
+ await dataProvider.end();
75
+ }
55
76
  }
@@ -1,5 +1,5 @@
1
1
  // consider replacing with https://www.npmjs.com/package/ts-morph
2
- import * as ts from 'typescript';
2
+ import ts from 'typescript';
3
3
  import * as fs from 'fs';
4
4
  export async function updateMigrationsFile(filePath, steps) {
5
5
  let maxStep = -1;
@@ -10,7 +10,7 @@ export async function updateMigrationsFile(filePath, steps) {
10
10
  fs.writeFileSync(filePath, '');
11
11
  }
12
12
  const importPath = 'remult/migrations';
13
- const importName = 'MigrationSteps';
13
+ const importName = 'Migrations';
14
14
  // Load the file
15
15
  const sourceFile = ts.createSourceFile(filePath, fs.readFileSync(filePath).toString(), ts.ScriptTarget.Latest, true);
16
16
  let migrationsExportFound = false;
@@ -1,3 +1,4 @@
1
+ import { remult as defaultRemult } from '../src/remult-proxy.js';
1
2
  import pg from 'pg';
2
3
  const { Pool } = pg;
3
4
  import { Remult } from '../src/context.js';
@@ -7,9 +8,11 @@ export class PostgresDataProvider {
7
8
  pool;
8
9
  options;
9
10
  supportsJsonColumnType = true;
10
- static getDb(remult) {
11
- const sql = SqlDatabase.getDb(remult);
12
- const me = sql._getSourceSql();
11
+ static getDb(dataProvider) {
12
+ const r = (dataProvider || defaultRemult.dataProvider);
13
+ if (!r._getSourceSql)
14
+ throw 'the data provider is not an SqlDatabase';
15
+ const me = r._getSourceSql();
13
16
  if (!me.pool) {
14
17
  throw 'the data provider is not a PostgresDataProvider';
15
18
  }
@@ -35,6 +38,9 @@ export class PostgresDataProvider {
35
38
  this.pool = new PostgresSchemaWrapper(pool, options.schema);
36
39
  }
37
40
  }
41
+ end() {
42
+ return this.pool.end();
43
+ }
38
44
  provideMigrationBuilder(builder) {
39
45
  var db = new SqlDatabase(this);
40
46
  var sb = new PostgresSchemaBuilder(db, this.options?.schema);
@@ -184,4 +190,7 @@ export class PostgresSchemaWrapper {
184
190
  c.release();
185
191
  }
186
192
  }
193
+ end() {
194
+ return this.pool.end();
195
+ }
187
196
  }
@@ -13,6 +13,10 @@ export class KnexDataProvider {
13
13
  constructor(knex) {
14
14
  this.knex = knex;
15
15
  }
16
+ end() {
17
+ return this.knex.destroy();
18
+ }
19
+ /* @internal */
16
20
  provideMigrationBuilder(builder) {
17
21
  var sb = new KnexSchemaBuilder(this.knex);
18
22
  return {
@@ -37,8 +41,8 @@ export class KnexDataProvider {
37
41
  execute(sql) {
38
42
  return this.createCommand().execute(sql);
39
43
  }
40
- static getDb(remult) {
41
- const r = (remult || remultContext).dataProvider;
44
+ static getDb(dataProvider) {
45
+ const r = (dataProvider || remultContext.dataProvider);
42
46
  if (!r.knex)
43
47
  throw 'the data provider is not an KnexDataProvider';
44
48
  return r.knex;
@@ -16,8 +16,8 @@ export class MongoDataProvider {
16
16
  }
17
17
  session;
18
18
  disableTransactions = false;
19
- static getDb(remult) {
20
- const r = (remult || remultContext).dataProvider;
19
+ static getDb(dataProvider) {
20
+ const r = (dataProvider || remultContext.dataProvider);
21
21
  if (!r.db)
22
22
  throw 'the data provider is not a MongoDataProvider';
23
23
  return { db: r.db, session: r.session };
@@ -6,6 +6,11 @@ export class SqlJsDataProvider {
6
6
  constructor(db) {
7
7
  this.db = db;
8
8
  }
9
+ orderByNullsFirst;
10
+ async end() {
11
+ ;
12
+ (await this.db).close();
13
+ }
9
14
  getLimitSqlSyntax(limit, offset) {
10
15
  return ' limit ' + limit + ' offset ' + offset;
11
16
  }
@@ -13,6 +13,7 @@ import { serverActionField } from '../src/server-action-info.js';
13
13
  import { initDataProvider } from './initDataProvider.js';
14
14
  import { remultStatic } from '../src/remult-static.js';
15
15
  import remultAdminHtml from './remult-admin.js';
16
+ import { isOfType } from '../src/isOfType.js';
16
17
  export function createRemultServerCore(options, serverCoreOptions) {
17
18
  if (!options) {
18
19
  options = {};
@@ -249,8 +250,8 @@ export class RemultServerImplementation {
249
250
  console.info('[remult] ' + myRoute);
250
251
  r.route(myRoute)
251
252
  .get(this.process((c, req, res, orig) => dataApiFactory(c).httpGet(res, req, () => this.serializeContext(c))))
252
- .put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).put(res, '', await this.coreOptions.getRequestBody(orig))))
253
- .delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, '')))
253
+ .put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).updateMany(res, req, await this.coreOptions.getRequestBody(orig))))
254
+ .delete(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).deleteMany(res, req, undefined)))
254
255
  .post(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).httpPost(res, req, await this.coreOptions.getRequestBody(orig), () => this.serializeContext(c))));
255
256
  r.route(myRoute + '/:id')
256
257
  //@ts-ignore
@@ -285,7 +286,7 @@ export class RemultServerImplementation {
285
286
  genReq.params = req['_tempParams'];
286
287
  }
287
288
  let myReq = new ExpressRequestBridgeToDataApiRequest(genReq);
288
- let myRes = new ExpressResponseBridgeToDataApiResponse(origRes, req);
289
+ let myRes = new ExpressResponseBridgeToDataApiResponse(origRes, req, this.options.error);
289
290
  try {
290
291
  await this.runWithRemult(async (remult) => {
291
292
  if (req) {
@@ -315,7 +316,7 @@ export class RemultServerImplementation {
315
316
  });
316
317
  }
317
318
  catch (err) {
318
- myRes.error(serializeError(err));
319
+ myRes.error(err, undefined);
319
320
  }
320
321
  };
321
322
  }
@@ -466,6 +467,17 @@ export class RemultServerImplementation {
466
467
  return secureBase(condition, def, item);
467
468
  };
468
469
  let apiPath = (spec.paths[this.options.rootPath + '/' + key] = {});
470
+ let itemInBody = {
471
+ requestBody: {
472
+ content: {
473
+ 'application/json': {
474
+ schema: {
475
+ $ref: '#/components/schemas/' + mutationKey,
476
+ },
477
+ },
478
+ },
479
+ },
480
+ };
469
481
  let apiPathWithId = (spec.paths[this.options.rootPath + '/' + key + '/{id}'] = {});
470
482
  //https://github.com/2fd/open-api.d.ts
471
483
  apiPath.get = secure(meta.options.allowApiRead, true, {
@@ -518,6 +530,73 @@ export class RemultServerImplementation {
518
530
  },
519
531
  },
520
532
  });
533
+ apiPath.delete = secure(meta.options.allowApiDelete, true, {
534
+ description: 'deletes row of ' +
535
+ key +
536
+ '. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)',
537
+ parameters: [...parameters],
538
+ responses: {
539
+ '400': {
540
+ description: 'Error: Bad Request',
541
+ content: {
542
+ 'application/json': {
543
+ schema: {
544
+ $ref: '#/components/schemas/InvalidResponse',
545
+ },
546
+ },
547
+ },
548
+ },
549
+ '200': {
550
+ description: 'returns the number of deleted rows ' + key,
551
+ content: {
552
+ 'application/json': {
553
+ schema: {
554
+ type: 'object',
555
+ properties: {
556
+ deleted: {
557
+ type: 'number',
558
+ },
559
+ },
560
+ },
561
+ },
562
+ },
563
+ },
564
+ },
565
+ });
566
+ apiPath.put = secure(meta.options.allowApiDelete, true, {
567
+ description: 'updates row of ' +
568
+ key +
569
+ '. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)',
570
+ parameters: [...parameters],
571
+ ...itemInBody,
572
+ responses: {
573
+ '400': {
574
+ description: 'Error: Bad Request',
575
+ content: {
576
+ 'application/json': {
577
+ schema: {
578
+ $ref: '#/components/schemas/InvalidResponse',
579
+ },
580
+ },
581
+ },
582
+ },
583
+ '200': {
584
+ description: 'returns the number of updated rows ' + key,
585
+ content: {
586
+ 'application/json': {
587
+ schema: {
588
+ type: 'object',
589
+ properties: {
590
+ updated: {
591
+ type: 'number',
592
+ },
593
+ },
594
+ },
595
+ },
596
+ },
597
+ },
598
+ },
599
+ });
521
600
  let idParameter = {
522
601
  name: 'id',
523
602
  in: 'path',
@@ -525,17 +604,6 @@ export class RemultServerImplementation {
525
604
  required: true,
526
605
  schema: { type: 'string' },
527
606
  };
528
- let itemInBody = {
529
- requestBody: {
530
- content: {
531
- 'application/json': {
532
- schema: {
533
- $ref: '#/components/schemas/' + mutationKey,
534
- },
535
- },
536
- },
537
- },
538
- };
539
607
  apiPath.post = secure(meta.options.allowApiInsert, false, {
540
608
  //"summary": "insert a " + key,
541
609
  //"description": "insert a " + key,
@@ -673,15 +741,17 @@ class ExpressRequestBridgeToDataApiRequest {
673
741
  class ExpressResponseBridgeToDataApiResponse {
674
742
  r;
675
743
  req;
744
+ handleError;
676
745
  forbidden() {
677
- this.setStatus(403).end();
746
+ this.error({ message: 'Forbidden' }, undefined, 403);
678
747
  }
679
748
  setStatus(status) {
680
749
  return this.r.status(status);
681
750
  }
682
- constructor(r, req) {
751
+ constructor(r, req, handleError) {
683
752
  this.r = r;
684
753
  this.req = req;
754
+ this.handleError = handleError;
685
755
  }
686
756
  progress(progress) { }
687
757
  success(data) {
@@ -694,22 +764,53 @@ class ExpressResponseBridgeToDataApiResponse {
694
764
  this.setStatus(204).end();
695
765
  }
696
766
  notFound() {
697
- this.setStatus(404).end();
767
+ this.error({ message: 'Forbidden' }, undefined, 404);
698
768
  }
699
- error(data) {
700
- data = serializeError(data);
701
- console.error({
702
- message: data.message,
703
- stack: data.stack?.split('\n'),
704
- url: this.req?.url,
705
- method: this.req?.method,
769
+ async error(exception, entity, httpStatusCode) {
770
+ let data = serializeError(exception);
771
+ if (!httpStatusCode) {
772
+ if (data.httpStatusCode) {
773
+ httpStatusCode = data.httpStatusCode;
774
+ }
775
+ else if (isOfType(exception, 'isForbiddenError') &&
776
+ exception.isForbiddenError) {
777
+ httpStatusCode = 403;
778
+ }
779
+ else if (data.modelState) {
780
+ httpStatusCode = 400;
781
+ }
782
+ else {
783
+ httpStatusCode = 500;
784
+ }
785
+ }
786
+ let responseSent = false;
787
+ const sendError = (httpStatusCode, body) => {
788
+ if (responseSent) {
789
+ throw Error('Error response already sent');
790
+ }
791
+ responseSent = true;
792
+ console.error({
793
+ message: body.message,
794
+ httpStatusCode,
795
+ stack: data.stack?.split('\n'),
796
+ url: this.req?.url,
797
+ method: this.req?.method,
798
+ });
799
+ this.setStatus(httpStatusCode).json(body);
800
+ };
801
+ await this.handleError?.({
802
+ httpStatusCode,
803
+ req: this.req,
804
+ entity,
805
+ exception,
806
+ responseBody: data,
807
+ sendError,
706
808
  });
707
- this.setStatus(400).json(data);
809
+ if (!responseSent) {
810
+ sendError(httpStatusCode, data);
811
+ }
708
812
  }
709
813
  }
710
- function throwError() {
711
- throw 'Invalid';
712
- }
713
814
  class inProcessQueueHandler {
714
815
  storage;
715
816
  constructor(storage) {
@@ -6,5 +6,79 @@ export function initAsyncHooks() {
6
6
  if (init)
7
7
  return;
8
8
  init = true;
9
- remultStatic.asyncContext = new RemultAsyncLocalStorage(new AsyncLocalStorage());
9
+ remultStatic.asyncContext = new RemultAsyncLocalStorage(new AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore());
10
+ let test = new AsyncLocalStorage();
11
+ test.run(1, async () => {
12
+ await Promise.resolve();
13
+ if (test.getStore() === undefined) {
14
+ console.log("async_hooks.AsyncLocalStorage not working, using sequential implementation (You're probably running on stackblitz, this will work on a normal nodejs environment");
15
+ remultStatic.asyncContext = new RemultAsyncLocalStorage(new SequentialRemultAsyncLocalStorageCore());
16
+ }
17
+ });
18
+ }
19
+ export class AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl {
20
+ asyncLocalStorage = new AsyncLocalStorage();
21
+ wasImplemented;
22
+ run(store, callback) {
23
+ let r;
24
+ this.asyncLocalStorage.run(store, () => {
25
+ r = new Promise(async (res, rej) => {
26
+ try {
27
+ res(await callback());
28
+ }
29
+ catch (err) {
30
+ rej(err);
31
+ }
32
+ });
33
+ });
34
+ return r;
35
+ }
36
+ getStore() {
37
+ return this.asyncLocalStorage.getStore();
38
+ }
39
+ }
40
+ const ignoreInStack = ["AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore.run", "RemultAsyncLocalStorage.run", "Module.withRemult", "RemultServerImplementation.runWithRemult"];
41
+ export class SequentialRemultAsyncLocalStorageCore {
42
+ wasImplemented;
43
+ async run(store, callback) {
44
+ let log = (msg) => {
45
+ };
46
+ if (false) {
47
+ let stack = new Error().stack;
48
+ let y = stack.split('\n');
49
+ while (y.length > 0 && (y[0].trim().startsWith("Error") || ignoreInStack.includes(y[0].trim().split(' ')[1]))) {
50
+ y.splice(0, 1);
51
+ }
52
+ stack = y.join('\n');
53
+ log = (msg) => {
54
+ console.log(msg, stack);
55
+ };
56
+ }
57
+ log('waiting on ');
58
+ const nextPromise = this.lastPromise.then(async () => {
59
+ log('executing ');
60
+ const previousValue = this.currentValue;
61
+ this.currentValue = store;
62
+ const result = await callback();
63
+ this.currentValue = previousValue;
64
+ return result;
65
+ });
66
+ this.lastPromise = nextPromise.catch(() => {
67
+ log("Error on ");
68
+ return undefined;
69
+ });
70
+ try {
71
+ return await nextPromise;
72
+ }
73
+ finally {
74
+ log('completed ');
75
+ }
76
+ }
77
+ getStore() {
78
+ return this.currentValue;
79
+ }
80
+ lastPromise = Promise.resolve(undefined);
81
+ currentValue;
82
+ }
83
+ export class AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore extends AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl {
10
84
  }
@@ -22,11 +22,17 @@ export class CompoundIdField {
22
22
  return Promise.resolve('');
23
23
  }
24
24
  getId(instance) {
25
+ let get = (field) => {
26
+ return instance[field.key];
27
+ };
28
+ if (typeof instance === 'function') {
29
+ get = instance;
30
+ }
25
31
  let r = '';
26
32
  this.fields.forEach((c) => {
27
33
  if (r.length > 0)
28
34
  r += ',';
29
- r += instance[c.key];
35
+ r += c.valueConverter.toJson(get(c));
30
36
  });
31
37
  return r;
32
38
  }
@@ -49,7 +55,7 @@ export class CompoundIdField {
49
55
  let val = value.toString();
50
56
  let id = val.split(',');
51
57
  this.fields.forEach((c, i) => {
52
- result[c.key] = id[i];
58
+ result[c.key] = c.valueConverter.fromJson(id[i]);
53
59
  });
54
60
  return result;
55
61
  }
@@ -24,11 +24,12 @@ export class RemultAsyncLocalStorage {
24
24
  constructor(remultObjectStorage) {
25
25
  this.remultObjectStorage = remultObjectStorage;
26
26
  }
27
- run(remult, callback) {
28
- if (this.remultObjectStorage)
29
- this.remultObjectStorage.run(remult, () => callback(remult));
27
+ async run(remult, callback) {
28
+ if (this.remultObjectStorage) {
29
+ return this.remultObjectStorage.run(remult, () => callback(remult));
30
+ }
30
31
  else
31
- callback(remult);
32
+ return callback(remult);
32
33
  }
33
34
  getRemult() {
34
35
  if (!this.remultObjectStorage) {
@@ -285,16 +286,5 @@ export function withRemult(callback, options) {
285
286
  const remult = new Remult();
286
287
  if (options?.dataProvider)
287
288
  remult.dataProvider = options.dataProvider;
288
- let r;
289
- remultStatic.asyncContext.run(remult, () => {
290
- r = new Promise(async (res, rej) => {
291
- try {
292
- res(await callback(remult));
293
- }
294
- catch (err) {
295
- rej(err);
296
- }
297
- });
298
- });
299
- return r;
289
+ return remultStatic.asyncContext.run(remult, r => callback(r));
300
290
  }