remult 0.26.18 → 0.26.19-next.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.
@@ -1,4 +1,4 @@
1
- import { CustomSqlFilterBuilder, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
1
+ import { CustomSqlFilterBuilder, dbNamesOfWithForceSqlExpression, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
2
2
  import { dbNamesOf, isDbReadonly, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
3
3
  import { customDatabaseFilterToken, Filter, } from '../src/filter/filter-interfaces.js';
4
4
  import { remult as remultContext } from '../src/remult-proxy.js';
@@ -92,7 +92,7 @@ export class KnexDataProvider {
92
92
  }
93
93
  static async filterToRaw(entity, condition, wrapIdentifier) {
94
94
  const repo = getRepository(entity);
95
- var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x), wrapIdentifier);
95
+ var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOfWithForceSqlExpression(repo.metadata, (x) => x), wrapIdentifier);
96
96
  b._addWhere = false;
97
97
  await (await getRepositoryInternals(repo)._translateWhereToFilter(condition)).__applyToConsumer(b);
98
98
  let r = await b.resolveWhere();
@@ -183,7 +183,7 @@ class KnexEntityDataProvider {
183
183
  });
184
184
  }
185
185
  async init() {
186
- const r = (await dbNamesOf(this.entity, (x) => x));
186
+ const r = (await dbNamesOfWithForceSqlExpression(this.entity, (x) => x));
187
187
  return {
188
188
  $dbNameOf: (f) => {
189
189
  let fm = f;
@@ -1,6 +1,6 @@
1
1
  import { ObjectId, } from 'mongodb';
2
2
  import { Filter } from './index.js';
3
- import { dbNamesOf } from './src/filter/filter-consumer-bridge-to-sql-request.js';
3
+ import { dbNamesOf, dbNamesOfWithForceSqlExpression, } from './src/filter/filter-consumer-bridge-to-sql-request.js';
4
4
  import { remult as remultContext } from './src/remult-proxy.js';
5
5
  import { getRepository } from './src/remult3/RepositoryImplementation.js';
6
6
  import { getRepositoryInternals } from './src/remult3/repository-internals.js';
@@ -50,7 +50,7 @@ export class MongoDataProvider {
50
50
  }
51
51
  static async filterToRaw(entity, condition) {
52
52
  const repo = getRepository(entity);
53
- var b = new FilterConsumerBridgeToMongo(await dbNamesOf(repo.metadata));
53
+ var b = new FilterConsumerBridgeToMongo(await dbNamesOfWithForceSqlExpression(repo.metadata));
54
54
  b._addWhere = false;
55
55
  await (await getRepositoryInternals(repo)._translateWhereToFilter(condition)).__applyToConsumer(b);
56
56
  let r = await b.resolveWhere();
@@ -1,4 +1,4 @@
1
- import { FilterConsumerBridgeToSqlRequest, dbNamesOf, isDbReadonly, } from '../filter/filter-consumer-bridge-to-sql-request.js';
1
+ import { FilterConsumerBridgeToSqlRequest, dbNamesOfWithForceSqlExpression, isDbReadonly, } from '../filter/filter-consumer-bridge-to-sql-request.js';
2
2
  import { Filter, customDatabaseFilterToken, } from '../filter/filter-interfaces.js';
3
3
  import { remult as defaultRemult } from '../remult-proxy.js';
4
4
  import { getRepository, isAutoIncrement, } from '../remult3/RepositoryImplementation.js';
@@ -6,9 +6,21 @@ import { Sort } from '../sort.js';
6
6
  import { ValueConverters } from '../valueConverters.js';
7
7
  import { getRepositoryInternals } from '../remult3/repository-internals.js';
8
8
  import { isOfType } from '../isOfType.js';
9
- // @dynamic
9
+ /**
10
+ * A DataProvider for Sql Databases
11
+ * @example
12
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
13
+ * @see [Connecting a Database](https://remult.dev/docs/quickstart#connecting-a-database)
14
+
15
+ */
10
16
  export class SqlDatabase {
11
17
  sql;
18
+ /**
19
+ * Gets the SQL database from the data provider.
20
+ * @param dataProvider - The data provider.
21
+ * @returns The SQL database.
22
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
23
+ */
12
24
  static getDb(dataProvider) {
13
25
  const r = (dataProvider || defaultRemult.dataProvider);
14
26
  if (isOfType(r, 'createCommand'))
@@ -16,12 +28,26 @@ export class SqlDatabase {
16
28
  else
17
29
  throw 'the data provider is not an SqlCommandFactory';
18
30
  }
31
+ /**
32
+ * Creates a new SQL command.
33
+ * @returns The SQL command.
34
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
35
+ */
19
36
  createCommand() {
20
37
  return new LogSQLCommand(this.sql.createCommand(), SqlDatabase.LogToConsole);
21
38
  }
39
+ /**
40
+ * Executes a SQL command.
41
+ * @param sql - The SQL command.
42
+ * @returns The SQL result.
43
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
44
+ */
22
45
  async execute(sql) {
23
46
  return await this.createCommand().execute(sql);
24
47
  }
48
+ /**
49
+ * Wraps an identifier with the database's identifier syntax.
50
+ */
25
51
  wrapIdentifier = (x) => x;
26
52
  /* @internal*/
27
53
  _getSourceSql() {
@@ -31,6 +57,11 @@ export class SqlDatabase {
31
57
  if (this.sql.ensureSchema)
32
58
  await this.sql.ensureSchema(entities);
33
59
  }
60
+ /**
61
+ * Gets the entity data provider.
62
+ * @param entity - The entity metadata.
63
+ * @returns The entity data provider.
64
+ */
34
65
  getEntityDataProvider(entity) {
35
66
  if (!this.sql.supportsJsonColumnType) {
36
67
  for (const f of entity.fields.toArray()) {
@@ -44,13 +75,18 @@ export class SqlDatabase {
44
75
  }
45
76
  }
46
77
  }
47
- return new ActualSQLServerDataProvider(entity, this, async (dbName) => {
78
+ return new ActualSQLEntityDataProvider(entity, this, async (dbName) => {
48
79
  if (this.createdEntities.indexOf(dbName.$entityName) < 0) {
49
80
  this.createdEntities.push(dbName.$entityName);
50
81
  await this.sql.entityIsUsedForTheFirstTime(entity);
51
82
  }
52
83
  }, this.sql);
53
84
  }
85
+ /**
86
+ * Runs a transaction. Used internally by remult when transactions are required
87
+ * @param action - The action to run in the transaction.
88
+ * @returns The promise of the transaction.
89
+ */
54
90
  transaction(action) {
55
91
  return this.sql.transaction(async (x) => {
56
92
  let completed = false;
@@ -103,12 +139,18 @@ export class SqlDatabase {
103
139
  },
104
140
  };
105
141
  }
142
+ /**
143
+ * Converts a filter to a raw SQL string.
144
+ * @see [Leveraging Database Capabilities with Raw SQL in Custom Filters](https://remult.dev/docs/running-sql-on-the-server#leveraging-entityfilter-for-sql-databases)
145
+
146
+ */
106
147
  static async filterToRaw(repo, condition, sqlCommand, dbNames, wrapIdentifier) {
107
148
  if (!sqlCommand) {
108
149
  sqlCommand = new myDummySQLCommand();
109
150
  }
110
151
  const r = getRepository(repo);
111
- var b = new FilterConsumerBridgeToSqlRequest(sqlCommand, dbNames || (await dbNamesOf(r.metadata, wrapIdentifier)));
152
+ var b = new FilterConsumerBridgeToSqlRequest(sqlCommand, dbNames ||
153
+ (await dbNamesOfWithForceSqlExpression(r.metadata, wrapIdentifier)));
112
154
  b._addWhere = false;
113
155
  await (await getRepositoryInternals(r)._translateWhereToFilter(condition)).__applyToConsumer(b);
114
156
  return await b.resolveWhere();
@@ -121,12 +163,20 @@ export class SqlDatabase {
121
163
  * `oneLiner` - to log all queries to the console as one line
122
164
  *
123
165
  * a `function` - to log all queries to the console as a custom format
166
+ * @example
167
+ * SqlDatabase.LogToConsole = (duration, query, args) => { console.log("be crazy ;)") }
124
168
  */
125
169
  static LogToConsole = false;
126
170
  /**
127
171
  * Threshold in milliseconds for logging queries to the console.
128
172
  */
129
173
  static durationThreshold = 0;
174
+ /**
175
+ * Creates a new SQL database.
176
+ * @param sql - The SQL implementation.
177
+ * @example
178
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
179
+ */
130
180
  constructor(sql) {
131
181
  this.sql = sql;
132
182
  if (sql.wrapIdentifier)
@@ -206,7 +256,7 @@ class LogSQLCommand {
206
256
  }
207
257
  }
208
258
  }
209
- class ActualSQLServerDataProvider {
259
+ class ActualSQLEntityDataProvider {
210
260
  entity;
211
261
  sql;
212
262
  iAmUsed;
@@ -219,7 +269,7 @@ class ActualSQLServerDataProvider {
219
269
  this.strategy = strategy;
220
270
  }
221
271
  async init() {
222
- let dbNameProvider = await dbNamesOf(this.entity, (x) => this.sql.wrapIdentifier(x));
272
+ let dbNameProvider = await dbNamesOfWithForceSqlExpression(this.entity, (x) => this.sql.wrapIdentifier(x));
223
273
  await this.iAmUsed(dbNameProvider);
224
274
  return dbNameProvider;
225
275
  }
@@ -190,6 +190,12 @@ export function shouldCreateEntity(entity, e) {
190
190
  e.$entityName.toLowerCase().indexOf('from ') < 0);
191
191
  }
192
192
  export async function dbNamesOf(repo, wrapIdentifierOrOptions) {
193
+ return internalDbNamesOf(repo, wrapIdentifierOrOptions);
194
+ }
195
+ export async function dbNamesOfWithForceSqlExpression(repo, wrapIdentifierOrOptions) {
196
+ return internalDbNamesOf(repo, wrapIdentifierOrOptions, true);
197
+ }
198
+ async function internalDbNamesOf(repo, wrapIdentifierOrOptions, forceSqlExpression = false) {
193
199
  let options = typeof wrapIdentifierOrOptions === 'function'
194
200
  ? { wrapIdentifier: wrapIdentifierOrOptions }
195
201
  : wrapIdentifierOrOptions || {};
@@ -213,7 +219,7 @@ export async function dbNamesOf(repo, wrapIdentifierOrOptions) {
213
219
  wrapIdentifier: options.wrapIdentifier,
214
220
  };
215
221
  for (const field of meta.fields) {
216
- let r = await fieldDbName(field, meta, options.wrapIdentifier);
222
+ let r = await fieldDbName(field, meta, options.wrapIdentifier, forceSqlExpression);
217
223
  if (!field.options.sqlExpression)
218
224
  if (typeof options.tableName === 'string')
219
225
  r = options.wrapIdentifier(options.tableName) + '.' + r;
@@ -242,19 +248,22 @@ export async function entityDbName(metadata, wrapIdentifier = (x) => x) {
242
248
  }
243
249
  return wrapIdentifier(metadata.dbName);
244
250
  }
245
- export async function fieldDbName(f, meta, wrapIdentifier = (x) => x) {
251
+ const sqlExpressionInProgressKey = Symbol.for(`sqlExpressionInProgressKey`);
252
+ export async function fieldDbName(f, meta, wrapIdentifier = (x) => x, forceSqlExpression = false) {
246
253
  try {
247
254
  if (f.options.sqlExpression) {
248
255
  let result;
249
256
  if (typeof f.options.sqlExpression === 'function') {
250
- const prev = f.options.sqlExpression;
257
+ if (f[sqlExpressionInProgressKey] && !forceSqlExpression) {
258
+ return "recursive sqlExpression call for field '" + f.key + "'. ";
259
+ }
251
260
  try {
252
- f.options.sqlExpression =
253
- "recursive sqlExpression call for field '" + f.key + "'. ";
254
- result = await prev(meta);
261
+ f[sqlExpressionInProgressKey] = true;
262
+ result = await f.options.sqlExpression(meta);
255
263
  f.options.sqlExpression = () => result;
256
264
  }
257
265
  finally {
266
+ delete f[sqlExpressionInProgressKey];
258
267
  }
259
268
  }
260
269
  else
@@ -269,7 +278,7 @@ export async function fieldDbName(f, meta, wrapIdentifier = (x) => x) {
269
278
  if (field) {
270
279
  let fInfo = meta.fields.find(field);
271
280
  if (fInfo)
272
- return fieldDbName(fInfo, meta, wrapIdentifier);
281
+ return fieldDbName(fInfo, meta, wrapIdentifier, forceSqlExpression);
273
282
  }
274
283
  return wrapIdentifier(f.dbName);
275
284
  }
@@ -1,6 +1,7 @@
1
1
  export const flags = {
2
2
  error500RetryCount: 4,
3
3
  };
4
+ //p1 - fix query docs to also explain how it can be used for infinite scroll and pagination.
4
5
  //y1 - 'test expression columns without aliases'
5
6
  //p1 - see if I can fix the no alias problem in selects
6
7
  //p1 - add luid - it's cool for order by.
@@ -8,6 +9,7 @@ export const flags = {
8
9
  //p1 - add nanoid
9
10
  //p1 - add id and use luid by default, but allow changes with Fields.id.defaultIdProvider
10
11
  //p1 - explain the benefits of changing the default provider for testing in docs.
12
+ //p1 - fix sqlite to support alter table when adding a column with ensure schema = on
11
13
  //p1 - fix app custom filters example for multiple filters.
12
14
  //p1 - add not!!!!
13
15
  //p1 - add LifecycleEvent to documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.26.18",
3
+ "version": "0.26.19-next.0",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -157,7 +157,7 @@ var KnexDataProvider = /** @class */ (function () {
157
157
  case 0:
158
158
  repo = (0, RepositoryImplementation_js_1.getRepository)(entity);
159
159
  _a = FilterConsumerBridgeToKnexRequest.bind;
160
- return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_2.dbNamesOf)(repo.metadata, function (x) { return x; })];
160
+ return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOfWithForceSqlExpression)(repo.metadata, function (x) { return x; })];
161
161
  case 1:
162
162
  b = new (_a.apply(FilterConsumerBridgeToKnexRequest, [void 0, _b.sent(), wrapIdentifier]))();
163
163
  b._addWhere = false;
@@ -310,7 +310,7 @@ var KnexEntityDataProvider = /** @class */ (function () {
310
310
  var _this = this;
311
311
  return tslib_1.__generator(this, function (_a) {
312
312
  switch (_a.label) {
313
- case 0: return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_2.dbNamesOf)(this.entity, function (x) { return x; })];
313
+ case 0: return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOfWithForceSqlExpression)(this.entity, function (x) { return x; })];
314
314
  case 1:
315
315
  r = (_a.sent());
316
316
  return [2 /*return*/, {
package/remult-mongo.js CHANGED
@@ -78,7 +78,7 @@ var MongoDataProvider = /** @class */ (function () {
78
78
  case 0:
79
79
  repo = (0, RepositoryImplementation_js_1.getRepository)(entity);
80
80
  _a = FilterConsumerBridgeToMongo.bind;
81
- return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(repo.metadata)];
81
+ return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOfWithForceSqlExpression)(repo.metadata)];
82
82
  case 1:
83
83
  b = new (_a.apply(FilterConsumerBridgeToMongo, [void 0, _b.sent()]))();
84
84
  b._addWhere = false;
@@ -4,14 +4,51 @@ import type { CustomSqlFilterBuilderFunction, EntityDbNamesBase } from '../filte
4
4
  import type { EntityFilter, EntityMetadata } from '../remult3/remult3.js';
5
5
  import type { RepositoryOverloads } from '../remult3/RepositoryImplementation.js';
6
6
  import type { CanBuildMigrations, MigrationBuilder, MigrationCode } from '../../migrations/migration-types.js';
7
+ /**
8
+ * A DataProvider for Sql Databases
9
+ * @example
10
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
11
+ * @see [Connecting a Database](https://remult.dev/docs/quickstart#connecting-a-database)
12
+
13
+ */
7
14
  export declare class SqlDatabase implements DataProvider, HasWrapIdentifier, CanBuildMigrations, SqlCommandFactory {
8
15
  private sql;
16
+ /**
17
+ * Gets the SQL database from the data provider.
18
+ * @param dataProvider - The data provider.
19
+ * @returns The SQL database.
20
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
21
+ */
9
22
  static getDb(dataProvider?: DataProvider): SqlDatabase;
23
+ /**
24
+ * Creates a new SQL command.
25
+ * @returns The SQL command.
26
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
27
+ */
10
28
  createCommand(): SqlCommand;
29
+ /**
30
+ * Executes a SQL command.
31
+ * @param sql - The SQL command.
32
+ * @returns The SQL result.
33
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
34
+ */
11
35
  execute(sql: string): Promise<SqlResult>;
36
+ /**
37
+ * Wraps an identifier with the database's identifier syntax.
38
+ */
12
39
  wrapIdentifier: (name: string) => string;
13
40
  ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
41
+ /**
42
+ * Gets the entity data provider.
43
+ * @param entity - The entity metadata.
44
+ * @returns The entity data provider.
45
+ */
14
46
  getEntityDataProvider(entity: EntityMetadata): EntityDataProvider;
47
+ /**
48
+ * Runs a transaction. Used internally by remult when transactions are required
49
+ * @param action - The action to run in the transaction.
50
+ * @returns The promise of the transaction.
51
+ */
15
52
  transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
16
53
  /**
17
54
  * Creates a raw filter for entity filtering.
@@ -24,6 +61,11 @@ export declare class SqlDatabase implements DataProvider, HasWrapIdentifier, Can
24
61
  * @see [Leveraging Database Capabilities with Raw SQL in Custom Filters](https://remult.dev/docs/custom-filter.html#leveraging-database-capabilities-with-raw-sql-in-custom-filters)
25
62
  */
26
63
  static rawFilter(build: CustomSqlFilterBuilderFunction): EntityFilter<any>;
64
+ /**
65
+ * Converts a filter to a raw SQL string.
66
+ * @see [Leveraging Database Capabilities with Raw SQL in Custom Filters](https://remult.dev/docs/running-sql-on-the-server#leveraging-entityfilter-for-sql-databases)
67
+
68
+ */
27
69
  static filterToRaw<entityType>(repo: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>, sqlCommand?: SqlCommandWithParameters, dbNames?: EntityDbNamesBase, wrapIdentifier?: (name: string) => string): Promise<string>;
28
70
  /**
29
71
  * `false` _(default)_ - No logging
@@ -33,12 +75,20 @@ export declare class SqlDatabase implements DataProvider, HasWrapIdentifier, Can
33
75
  * `oneLiner` - to log all queries to the console as one line
34
76
  *
35
77
  * a `function` - to log all queries to the console as a custom format
78
+ * @example
79
+ * SqlDatabase.LogToConsole = (duration, query, args) => { console.log("be crazy ;)") }
36
80
  */
37
81
  static LogToConsole: boolean | 'oneLiner' | ((duration: number, query: string, args: Record<string, any>) => void);
38
82
  /**
39
83
  * Threshold in milliseconds for logging queries to the console.
40
84
  */
41
85
  static durationThreshold: number;
86
+ /**
87
+ * Creates a new SQL database.
88
+ * @param sql - The SQL implementation.
89
+ * @example
90
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
91
+ */
42
92
  constructor(sql: SqlImplementation);
43
93
  provideMigrationBuilder: (builder: MigrationCode) => MigrationBuilder;
44
94
  private createdEntities;
@@ -10,10 +10,25 @@ var sort_js_1 = require("../sort.js");
10
10
  var valueConverters_js_1 = require("../valueConverters.js");
11
11
  var repository_internals_js_1 = require("../remult3/repository-internals.js");
12
12
  var isOfType_js_1 = require("../isOfType.js");
13
- // @dynamic
13
+ /**
14
+ * A DataProvider for Sql Databases
15
+ * @example
16
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
17
+ * @see [Connecting a Database](https://remult.dev/docs/quickstart#connecting-a-database)
18
+
19
+ */
14
20
  var SqlDatabase = /** @class */ (function () {
21
+ /**
22
+ * Creates a new SQL database.
23
+ * @param sql - The SQL implementation.
24
+ * @example
25
+ * const db = new SqlDatabase(new PostgresDataProvider(pgPool))
26
+ */
15
27
  function SqlDatabase(sql) {
16
28
  this.sql = sql;
29
+ /**
30
+ * Wraps an identifier with the database's identifier syntax.
31
+ */
17
32
  this.wrapIdentifier = function (x) { return x; };
18
33
  this.createdEntities = [];
19
34
  if (sql.wrapIdentifier)
@@ -24,6 +39,12 @@ var SqlDatabase = /** @class */ (function () {
24
39
  if ((0, isOfType_js_1.isOfType)(sql, 'end'))
25
40
  this.end = function () { return sql.end(); };
26
41
  }
42
+ /**
43
+ * Gets the SQL database from the data provider.
44
+ * @param dataProvider - The data provider.
45
+ * @returns The SQL database.
46
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
47
+ */
27
48
  SqlDatabase.getDb = function (dataProvider) {
28
49
  var r = (dataProvider || remult_proxy_js_1.remult.dataProvider);
29
50
  if ((0, isOfType_js_1.isOfType)(r, 'createCommand'))
@@ -31,9 +52,20 @@ var SqlDatabase = /** @class */ (function () {
31
52
  else
32
53
  throw 'the data provider is not an SqlCommandFactory';
33
54
  };
55
+ /**
56
+ * Creates a new SQL command.
57
+ * @returns The SQL command.
58
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
59
+ */
34
60
  SqlDatabase.prototype.createCommand = function () {
35
61
  return new LogSQLCommand(this.sql.createCommand(), SqlDatabase.LogToConsole);
36
62
  };
63
+ /**
64
+ * Executes a SQL command.
65
+ * @param sql - The SQL command.
66
+ * @returns The SQL result.
67
+ * @see [Direct Database Access](https://remult.dev/docs/running-sql-on-the-server)
68
+ */
37
69
  SqlDatabase.prototype.execute = function (sql) {
38
70
  return tslib_1.__awaiter(this, void 0, void 0, function () {
39
71
  return tslib_1.__generator(this, function (_a) {
@@ -63,6 +95,11 @@ var SqlDatabase = /** @class */ (function () {
63
95
  });
64
96
  });
65
97
  };
98
+ /**
99
+ * Gets the entity data provider.
100
+ * @param entity - The entity metadata.
101
+ * @returns The entity data provider.
102
+ */
66
103
  SqlDatabase.prototype.getEntityDataProvider = function (entity) {
67
104
  var e_1, _a;
68
105
  var _this = this;
@@ -84,7 +121,7 @@ var SqlDatabase = /** @class */ (function () {
84
121
  finally { if (e_1) throw e_1.error; }
85
122
  }
86
123
  }
87
- return new ActualSQLServerDataProvider(entity, this, function (dbName) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
124
+ return new ActualSQLEntityDataProvider(entity, this, function (dbName) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
88
125
  return tslib_1.__generator(this, function (_a) {
89
126
  switch (_a.label) {
90
127
  case 0:
@@ -99,6 +136,11 @@ var SqlDatabase = /** @class */ (function () {
99
136
  });
100
137
  }); }, this.sql);
101
138
  };
139
+ /**
140
+ * Runs a transaction. Used internally by remult when transactions are required
141
+ * @param action - The action to run in the transaction.
142
+ * @returns The promise of the transaction.
143
+ */
102
144
  SqlDatabase.prototype.transaction = function (action) {
103
145
  var _this = this;
104
146
  return this.sql.transaction(function (x) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
@@ -169,6 +211,11 @@ var SqlDatabase = /** @class */ (function () {
169
211
  },
170
212
  _a;
171
213
  };
214
+ /**
215
+ * Converts a filter to a raw SQL string.
216
+ * @see [Leveraging Database Capabilities with Raw SQL in Custom Filters](https://remult.dev/docs/running-sql-on-the-server#leveraging-entityfilter-for-sql-databases)
217
+
218
+ */
172
219
  SqlDatabase.filterToRaw = function (repo, condition, sqlCommand, dbNames, wrapIdentifier) {
173
220
  return tslib_1.__awaiter(this, void 0, void 0, function () {
174
221
  var r, b, _a, _b, _c;
@@ -183,7 +230,7 @@ var SqlDatabase = /** @class */ (function () {
183
230
  _b = [void 0, sqlCommand];
184
231
  _c = dbNames;
185
232
  if (_c) return [3 /*break*/, 2];
186
- return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(r.metadata, wrapIdentifier)];
233
+ return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOfWithForceSqlExpression)(r.metadata, wrapIdentifier)];
187
234
  case 1:
188
235
  _c = (_d.sent());
189
236
  _d.label = 2;
@@ -208,6 +255,8 @@ var SqlDatabase = /** @class */ (function () {
208
255
  * `oneLiner` - to log all queries to the console as one line
209
256
  *
210
257
  * a `function` - to log all queries to the console as a custom format
258
+ * @example
259
+ * SqlDatabase.LogToConsole = (duration, query, args) => { console.log("be crazy ;)") }
211
260
  */
212
261
  SqlDatabase.LogToConsole = false;
213
262
  /**
@@ -291,20 +340,20 @@ var LogSQLCommand = /** @class */ (function () {
291
340
  };
292
341
  return LogSQLCommand;
293
342
  }());
294
- var ActualSQLServerDataProvider = /** @class */ (function () {
295
- function ActualSQLServerDataProvider(entity, sql, iAmUsed, strategy) {
343
+ var ActualSQLEntityDataProvider = /** @class */ (function () {
344
+ function ActualSQLEntityDataProvider(entity, sql, iAmUsed, strategy) {
296
345
  this.entity = entity;
297
346
  this.sql = sql;
298
347
  this.iAmUsed = iAmUsed;
299
348
  this.strategy = strategy;
300
349
  }
301
- ActualSQLServerDataProvider.prototype.init = function () {
350
+ ActualSQLEntityDataProvider.prototype.init = function () {
302
351
  return tslib_1.__awaiter(this, void 0, void 0, function () {
303
352
  var dbNameProvider;
304
353
  var _this = this;
305
354
  return tslib_1.__generator(this, function (_a) {
306
355
  switch (_a.label) {
307
- case 0: return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(this.entity, function (x) {
356
+ case 0: return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOfWithForceSqlExpression)(this.entity, function (x) {
308
357
  return _this.sql.wrapIdentifier(x);
309
358
  })];
310
359
  case 1:
@@ -317,7 +366,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
317
366
  });
318
367
  });
319
368
  };
320
- ActualSQLServerDataProvider.prototype.count = function (where) {
369
+ ActualSQLEntityDataProvider.prototype.count = function (where) {
321
370
  return tslib_1.__awaiter(this, void 0, void 0, function () {
322
371
  var e, select, r, wc, _a;
323
372
  return tslib_1.__generator(this, function (_b) {
@@ -342,7 +391,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
342
391
  });
343
392
  });
344
393
  };
345
- ActualSQLServerDataProvider.prototype.find = function (options) {
394
+ ActualSQLEntityDataProvider.prototype.find = function (options) {
346
395
  return tslib_1.__awaiter(this, void 0, void 0, function () {
347
396
  var e, _a, colKeys, select, r, where, _b, first, segs, _c, _d, s, segs_1, segs_1_1, c, page;
348
397
  var e_2, _e, e_3, _f;
@@ -436,7 +485,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
436
485
  });
437
486
  });
438
487
  };
439
- ActualSQLServerDataProvider.prototype.buildResultRow = function (colKeys, y, r) {
488
+ ActualSQLEntityDataProvider.prototype.buildResultRow = function (colKeys, y, r) {
440
489
  var result = {};
441
490
  for (var index = 0; index < colKeys.length; index++) {
442
491
  var col = colKeys[index];
@@ -449,7 +498,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
449
498
  }
450
499
  return result;
451
500
  };
452
- ActualSQLServerDataProvider.prototype.buildSelect = function (e) {
501
+ ActualSQLEntityDataProvider.prototype.buildSelect = function (e) {
453
502
  var e_4, _a;
454
503
  var select = '';
455
504
  var colKeys = [];
@@ -477,7 +526,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
477
526
  }
478
527
  return { colKeys: colKeys, select: select };
479
528
  };
480
- ActualSQLServerDataProvider.prototype.update = function (id, data) {
529
+ ActualSQLEntityDataProvider.prototype.update = function (id, data) {
481
530
  return tslib_1.__awaiter(this, void 0, void 0, function () {
482
531
  var e, r, statement, added, _a, _b, x, v, idFilter, f, _c, _d, colKeys, select, returning;
483
532
  var e_5, _e;
@@ -547,7 +596,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
547
596
  });
548
597
  });
549
598
  };
550
- ActualSQLServerDataProvider.prototype.delete = function (id) {
599
+ ActualSQLEntityDataProvider.prototype.delete = function (id) {
551
600
  return tslib_1.__awaiter(this, void 0, void 0, function () {
552
601
  var e, r, f, statement, _a;
553
602
  var _this = this;
@@ -572,7 +621,7 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
572
621
  });
573
622
  });
574
623
  };
575
- ActualSQLServerDataProvider.prototype.insert = function (data) {
624
+ ActualSQLEntityDataProvider.prototype.insert = function (data) {
576
625
  return tslib_1.__awaiter(this, void 0, void 0, function () {
577
626
  var e, r, cols, vals, added, _a, _b, x, v, statement, _c, colKeys, select;
578
627
  var e_6, _d;
@@ -643,8 +692,8 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
643
692
  });
644
693
  });
645
694
  };
646
- ActualSQLServerDataProvider.LogToConsole = false;
647
- return ActualSQLServerDataProvider;
695
+ ActualSQLEntityDataProvider.LogToConsole = false;
696
+ return ActualSQLEntityDataProvider;
648
697
  }());
649
698
  var myDummySQLCommand = /** @class */ (function () {
650
699
  function myDummySQLCommand() {
@@ -80,5 +80,6 @@ export interface dbNamesOfOptions {
80
80
  tableName?: boolean | string;
81
81
  }
82
82
  export declare function dbNamesOf<entityType>(repo: EntityMetadataOverloads<entityType>, wrapIdentifierOrOptions?: ((name: string) => string) | dbNamesOfOptions): Promise<EntityDbNames<entityType>>;
83
+ export declare function dbNamesOfWithForceSqlExpression<entityType>(repo: EntityMetadataOverloads<entityType>, wrapIdentifierOrOptions?: ((name: string) => string) | dbNamesOfOptions): Promise<EntityDbNames<entityType>>;
83
84
  export declare function entityDbName(metadata: EntityMetadata, wrapIdentifier?: (name: string) => string): Promise<string>;
84
- export declare function fieldDbName(f: FieldMetadata, meta: EntityMetadata, wrapIdentifier?: (name: string) => string): Promise<string>;
85
+ export declare function fieldDbName(f: FieldMetadata, meta: EntityMetadata, wrapIdentifier?: (name: string) => string, forceSqlExpression?: boolean): Promise<string>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fieldDbName = exports.entityDbName = exports.dbNamesOf = exports.shouldCreateEntity = exports.shouldNotCreateField = exports.isDbReadonly = exports.CustomSqlFilterBuilder = exports.FilterConsumerBridgeToSqlRequest = void 0;
3
+ exports.fieldDbName = exports.entityDbName = exports.dbNamesOfWithForceSqlExpression = exports.dbNamesOf = exports.shouldCreateEntity = exports.shouldNotCreateField = exports.isDbReadonly = exports.CustomSqlFilterBuilder = exports.FilterConsumerBridgeToSqlRequest = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var sql_database_js_1 = require("../data-providers/sql-database.js");
6
6
  var remult_proxy_js_1 = require("../remult-proxy.js");
@@ -297,6 +297,23 @@ function shouldCreateEntity(entity, e) {
297
297
  }
298
298
  exports.shouldCreateEntity = shouldCreateEntity;
299
299
  function dbNamesOf(repo, wrapIdentifierOrOptions) {
300
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
301
+ return tslib_1.__generator(this, function (_a) {
302
+ return [2 /*return*/, internalDbNamesOf(repo, wrapIdentifierOrOptions)];
303
+ });
304
+ });
305
+ }
306
+ exports.dbNamesOf = dbNamesOf;
307
+ function dbNamesOfWithForceSqlExpression(repo, wrapIdentifierOrOptions) {
308
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
309
+ return tslib_1.__generator(this, function (_a) {
310
+ return [2 /*return*/, internalDbNamesOf(repo, wrapIdentifierOrOptions, true)];
311
+ });
312
+ });
313
+ }
314
+ exports.dbNamesOfWithForceSqlExpression = dbNamesOfWithForceSqlExpression;
315
+ function internalDbNamesOf(repo, wrapIdentifierOrOptions, forceSqlExpression) {
316
+ if (forceSqlExpression === void 0) { forceSqlExpression = false; }
300
317
  return tslib_1.__awaiter(this, void 0, void 0, function () {
301
318
  var options, meta, result, _a, _b, field, r, e_3_1;
302
319
  var _c, e_3, _d;
@@ -335,7 +352,7 @@ function dbNamesOf(repo, wrapIdentifierOrOptions) {
335
352
  case 3:
336
353
  if (!!_b.done) return [3 /*break*/, 6];
337
354
  field = _b.value;
338
- return [4 /*yield*/, fieldDbName(field, meta, options.wrapIdentifier)];
355
+ return [4 /*yield*/, fieldDbName(field, meta, options.wrapIdentifier, forceSqlExpression)];
339
356
  case 4:
340
357
  r = _e.sent();
341
358
  if (!field.options.sqlExpression)
@@ -365,7 +382,6 @@ function dbNamesOf(repo, wrapIdentifierOrOptions) {
365
382
  });
366
383
  });
367
384
  }
368
- exports.dbNamesOf = dbNamesOf;
369
385
  function entityDbName(metadata, wrapIdentifier) {
370
386
  if (wrapIdentifier === void 0) { wrapIdentifier = function (x) { return x; }; }
371
387
  return tslib_1.__awaiter(this, void 0, void 0, function () {
@@ -395,28 +411,33 @@ function entityDbName(metadata, wrapIdentifier) {
395
411
  });
396
412
  }
397
413
  exports.entityDbName = entityDbName;
398
- function fieldDbName(f, meta, wrapIdentifier) {
414
+ var sqlExpressionInProgressKey = Symbol.for("sqlExpressionInProgressKey");
415
+ function fieldDbName(f, meta, wrapIdentifier, forceSqlExpression) {
399
416
  if (wrapIdentifier === void 0) { wrapIdentifier = function (x) { return x; }; }
417
+ if (forceSqlExpression === void 0) { forceSqlExpression = false; }
400
418
  return tslib_1.__awaiter(this, void 0, void 0, function () {
401
- var result_1, prev, rel, field, fInfo;
419
+ var result_1, rel, field, fInfo;
402
420
  return tslib_1.__generator(this, function (_a) {
403
421
  switch (_a.label) {
404
422
  case 0:
405
423
  _a.trys.push([0, , 8, 9]);
406
424
  if (!f.options.sqlExpression) return [3 /*break*/, 7];
407
425
  if (!(typeof f.options.sqlExpression === 'function')) return [3 /*break*/, 5];
408
- prev = f.options.sqlExpression;
426
+ if (f[sqlExpressionInProgressKey] && !forceSqlExpression) {
427
+ return [2 /*return*/, "recursive sqlExpression call for field '" + f.key + "'. "];
428
+ }
409
429
  _a.label = 1;
410
430
  case 1:
411
431
  _a.trys.push([1, , 3, 4]);
412
- f.options.sqlExpression =
413
- "recursive sqlExpression call for field '" + f.key + "'. ";
414
- return [4 /*yield*/, prev(meta)];
432
+ f[sqlExpressionInProgressKey] = true;
433
+ return [4 /*yield*/, f.options.sqlExpression(meta)];
415
434
  case 2:
416
435
  result_1 = _a.sent();
417
436
  f.options.sqlExpression = function () { return result_1; };
418
437
  return [3 /*break*/, 4];
419
- case 3: return [7 /*endfinally*/];
438
+ case 3:
439
+ delete f[sqlExpressionInProgressKey];
440
+ return [7 /*endfinally*/];
420
441
  case 4: return [3 /*break*/, 6];
421
442
  case 5:
422
443
  result_1 = f.options.sqlExpression;
@@ -432,7 +453,7 @@ function fieldDbName(f, meta, wrapIdentifier) {
432
453
  if (field) {
433
454
  fInfo = meta.fields.find(field);
434
455
  if (fInfo)
435
- return [2 /*return*/, fieldDbName(fInfo, meta, wrapIdentifier)];
456
+ return [2 /*return*/, fieldDbName(fInfo, meta, wrapIdentifier, forceSqlExpression)];
436
457
  }
437
458
  return [2 /*return*/, wrapIdentifier(f.dbName)];
438
459
  case 8: return [7 /*endfinally*/];
@@ -285,6 +285,19 @@ export interface Repository<entityType> {
285
285
  * for await (const task of taskRepo.query()) {
286
286
  * // do something.
287
287
  * }
288
+ * @example
289
+ * const query = taskRepo.query({
290
+ * where: { completed: false },
291
+ * pageSize: 100,
292
+ * })
293
+ * const count = await query.count()
294
+ * console.log('Paged: ' + count / 100)
295
+ * let paginator = await query.paginator()
296
+ * console.log(paginator.items.length)
297
+ * if (paginator.hasNextPage) {
298
+ * paginator = await paginator.nextPage()
299
+ * console.log(paginator.items.length)
300
+ * }
288
301
  * */
289
302
  query(options?: QueryOptions<entityType>): QueryResult<entityType>;
290
303
  /** Returns a count of the items matching the criteria.
@@ -596,7 +609,22 @@ export interface QueryResult<entityType> {
596
609
  /** Performs an operation on all the items matching the query criteria */
597
610
  forEach(what: (item: entityType) => Promise<any>): Promise<number>;
598
611
  }
599
- /** An interface used to paginating using the `query` method in the `Repository` object */
612
+ /** An interface used to paginating using the `query` method in the `Repository` object
613
+ * @example
614
+ * @example
615
+ * const query = taskRepo.query({
616
+ * where: { completed: false },
617
+ * pageSize: 100,
618
+ * })
619
+ * const count = await query.count()
620
+ * console.log('Paged: ' + count / 100)
621
+ * let paginator = await query.paginator()
622
+ * console.log(paginator.items.length)
623
+ * if (paginator.hasNextPage) {
624
+ * paginator = await paginator.nextPage()
625
+ * console.log(paginator.items.length)
626
+ * }
627
+ */
600
628
  export interface Paginator<entityType> {
601
629
  /** the items in the current page */
602
630
  items: entityType[];
@@ -4,6 +4,7 @@ exports.flags = void 0;
4
4
  exports.flags = {
5
5
  error500RetryCount: 4,
6
6
  };
7
+ //p1 - fix query docs to also explain how it can be used for infinite scroll and pagination.
7
8
  //y1 - 'test expression columns without aliases'
8
9
  //p1 - see if I can fix the no alias problem in selects
9
10
  //p1 - add luid - it's cool for order by.
@@ -11,6 +12,7 @@ exports.flags = {
11
12
  //p1 - add nanoid
12
13
  //p1 - add id and use luid by default, but allow changes with Fields.id.defaultIdProvider
13
14
  //p1 - explain the benefits of changing the default provider for testing in docs.
15
+ //p1 - fix sqlite to support alter table when adding a column with ensure schema = on
14
16
  //p1 - fix app custom filters example for multiple filters.
15
17
  //p1 - add not!!!!
16
18
  //p1 - add LifecycleEvent to documentation