remult 0.25.8 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +194 -129
  2. package/esm/graphql.js +131 -59
  3. package/esm/index.js +1 -1
  4. package/esm/migrations/compare-migration-snapshots.js +61 -0
  5. package/esm/migrations/generate-migrations.js +68 -0
  6. package/esm/migrations/index.js +2 -0
  7. package/esm/migrations/migrate.js +90 -0
  8. package/esm/migrations/migration-types.js +36 -0
  9. package/esm/migrations/update-migrations-ts-file.js +115 -0
  10. package/esm/postgres/postgres-data-provider.js +24 -3
  11. package/esm/postgres/schema-builder.js +35 -26
  12. package/esm/remult-better-sqlite3.js +47 -0
  13. package/esm/remult-bun-sqlite.js +41 -0
  14. package/esm/remult-knex/index.js +180 -51
  15. package/esm/remult-mongo.js +2 -2
  16. package/esm/remult-sql-js.js +3 -78
  17. package/esm/remult-sqlite-core.js +104 -0
  18. package/esm/server/expressBridge.js +130 -29
  19. package/esm/server/initAsyncHooks.js +75 -1
  20. package/esm/src/CompoundIdField.js +8 -2
  21. package/esm/src/context.js +20 -24
  22. package/esm/src/data-api.js +71 -30
  23. package/esm/src/data-providers/rest-data-provider.js +17 -15
  24. package/esm/src/data-providers/sql-database.js +32 -7
  25. package/esm/src/data-providers/web-sql-data-provider.js +1 -9
  26. package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +37 -11
  27. package/esm/src/filter/filter-interfaces.js +229 -17
  28. package/esm/src/isOfType.js +9 -0
  29. package/esm/src/remult3/Fields.js +70 -18
  30. package/esm/src/remult3/RepositoryImplementation.js +47 -21
  31. package/esm/src/remult3/addValidator.js +15 -0
  32. package/esm/src/remult3/remult3.js +28 -57
  33. package/esm/src/server-action.js +4 -4
  34. package/esm/src/validators.js +6 -3
  35. package/esm/src/valueConverters.js +1 -1
  36. package/graphql.js +156 -71
  37. package/index.d.ts +4 -4
  38. package/index.js +2 -1
  39. package/migrations/compare-migration-snapshots.d.ts +27 -0
  40. package/migrations/compare-migration-snapshots.js +165 -0
  41. package/migrations/generate-migrations.d.ts +21 -0
  42. package/migrations/generate-migrations.js +104 -0
  43. package/migrations/index.d.ts +3 -0
  44. package/migrations/index.js +7 -0
  45. package/migrations/migrate.d.ts +27 -0
  46. package/migrations/migrate.js +175 -0
  47. package/migrations/migration-types.d.ts +48 -0
  48. package/migrations/migration-types.js +88 -0
  49. package/migrations/update-migrations-ts-file.d.ts +1 -0
  50. package/migrations/update-migrations-ts-file.js +141 -0
  51. package/package.json +21 -1
  52. package/postgres/postgres-data-provider.d.ts +8 -3
  53. package/postgres/postgres-data-provider.js +46 -3
  54. package/postgres/schema-builder.js +81 -48
  55. package/remult-better-sqlite3.d.ts +12 -0
  56. package/remult-better-sqlite3.js +64 -0
  57. package/remult-bun-sqlite.d.ts +11 -0
  58. package/remult-bun-sqlite.js +56 -0
  59. package/remult-knex/index.d.ts +12 -5
  60. package/remult-knex/index.js +257 -90
  61. package/remult-mongo.d.ts +2 -2
  62. package/remult-mongo.js +2 -2
  63. package/remult-sql-js.d.ts +2 -15
  64. package/remult-sql-js.js +11 -152
  65. package/remult-sqlite-core.d.ts +21 -0
  66. package/remult-sqlite-core.js +217 -0
  67. package/server/expressBridge.d.ts +30 -1
  68. package/server/expressBridge.js +140 -32
  69. package/server/initAsyncHooks.d.ts +16 -0
  70. package/server/initAsyncHooks.js +128 -2
  71. package/src/CompoundIdField.js +8 -2
  72. package/src/column-interfaces.d.ts +9 -3
  73. package/src/context.d.ts +8 -6
  74. package/src/context.js +27 -36
  75. package/src/data-api.d.ts +13 -9
  76. package/src/data-api.js +184 -135
  77. package/src/data-providers/rest-data-provider.js +26 -15
  78. package/src/data-providers/sql-database.d.ts +17 -5
  79. package/src/data-providers/sql-database.js +31 -7
  80. package/src/data-providers/web-sql-data-provider.d.ts +1 -2
  81. package/src/data-providers/web-sql-data-provider.js +4 -8
  82. package/src/entity.d.ts +64 -6
  83. package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +31 -7
  84. package/src/filter/filter-consumer-bridge-to-sql-request.js +46 -21
  85. package/src/filter/filter-interfaces.d.ts +106 -39
  86. package/src/filter/filter-interfaces.js +312 -32
  87. package/src/isOfType.d.ts +2 -0
  88. package/src/isOfType.js +14 -0
  89. package/src/remult3/Fields.d.ts +36 -0
  90. package/src/remult3/Fields.js +81 -19
  91. package/src/remult3/RepositoryImplementation.d.ts +7 -3
  92. package/src/remult3/RepositoryImplementation.js +106 -71
  93. package/src/remult3/addValidator.d.ts +2 -0
  94. package/src/remult3/addValidator.js +20 -0
  95. package/src/remult3/remult3.d.ts +6 -2
  96. package/src/remult3/remult3.js +28 -57
  97. package/src/server-action.d.ts +1 -1
  98. package/src/server-action.js +5 -4
  99. package/src/sql-command.d.ts +6 -1
  100. package/src/validators.d.ts +1 -0
  101. package/src/validators.js +10 -4
  102. package/src/valueConverters.js +1 -1
@@ -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,21 @@ export class PostgresDataProvider {
35
38
  this.pool = new PostgresSchemaWrapper(pool, options.schema);
36
39
  }
37
40
  }
41
+ end() {
42
+ return this.pool.end();
43
+ }
44
+ provideMigrationBuilder(builder) {
45
+ var db = new SqlDatabase(this);
46
+ var sb = new PostgresSchemaBuilder(db, this.options?.schema);
47
+ return {
48
+ addColumn: async (meta, field) => {
49
+ builder.addSql(await sb.getAddColumnScript(meta, field));
50
+ },
51
+ createTable: async (meta) => {
52
+ builder.addSql(await sb.createTableScript(meta));
53
+ },
54
+ };
55
+ }
38
56
  wrapIdentifier = (name) => name
39
57
  .split('.')
40
58
  .map((name) => name.startsWith('"') ? name : '"' + name.replace(/"/g, '""') + '"')
@@ -172,4 +190,7 @@ export class PostgresSchemaWrapper {
172
190
  c.release();
173
191
  }
174
192
  }
193
+ end() {
194
+ return this.pool.end();
195
+ }
175
196
  }
@@ -1,4 +1,4 @@
1
- import { dbNamesOf, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
1
+ import { dbNamesOf, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
2
2
  import { remult as defaultRemult } from '../src/remult-proxy.js';
3
3
  import { remultStatic } from '../src/remult-static.js';
4
4
  import { isAutoIncrement } from '../src/remult3/RepositoryImplementation.js';
@@ -19,7 +19,7 @@ export function postgresColumnSyntax(x, dbName) {
19
19
  if (x.valueConverter == ValueConverters.DateOnly)
20
20
  result += ' date';
21
21
  else
22
- result += ' timestamp';
22
+ result += ' timestamptz';
23
23
  else
24
24
  result += ' ' + x.valueConverter.fieldTypeInDb;
25
25
  }
@@ -109,11 +109,9 @@ export class PostgresSchemaBuilder {
109
109
  for (const entity of entities) {
110
110
  let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
111
111
  try {
112
- if (!entity.options.sqlExpression) {
113
- if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
114
- await this.createIfNotExist(entity);
115
- await this.verifyAllColumns(entity);
116
- }
112
+ if (shouldCreateEntity(entity, e)) {
113
+ await this.createIfNotExist(entity);
114
+ await this.verifyAllColumns(entity);
117
115
  }
118
116
  }
119
117
  catch (err) {
@@ -130,29 +128,41 @@ export class PostgresSchemaBuilder {
130
128
  `${this.whereTableAndSchema(c, e)}`)
131
129
  .then(async (r) => {
132
130
  if (r.rows.length == 0) {
133
- let result = '';
134
- for (const x of entity.fields) {
135
- if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
136
- if (result.length != 0)
137
- result += ',';
138
- result += '\r\n ';
139
- if (isAutoIncrement(x))
140
- result += e.$dbNameOf(x) + ' serial';
141
- else {
142
- result += postgresColumnSyntax(x, e.$dbNameOf(x));
143
- }
144
- if (x == entity.idMetadata.field)
145
- result += ' primary key';
146
- }
147
- }
148
- let sql = `CREATE SCHEMA IF NOT EXISTS ${this.schemaOnly(e)};
149
- CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
131
+ const sql = await this.createTableScript(entity);
150
132
  if (PostgresSchemaBuilder.logToConsole)
151
133
  console.info(sql);
152
134
  await this.pool.execute(sql);
153
135
  }
154
136
  });
155
137
  }
138
+ /* @internal*/
139
+ async getAddColumnScript(entity, field) {
140
+ let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
141
+ return (`ALTER table ${this.schemaAndName(e)} ` +
142
+ `ADD column ${postgresColumnSyntax(field, e.$dbNameOf(field))}`);
143
+ }
144
+ /* @internal*/
145
+ async createTableScript(entity) {
146
+ let result = '';
147
+ let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
148
+ for (const x of entity.fields) {
149
+ if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
150
+ if (result.length != 0)
151
+ result += ',';
152
+ result += '\r\n ';
153
+ if (isAutoIncrement(x))
154
+ result += e.$dbNameOf(x) + ' serial';
155
+ else {
156
+ result += postgresColumnSyntax(x, e.$dbNameOf(x));
157
+ }
158
+ if (x == entity.idMetadata.field)
159
+ result += ' primary key';
160
+ }
161
+ }
162
+ let sql = `CREATE SCHEMA IF NOT EXISTS ${this.schemaOnly(e)};
163
+ CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
164
+ return sql;
165
+ }
156
166
  async addColumnIfNotExist(entity, c) {
157
167
  let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
158
168
  if (shouldNotCreateField(c(entity), e))
@@ -163,8 +173,7 @@ CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
163
173
  if ((await cmd.execute(`SELECT 1 FROM information_schema.columns WHERE ` +
164
174
  `${this.whereTableAndSchema(cmd, e)} ` +
165
175
  `AND column_name=${cmd.param(colName.toLocaleLowerCase())}`)).rows.length == 0) {
166
- let sql = `ALTER table ${this.schemaAndName(e)} ` +
167
- `ADD column ${postgresColumnSyntax(c(entity), colName)}`;
176
+ let sql = await this.getAddColumnScript(entity, c(entity));
168
177
  if (PostgresSchemaBuilder.logToConsole)
169
178
  console.info(sql);
170
179
  await this.pool.execute(sql);
@@ -0,0 +1,47 @@
1
+ import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
2
+ export class BetterSqlite3DataProvider extends SqliteCoreDataProvider {
3
+ constructor(db) {
4
+ super(() => new BetterSqlite3Command(db), async () => { db.close(); });
5
+ }
6
+ }
7
+ class BetterSqlite3Command {
8
+ db;
9
+ values = {};
10
+ i = 0;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async execute(sql) {
15
+ const s = this.db.prepare(sql);
16
+ if (s.reader) {
17
+ return new BetterSqlite3SqlResult(s.all(this.values));
18
+ }
19
+ else {
20
+ const result = s.run(this.values);
21
+ return new BetterSqlite3SqlResult([]);
22
+ }
23
+ }
24
+ addParameterAndReturnSqlToken(val) {
25
+ return this.param(val);
26
+ }
27
+ param(val) {
28
+ if (val instanceof Date)
29
+ val = val.valueOf();
30
+ if (typeof val === "boolean")
31
+ val = val ? 1 : 0;
32
+ const key = ':' + (this.i++);
33
+ this.values[key.substring(1)] = (val);
34
+ return key;
35
+ }
36
+ }
37
+ export class BetterSqlite3SqlResult {
38
+ result;
39
+ constructor(result) {
40
+ this.result = result;
41
+ this.rows = result;
42
+ }
43
+ rows;
44
+ getColumnKeyInResultForIndexInSelect(index) {
45
+ return Object.keys(this.result[0])[index];
46
+ }
47
+ }
@@ -0,0 +1,41 @@
1
+ import { SqliteCoreDataProvider } from "./remult-sqlite-core.js";
2
+ export class BunSqliteDataProvider extends SqliteCoreDataProvider {
3
+ constructor(db) {
4
+ super(() => new BunSqliteCommand(db), async () => { db.close(); });
5
+ }
6
+ }
7
+ class BunSqliteCommand {
8
+ db;
9
+ values = {};
10
+ i = 0;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async execute(sql) {
15
+ const s = this.db.query(sql);
16
+ return new BunSqliteSqlResult(s.all(this.values));
17
+ }
18
+ addParameterAndReturnSqlToken(val) {
19
+ return this.param(val);
20
+ }
21
+ param(val) {
22
+ if (val instanceof Date)
23
+ val = val.valueOf();
24
+ if (typeof val === "boolean")
25
+ val = val ? 1 : 0;
26
+ const key = ':' + (this.i++);
27
+ this.values[key] = (val);
28
+ return key;
29
+ }
30
+ }
31
+ class BunSqliteSqlResult {
32
+ result;
33
+ constructor(result) {
34
+ this.result = result;
35
+ this.rows = result;
36
+ }
37
+ rows;
38
+ getColumnKeyInResultForIndexInSelect(index) {
39
+ return Object.keys(this.result[0])[index];
40
+ }
41
+ }
@@ -1,4 +1,5 @@
1
- import { dbNamesOf, isDbReadonly, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
1
+ import { CustomSqlFilterBuilder, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
2
+ import { dbNamesOf, isDbReadonly, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
2
3
  import { customDatabaseFilterToken, Filter, } from '../src/filter/filter-interfaces.js';
3
4
  import { CompoundIdField } from '../src/CompoundIdField.js';
4
5
  import { remult as remultContext } from '../src/remult-proxy.js';
@@ -13,8 +14,36 @@ export class KnexDataProvider {
13
14
  constructor(knex) {
14
15
  this.knex = knex;
15
16
  }
16
- static getDb(remult) {
17
- const r = (remult || remultContext).dataProvider;
17
+ end() {
18
+ return this.knex.destroy();
19
+ }
20
+ /* @internal */
21
+ provideMigrationBuilder(builder) {
22
+ var sb = new KnexSchemaBuilder(this.knex);
23
+ return {
24
+ async createTable(entity) {
25
+ let e = await dbNamesOf(entity, (x) => x);
26
+ sb.createTableKnexCommand(entity, e)
27
+ .toSQL()
28
+ .forEach((sql) => builder.addSql(sql.sql));
29
+ },
30
+ async addColumn(entity, field) {
31
+ let e = await dbNamesOf(entity, (x) => x);
32
+ await sb
33
+ .createColumnKnexCommand(e, field, e.$dbNameOf(field))
34
+ .toSQL()
35
+ .forEach((sql) => builder.addSql(sql.sql));
36
+ },
37
+ };
38
+ }
39
+ createCommand() {
40
+ return new KnexBridgeToSQLCommand(this.knex);
41
+ }
42
+ execute(sql) {
43
+ return this.createCommand().execute(sql);
44
+ }
45
+ static getDb(dataProvider) {
46
+ const r = (dataProvider || remultContext.dataProvider);
18
47
  if (!r.knex)
19
48
  throw 'the data provider is not an KnexDataProvider';
20
49
  return r.knex;
@@ -43,7 +72,7 @@ export class KnexDataProvider {
43
72
  }
44
73
  }
45
74
  }
46
- return new KnexEntityDataProvider(entity, this.knex);
75
+ return new KnexEntityDataProvider(entity, this.knex, this.wrapIdentifier);
47
76
  }
48
77
  async transaction(action) {
49
78
  let t = await this.knex.transaction();
@@ -63,9 +92,9 @@ export class KnexDataProvider {
63
92
  },
64
93
  };
65
94
  }
66
- static async filterToRaw(entity, condition) {
95
+ static async filterToRaw(entity, condition, wrapIdentifier) {
67
96
  const repo = getRepository(entity);
68
- var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x));
97
+ var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x), wrapIdentifier);
69
98
  b._addWhere = false;
70
99
  await (await getRepositoryInternals(repo)._translateWhereToFilter(condition)).__applyToConsumer(b);
71
100
  let r = await b.resolveWhere();
@@ -80,13 +109,15 @@ export class KnexDataProvider {
80
109
  class KnexEntityDataProvider {
81
110
  entity;
82
111
  knex;
83
- constructor(entity, knex) {
112
+ rawSqlWrapIdentifier;
113
+ constructor(entity, knex, rawSqlWrapIdentifier) {
84
114
  this.entity = entity;
85
115
  this.knex = knex;
116
+ this.rawSqlWrapIdentifier = rawSqlWrapIdentifier;
86
117
  }
87
118
  async count(where) {
88
119
  const e = await this.init();
89
- const br = new FilterConsumerBridgeToKnexRequest(e);
120
+ const br = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
90
121
  where.__applyToConsumer(br);
91
122
  let r = await br.resolveWhere();
92
123
  const result = await this.knex(e.$entityName)
@@ -115,7 +146,7 @@ class KnexEntityDataProvider {
115
146
  }
116
147
  let query = this.knex(e.$entityName).select(cols);
117
148
  if (options?.where) {
118
- const br = new FilterConsumerBridgeToKnexRequest(e);
149
+ const br = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
119
150
  options.where.__applyToConsumer(br);
120
151
  let r = await br.resolveWhere();
121
152
  query.where((b) => r.forEach((y) => y(b)));
@@ -160,11 +191,12 @@ class KnexEntityDataProvider {
160
191
  return r.$dbNameOf(f);
161
192
  },
162
193
  $entityName: r.$entityName,
194
+ wrapIdentifier: r.wrapIdentifier,
163
195
  };
164
196
  }
165
197
  async update(id, data) {
166
198
  const e = await this.init();
167
- let f = new FilterConsumerBridgeToKnexRequest(e);
199
+ let f = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
168
200
  Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
169
201
  let resultFilter = this.entity.idMetadata.getIdFilter(id);
170
202
  if (data.id != undefined)
@@ -191,7 +223,7 @@ class KnexEntityDataProvider {
191
223
  }
192
224
  async delete(id) {
193
225
  const e = await this.init();
194
- let f = new FilterConsumerBridgeToKnexRequest(e);
226
+ let f = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
195
227
  Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
196
228
  let where = await f.resolveWhere();
197
229
  await this.knex(e.$entityName)
@@ -239,7 +271,8 @@ class KnexEntityDataProvider {
239
271
  }
240
272
  }
241
273
  class FilterConsumerBridgeToKnexRequest {
242
- nameProvider;
274
+ innerNameProvider;
275
+ rawSqlWrapIdentifier;
243
276
  _addWhere = true;
244
277
  promises = [];
245
278
  result = [];
@@ -253,8 +286,9 @@ class FilterConsumerBridgeToKnexRequest {
253
286
  }
254
287
  return this.result;
255
288
  }
256
- constructor(nameProvider) {
257
- this.nameProvider = nameProvider;
289
+ constructor(innerNameProvider, rawSqlWrapIdentifier) {
290
+ this.innerNameProvider = innerNameProvider;
291
+ this.rawSqlWrapIdentifier = rawSqlWrapIdentifier;
258
292
  }
259
293
  custom(key, customItem) {
260
294
  throw new Error('Custom filter should be translated before it gets here');
@@ -263,7 +297,7 @@ class FilterConsumerBridgeToKnexRequest {
263
297
  this.promises.push((async () => {
264
298
  const result = [];
265
299
  for (const element of orElements) {
266
- let f = new FilterConsumerBridgeToKnexRequest(this.nameProvider);
300
+ let f = new FilterConsumerBridgeToKnexRequest(this.innerNameProvider, this.rawSqlWrapIdentifier);
267
301
  f._addWhere = false;
268
302
  element.__applyToConsumer(f);
269
303
  let where = await f.resolveWhere();
@@ -283,13 +317,13 @@ class FilterConsumerBridgeToKnexRequest {
283
317
  })());
284
318
  }
285
319
  isNull(col) {
286
- this.result.push((b) => b.whereNull(this.nameProvider.$dbNameOf(col)));
320
+ this.result.push((b) => b.whereNull(this.innerNameProvider.$dbNameOf(col)));
287
321
  }
288
322
  isNotNull(col) {
289
- this.result.push((b) => b.whereNotNull(this.nameProvider.$dbNameOf(col)));
323
+ this.result.push((b) => b.whereNotNull(this.innerNameProvider.$dbNameOf(col)));
290
324
  }
291
325
  isIn(col, val) {
292
- this.result.push((knex) => knex.whereIn(this.nameProvider.$dbNameOf(col), val.map((x) => translateValueAndHandleArrayAndHandleArray(col, x))));
326
+ this.result.push((knex) => knex.whereIn(this.innerNameProvider.$dbNameOf(col), val.map((x) => translateValueAndHandleArrayAndHandleArray(col, x))));
293
327
  }
294
328
  isEqualTo(col, val) {
295
329
  this.add(col, val, '=');
@@ -311,7 +345,7 @@ class FilterConsumerBridgeToKnexRequest {
311
345
  }
312
346
  containsCaseInsensitive(col, val) {
313
347
  this.result.push((b) => b.whereRaw('lower (' +
314
- b.client.ref(this.nameProvider.$dbNameOf(col)) +
348
+ b.client.ref(this.innerNameProvider.$dbNameOf(col)) +
315
349
  ") like lower ('%" +
316
350
  val.replace(/'/g, "''") +
317
351
  "%')"));
@@ -319,20 +353,30 @@ class FilterConsumerBridgeToKnexRequest {
319
353
  }
320
354
  notContainsCaseInsensitive(col, val) {
321
355
  this.result.push((b) => b.whereRaw('not lower (' +
322
- b.client.ref(this.nameProvider.$dbNameOf(col)) +
356
+ b.client.ref(this.innerNameProvider.$dbNameOf(col)) +
323
357
  ") like lower ('%" +
324
358
  val.replace(/'/g, "''") +
325
359
  "%')"));
326
360
  this.promises.push((async () => { })());
327
361
  }
328
362
  add(col, val, operator) {
329
- this.result.push((b) => b.where(this.nameProvider.$dbNameOf(col), operator, translateValueAndHandleArrayAndHandleArray(col, val)));
363
+ this.result.push((b) => b.where(this.innerNameProvider.$dbNameOf(col), operator, translateValueAndHandleArrayAndHandleArray(col, val)));
330
364
  }
331
365
  databaseCustom(databaseCustom) {
332
366
  this.promises.push((async () => {
333
367
  if (databaseCustom?.buildKnex) {
334
368
  this.result.push(await databaseCustom.buildKnex());
335
369
  }
370
+ if (databaseCustom?.buildSql) {
371
+ let r = new KnexCommandHelper();
372
+ const item = new CustomSqlFilterBuilder(r, this.rawSqlWrapIdentifier);
373
+ let sql = await databaseCustom.buildSql(item);
374
+ if (typeof sql !== 'string')
375
+ sql = item.sql;
376
+ if (sql) {
377
+ this.result.push((b) => b.whereRaw(sql, r.values));
378
+ }
379
+ }
336
380
  })());
337
381
  }
338
382
  }
@@ -350,11 +394,9 @@ export class KnexSchemaBuilder {
350
394
  for (const entity of entities) {
351
395
  let e = await dbNamesOf(entity, (x) => x);
352
396
  try {
353
- if (!entity.options.sqlExpression) {
354
- if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
355
- await this.createIfNotExist(entity);
356
- await this.verifyAllColumns(entity);
357
- }
397
+ if (shouldCreateEntity(entity, e)) {
398
+ await this.createIfNotExist(entity);
399
+ await this.verifyAllColumns(entity);
358
400
  }
359
401
  }
360
402
  catch (err) {
@@ -366,27 +408,30 @@ export class KnexSchemaBuilder {
366
408
  async createIfNotExist(entity) {
367
409
  const e = await dbNamesOf(entity, (x) => x);
368
410
  if (!(await this.knex.schema.hasTable(e.$entityName))) {
369
- let cols = new Map();
370
- for (const f of entity.fields) {
371
- cols.set(f, {
372
- name: e.$dbNameOf(f),
373
- readonly: shouldNotCreateField(f, e),
374
- });
375
- }
376
- await logSql(this.knex.schema.createTable(e.$entityName, (b) => {
377
- for (const x of entity.fields) {
378
- if (!cols.get(x).readonly || isAutoIncrement(x)) {
379
- if (isAutoIncrement(x))
380
- b.increments(cols.get(x).name);
381
- else {
382
- buildColumn(x, cols.get(x).name, b, supportsJsonDataStorage(this.knex));
383
- if (x == entity.idMetadata.field)
384
- b.primary([cols.get(x).name]);
385
- }
411
+ await logSql(this.createTableKnexCommand(entity, e));
412
+ }
413
+ }
414
+ createTableKnexCommand(entity, e) {
415
+ let cols = new Map();
416
+ for (const f of entity.fields) {
417
+ cols.set(f, {
418
+ name: e.$dbNameOf(f),
419
+ readonly: shouldNotCreateField(f, e),
420
+ });
421
+ }
422
+ return this.knex.schema.createTable(e.$entityName, (b) => {
423
+ for (const x of entity.fields) {
424
+ if (!cols.get(x).readonly || isAutoIncrement(x)) {
425
+ if (isAutoIncrement(x))
426
+ b.increments(cols.get(x).name);
427
+ else {
428
+ buildColumn(x, cols.get(x).name, b, supportsJsonDataStorage(this.knex));
429
+ if (x == entity.idMetadata.field)
430
+ b.primary([cols.get(x).name]);
386
431
  }
387
432
  }
388
- }));
389
- }
433
+ }
434
+ });
390
435
  }
391
436
  async addColumnIfNotExist(entity, c) {
392
437
  let e = await dbNamesOf(entity, (x) => x);
@@ -395,11 +440,14 @@ export class KnexSchemaBuilder {
395
440
  let col = c(entity);
396
441
  let colName = e.$dbNameOf(col);
397
442
  if (!(await this.knex.schema.hasColumn(e.$entityName, colName))) {
398
- await logSql(this.knex.schema.alterTable(e.$entityName, (b) => {
399
- buildColumn(col, colName, b, supportsJsonDataStorage(this.knex));
400
- }));
443
+ await logSql(this.createColumnKnexCommand(e, col, colName));
401
444
  }
402
445
  }
446
+ createColumnKnexCommand(e, col, colName) {
447
+ return this.knex.schema.alterTable(e.$entityName, (b) => {
448
+ buildColumn(col, colName, b, supportsJsonDataStorage(this.knex));
449
+ });
450
+ }
403
451
  async verifyAllColumns(entity) {
404
452
  let e = await dbNamesOf(entity, (x) => x);
405
453
  try {
@@ -475,16 +523,24 @@ export function buildColumn(x, dbName, b, supportsJson = true) {
475
523
  else if (x.valueConverter.fieldTypeInDb == 'json')
476
524
  if (supportsJson)
477
525
  b.json(dbName);
478
- else
479
- b.text(dbName);
526
+ else {
527
+ let c = b.text(dbName);
528
+ if (!x.allowNull)
529
+ c.defaultTo('').notNullable();
530
+ }
480
531
  else
481
532
  b.specificType(dbName, x.valueConverter.fieldTypeInDb);
482
533
  }
483
- else {
534
+ else if (x.valueType === String) {
484
535
  let c = b.string(dbName, x.options.maxLength);
485
536
  if (!x.allowNull)
486
537
  c.defaultTo('').notNullable();
487
538
  }
539
+ else {
540
+ let c = b.text(dbName);
541
+ if (!x.allowNull)
542
+ c.defaultTo('').notNullable();
543
+ }
488
544
  }
489
545
  function logSql(who) {
490
546
  if (KnexSchemaBuilder.logToConsole)
@@ -502,3 +558,76 @@ function translateValueAndHandleArrayAndHandleArray(field, val) {
502
558
  return JSON.stringify(result);
503
559
  return result;
504
560
  }
561
+ class KnexCommandHelper {
562
+ values = {};
563
+ i = 0;
564
+ addParameterAndReturnSqlToken(val) {
565
+ return this.param(val);
566
+ }
567
+ param(val) {
568
+ if (Array.isArray(val))
569
+ val = JSON.stringify(val);
570
+ const key = ':' + this.i++;
571
+ this.values[key.substring(1)] = val;
572
+ return key;
573
+ }
574
+ }
575
+ class KnexBridgeToSQLCommand extends KnexCommandHelper {
576
+ source;
577
+ constructor(source) {
578
+ super();
579
+ this.source = source;
580
+ }
581
+ values = {};
582
+ i = 0;
583
+ addParameterAndReturnSqlToken(val) {
584
+ return this.param(val);
585
+ }
586
+ param(val) {
587
+ if (Array.isArray(val))
588
+ val = JSON.stringify(val);
589
+ const key = ':' + this.i++;
590
+ this.values[key.substring(1)] = val;
591
+ return key;
592
+ }
593
+ async execute(sql) {
594
+ return await this.source.raw(sql, this.values).then((r) => {
595
+ switch (this.source.client.config.client) {
596
+ case 'mysql':
597
+ case 'mysql2':
598
+ return new KnexPostgresBridgeToSQLQueryResult({
599
+ fields: r[1],
600
+ rows: r[0],
601
+ });
602
+ case 'pg':
603
+ return new KnexPostgresBridgeToSQLQueryResult(r);
604
+ default:
605
+ case 'better-sqlite3':
606
+ case 'mssql':
607
+ return new KnexPostgresBridgeToSQLQueryResult({
608
+ rows: r,
609
+ });
610
+ }
611
+ });
612
+ }
613
+ }
614
+ class KnexPostgresBridgeToSQLQueryResult {
615
+ r;
616
+ getColumnKeyInResultForIndexInSelect(index) {
617
+ if (this.r.fields)
618
+ return this.r.fields[index].name;
619
+ if (this.rows.length == 0)
620
+ throw Error('No rows');
621
+ let i = 0;
622
+ for (let m in this.rows[0]) {
623
+ if (i++ == index)
624
+ return m;
625
+ }
626
+ throw Error('index not found');
627
+ }
628
+ constructor(r) {
629
+ this.r = r;
630
+ this.rows = r.rows;
631
+ }
632
+ rows;
633
+ }
@@ -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 };