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.
- package/README.md +194 -129
- package/esm/graphql.js +131 -59
- package/esm/index.js +1 -1
- package/esm/migrations/compare-migration-snapshots.js +61 -0
- package/esm/migrations/generate-migrations.js +68 -0
- package/esm/migrations/index.js +2 -0
- package/esm/migrations/migrate.js +90 -0
- package/esm/migrations/migration-types.js +36 -0
- package/esm/migrations/update-migrations-ts-file.js +115 -0
- package/esm/postgres/postgres-data-provider.js +24 -3
- package/esm/postgres/schema-builder.js +35 -26
- package/esm/remult-better-sqlite3.js +47 -0
- package/esm/remult-bun-sqlite.js +41 -0
- package/esm/remult-knex/index.js +180 -51
- package/esm/remult-mongo.js +2 -2
- package/esm/remult-sql-js.js +3 -78
- package/esm/remult-sqlite-core.js +104 -0
- package/esm/server/expressBridge.js +130 -29
- package/esm/server/initAsyncHooks.js +75 -1
- package/esm/src/CompoundIdField.js +8 -2
- package/esm/src/context.js +20 -24
- package/esm/src/data-api.js +71 -30
- package/esm/src/data-providers/rest-data-provider.js +17 -15
- package/esm/src/data-providers/sql-database.js +32 -7
- package/esm/src/data-providers/web-sql-data-provider.js +1 -9
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +37 -11
- package/esm/src/filter/filter-interfaces.js +229 -17
- package/esm/src/isOfType.js +9 -0
- package/esm/src/remult3/Fields.js +70 -18
- package/esm/src/remult3/RepositoryImplementation.js +47 -21
- package/esm/src/remult3/addValidator.js +15 -0
- package/esm/src/remult3/remult3.js +28 -57
- package/esm/src/server-action.js +4 -4
- package/esm/src/validators.js +6 -3
- package/esm/src/valueConverters.js +1 -1
- package/graphql.js +156 -71
- package/index.d.ts +4 -4
- package/index.js +2 -1
- package/migrations/compare-migration-snapshots.d.ts +27 -0
- package/migrations/compare-migration-snapshots.js +165 -0
- package/migrations/generate-migrations.d.ts +21 -0
- package/migrations/generate-migrations.js +104 -0
- package/migrations/index.d.ts +3 -0
- package/migrations/index.js +7 -0
- package/migrations/migrate.d.ts +27 -0
- package/migrations/migrate.js +175 -0
- package/migrations/migration-types.d.ts +48 -0
- package/migrations/migration-types.js +88 -0
- package/migrations/update-migrations-ts-file.d.ts +1 -0
- package/migrations/update-migrations-ts-file.js +141 -0
- package/package.json +21 -1
- package/postgres/postgres-data-provider.d.ts +8 -3
- package/postgres/postgres-data-provider.js +46 -3
- package/postgres/schema-builder.js +81 -48
- package/remult-better-sqlite3.d.ts +12 -0
- package/remult-better-sqlite3.js +64 -0
- package/remult-bun-sqlite.d.ts +11 -0
- package/remult-bun-sqlite.js +56 -0
- package/remult-knex/index.d.ts +12 -5
- package/remult-knex/index.js +257 -90
- package/remult-mongo.d.ts +2 -2
- package/remult-mongo.js +2 -2
- package/remult-sql-js.d.ts +2 -15
- package/remult-sql-js.js +11 -152
- package/remult-sqlite-core.d.ts +21 -0
- package/remult-sqlite-core.js +217 -0
- package/server/expressBridge.d.ts +30 -1
- package/server/expressBridge.js +140 -32
- package/server/initAsyncHooks.d.ts +16 -0
- package/server/initAsyncHooks.js +128 -2
- package/src/CompoundIdField.js +8 -2
- package/src/column-interfaces.d.ts +9 -3
- package/src/context.d.ts +8 -6
- package/src/context.js +27 -36
- package/src/data-api.d.ts +13 -9
- package/src/data-api.js +184 -135
- package/src/data-providers/rest-data-provider.js +26 -15
- package/src/data-providers/sql-database.d.ts +17 -5
- package/src/data-providers/sql-database.js +31 -7
- package/src/data-providers/web-sql-data-provider.d.ts +1 -2
- package/src/data-providers/web-sql-data-provider.js +4 -8
- package/src/entity.d.ts +64 -6
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +31 -7
- package/src/filter/filter-consumer-bridge-to-sql-request.js +46 -21
- package/src/filter/filter-interfaces.d.ts +106 -39
- package/src/filter/filter-interfaces.js +312 -32
- package/src/isOfType.d.ts +2 -0
- package/src/isOfType.js +14 -0
- package/src/remult3/Fields.d.ts +36 -0
- package/src/remult3/Fields.js +81 -19
- package/src/remult3/RepositoryImplementation.d.ts +7 -3
- package/src/remult3/RepositoryImplementation.js +106 -71
- package/src/remult3/addValidator.d.ts +2 -0
- package/src/remult3/addValidator.js +20 -0
- package/src/remult3/remult3.d.ts +6 -2
- package/src/remult3/remult3.js +28 -57
- package/src/server-action.d.ts +1 -1
- package/src/server-action.js +5 -4
- package/src/sql-command.d.ts +6 -1
- package/src/validators.d.ts +1 -0
- package/src/validators.js +10 -4
- package/src/valueConverters.js +1 -1
|
@@ -10,6 +10,7 @@ var RepositoryImplementation_js_1 = require("../remult3/RepositoryImplementation
|
|
|
10
10
|
var sort_js_1 = require("../sort.js");
|
|
11
11
|
var valueConverters_js_1 = require("../valueConverters.js");
|
|
12
12
|
var repository_internals_js_1 = require("../remult3/repository-internals.js");
|
|
13
|
+
var isOfType_js_1 = require("../isOfType.js");
|
|
13
14
|
// @dynamic
|
|
14
15
|
var SqlDatabase = /** @class */ (function () {
|
|
15
16
|
function SqlDatabase(sql) {
|
|
@@ -18,12 +19,18 @@ var SqlDatabase = /** @class */ (function () {
|
|
|
18
19
|
this.createdEntities = [];
|
|
19
20
|
if (sql.wrapIdentifier)
|
|
20
21
|
this.wrapIdentifier = function (x) { return sql.wrapIdentifier(x); };
|
|
22
|
+
if ((0, isOfType_js_1.isOfType)(sql, 'provideMigrationBuilder')) {
|
|
23
|
+
this.provideMigrationBuilder = function (x) { return sql.provideMigrationBuilder(x); };
|
|
24
|
+
}
|
|
25
|
+
if ((0, isOfType_js_1.isOfType)(sql, 'end'))
|
|
26
|
+
this.end = function () { return sql.end(); };
|
|
21
27
|
}
|
|
22
|
-
SqlDatabase.getDb = function (
|
|
23
|
-
var r = (
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
SqlDatabase.getDb = function (dataProvider) {
|
|
29
|
+
var r = (dataProvider || remult_proxy_js_1.remult.dataProvider);
|
|
30
|
+
if ((0, isOfType_js_1.isOfType)(r, 'createCommand'))
|
|
31
|
+
return r;
|
|
32
|
+
else
|
|
33
|
+
throw 'the data provider is not an SqlCommandFactory';
|
|
27
34
|
};
|
|
28
35
|
SqlDatabase.prototype.createCommand = function () {
|
|
29
36
|
return new LogSQLCommand(this.sql.createCommand(), SqlDatabase.LogToConsole);
|
|
@@ -129,6 +136,7 @@ var SqlDatabase = /** @class */ (function () {
|
|
|
129
136
|
transaction: function (z) { return x.transaction(z); },
|
|
130
137
|
supportsJsonColumnType: this.sql.supportsJsonColumnType,
|
|
131
138
|
wrapIdentifier: this.wrapIdentifier,
|
|
139
|
+
end: this.end,
|
|
132
140
|
}))];
|
|
133
141
|
case 2:
|
|
134
142
|
_a.sent();
|
|
@@ -141,6 +149,16 @@ var SqlDatabase = /** @class */ (function () {
|
|
|
141
149
|
});
|
|
142
150
|
}); });
|
|
143
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Creates a raw filter for entity filtering.
|
|
154
|
+
* @param {CustomSqlFilterBuilderFunction} build - The custom SQL filter builder function.
|
|
155
|
+
* @returns {EntityFilter<any>} - The entity filter with a custom SQL filter.
|
|
156
|
+
* @example
|
|
157
|
+
* SqlDatabase.rawFilter(({param}) =>
|
|
158
|
+
`"customerId" in (select id from customers where city = ${param(customerCity)})`
|
|
159
|
+
)
|
|
160
|
+
* @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)
|
|
161
|
+
*/
|
|
144
162
|
SqlDatabase.rawFilter = function (build) {
|
|
145
163
|
var _a;
|
|
146
164
|
return _a = {},
|
|
@@ -149,7 +167,8 @@ var SqlDatabase = /** @class */ (function () {
|
|
|
149
167
|
},
|
|
150
168
|
_a;
|
|
151
169
|
};
|
|
152
|
-
SqlDatabase.filterToRaw = function (repo, condition, sqlCommand, dbNames) {
|
|
170
|
+
SqlDatabase.filterToRaw = function (repo, condition, sqlCommand, dbNames, wrapIdentifier) {
|
|
171
|
+
if (wrapIdentifier === void 0) { wrapIdentifier = function (x) { return x; }; }
|
|
153
172
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
154
173
|
var r, b, _a, _b, _c;
|
|
155
174
|
return tslib_1.__generator(this, function (_d) {
|
|
@@ -163,7 +182,7 @@ var SqlDatabase = /** @class */ (function () {
|
|
|
163
182
|
_b = [void 0, sqlCommand];
|
|
164
183
|
_c = dbNames;
|
|
165
184
|
if (_c) return [3 /*break*/, 2];
|
|
166
|
-
return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(r.metadata)];
|
|
185
|
+
return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(r.metadata, wrapIdentifier)];
|
|
167
186
|
case 1:
|
|
168
187
|
_c = (_d.sent());
|
|
169
188
|
_d.label = 2;
|
|
@@ -515,6 +534,11 @@ var ActualSQLServerDataProvider = /** @class */ (function () {
|
|
|
515
534
|
return [2 /*return*/, r.execute(statement).then(function (sqlResult) {
|
|
516
535
|
var _a, _b;
|
|
517
536
|
(_b = (_a = _this.sql._getSourceSql()).afterMutation) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
537
|
+
if (sqlResult.rows.length != 1)
|
|
538
|
+
throw new Error('Failed to update row with id ' +
|
|
539
|
+
id +
|
|
540
|
+
', rows updated: ' +
|
|
541
|
+
sqlResult.rows.length);
|
|
518
542
|
return _this.buildResultRow(colKeys, sqlResult.rows[0], sqlResult);
|
|
519
543
|
})];
|
|
520
544
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { __RowsOfDataForTesting } from '../__RowsOfDataForTesting.js';
|
|
2
2
|
import type { SqlCommand, SqlImplementation } from '../sql-command.js';
|
|
3
|
-
import type { Remult } from '../context.js';
|
|
4
3
|
import type { EntityMetadata } from '../remult3/remult3.js';
|
|
5
4
|
export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDataForTesting {
|
|
6
5
|
private databaseName;
|
|
@@ -8,7 +7,7 @@ export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDa
|
|
|
8
7
|
[tableName: string]: any;
|
|
9
8
|
};
|
|
10
9
|
constructor(databaseName: string, databaseSize?: number);
|
|
11
|
-
|
|
10
|
+
end(): Promise<void>;
|
|
12
11
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
13
12
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
14
13
|
ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
|
|
@@ -13,14 +13,10 @@ var WebSqlDataProvider = /** @class */ (function () {
|
|
|
13
13
|
//@ts-ignore
|
|
14
14
|
this.db = window.openDatabase(databaseName, '1.0', databaseName, databaseSize);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!me.db) {
|
|
21
|
-
throw 'the data provider is not a WebSqlDataProvider';
|
|
22
|
-
}
|
|
23
|
-
return me.db;
|
|
16
|
+
WebSqlDataProvider.prototype.end = function () {
|
|
17
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
|
|
18
|
+
return [2 /*return*/];
|
|
19
|
+
}); });
|
|
24
20
|
};
|
|
25
21
|
WebSqlDataProvider.prototype.getLimitSqlSyntax = function (limit, offset) {
|
|
26
22
|
return ' limit ' + limit + ' offset ' + offset;
|
package/src/entity.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Allowed, AllowedForInstance } from './context.js';
|
|
2
2
|
import type { FieldMetadata } from './column-interfaces.js';
|
|
3
3
|
import type { EntityFilter, EntityIdFields, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata, LifecycleEvent } from './remult3/remult3.js';
|
|
4
|
+
import type { FilterPreciseValues } from './filter/filter-interfaces.js';
|
|
4
5
|
export interface EntityOptions<entityType = any> {
|
|
5
6
|
/**A human readable name for the entity */
|
|
6
7
|
caption?: string;
|
|
@@ -24,18 +25,57 @@ export interface EntityOptions<entityType = any> {
|
|
|
24
25
|
allowApiInsert?: AllowedForInstance<entityType>;
|
|
25
26
|
/** sets the `allowApiUpdate`, `allowApiDelete` and `allowApiInsert` properties in a single set */
|
|
26
27
|
allowApiCrud?: Allowed;
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
/**
|
|
29
|
+
* An optional filter that determines which rows can be queried using the API.
|
|
30
|
+
* This filter is applied to all CRUD operations to ensure that only authorized data is accessible.
|
|
31
|
+
*
|
|
32
|
+
* Use `apiPrefilter` to restrict data based on user profile or other conditions.
|
|
33
|
+
*
|
|
30
34
|
* @example
|
|
31
|
-
*
|
|
35
|
+
* // Only include non-archived items in API responses
|
|
36
|
+
* apiPrefilter: { archive: false }
|
|
32
37
|
*
|
|
33
38
|
* @example
|
|
34
|
-
*
|
|
35
|
-
*
|
|
39
|
+
* // Allow admins to access all rows, but restrict non-admins to non-archived items
|
|
40
|
+
* apiPrefilter: () => remult.isAllowed("admin") ? {} : { archive: false }
|
|
36
41
|
*
|
|
42
|
+
* @see [EntityFilter](https://remult.dev/docs/access-control.html#filtering-accessible-rows)
|
|
37
43
|
*/
|
|
38
44
|
apiPrefilter?: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>);
|
|
45
|
+
/**
|
|
46
|
+
* An optional function that allows for preprocessing or modifying the EntityFilter for a specific entity type
|
|
47
|
+
* before it is used in API CRUD operations. This function can be used to enforce additional access control
|
|
48
|
+
* rules or adjust the filter based on the current context or specific request.
|
|
49
|
+
*
|
|
50
|
+
* @template entityType The type of the entity being filtered.
|
|
51
|
+
* @param filter The initial EntityFilter for the entity type.
|
|
52
|
+
* @param event Additional information and utilities for preprocessing the filter.
|
|
53
|
+
* @returns The modified EntityFilter or a Promise that resolves to the modified EntityFilter.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* @Entity<Task>("tasks", {
|
|
58
|
+
* apiPreprocessFilter: async (filter, { getPreciseValues }) => {
|
|
59
|
+
* // Ensure that users can only query tasks for specific customers
|
|
60
|
+
* const preciseValues = await getPreciseValues();
|
|
61
|
+
* if (!preciseValues.customerId) {
|
|
62
|
+
* throw new ForbiddenError("You must specify a valid customerId filter");
|
|
63
|
+
* }
|
|
64
|
+
* return filter;
|
|
65
|
+
* }
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
apiPreprocessFilter?: (filter: EntityFilter<entityType>, event: PreprocessFilterEvent<entityType>) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>;
|
|
70
|
+
/**
|
|
71
|
+
* Similar to apiPreprocessFilter, but for backend operations.
|
|
72
|
+
*
|
|
73
|
+
* @template entityType The type of the entity being filtered.
|
|
74
|
+
* @param filter The initial EntityFilter for the entity type.
|
|
75
|
+
* @param event Additional information and utilities for preprocessing the filter.
|
|
76
|
+
* @returns The modified EntityFilter or a Promise that resolves to the modified EntityFilter.
|
|
77
|
+
*/
|
|
78
|
+
backendPreprocessFilter?: (filter: EntityFilter<entityType>, event: PreprocessFilterEvent<entityType>) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>;
|
|
39
79
|
/** A filter that will be used for all queries from this entity both from the API and from within the backend.
|
|
40
80
|
* @example
|
|
41
81
|
* backendPrefilter: { archive:false }
|
|
@@ -124,3 +164,21 @@ export interface EntityOptions<entityType = any> {
|
|
|
124
164
|
entityRefInit?: (ref: EntityRef<entityType>, row: entityType) => void;
|
|
125
165
|
apiRequireId?: Allowed;
|
|
126
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Provides additional information and utilities for preprocessing filters in API and backend operations.
|
|
169
|
+
* @template entityType The type of the entity being filtered.
|
|
170
|
+
*/
|
|
171
|
+
export interface PreprocessFilterEvent<entityType> {
|
|
172
|
+
/**
|
|
173
|
+
* Metadata of the entity being filtered.
|
|
174
|
+
*/
|
|
175
|
+
metadata: EntityMetadata<entityType>;
|
|
176
|
+
/**
|
|
177
|
+
* Retrieves precise values for each property in a filter for an entity.
|
|
178
|
+
* @param filter Optional filter to analyze. If not provided, the current filter being preprocessed is used.
|
|
179
|
+
* @returns A promise that resolves to a FilterPreciseValues object containing the precise values for each property.
|
|
180
|
+
|
|
181
|
+
* {@Link FilterPreciseValues }
|
|
182
|
+
*/
|
|
183
|
+
getFilterPreciseValues(filter?: EntityFilter<entityType>): Promise<FilterPreciseValues<entityType>>;
|
|
184
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FieldMetadata } from '../column-interfaces.js';
|
|
2
2
|
import type { EntityMetadataOverloads, RepositoryOverloads } from '../remult3/RepositoryImplementation.js';
|
|
3
3
|
import type { EntityFilter, EntityMetadata, MembersOnly } from '../remult3/remult3.js';
|
|
4
|
-
import type { SqlCommandWithParameters } from '../sql-command.js';
|
|
4
|
+
import type { HasWrapIdentifier, SqlCommandWithParameters } from '../sql-command.js';
|
|
5
5
|
import type { Filter, FilterConsumer } from './filter-interfaces.js';
|
|
6
6
|
export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer {
|
|
7
7
|
private r;
|
|
@@ -28,25 +28,49 @@ export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer
|
|
|
28
28
|
private addToWhere;
|
|
29
29
|
databaseCustom(databaseCustom: CustomSqlFilterObject): void;
|
|
30
30
|
}
|
|
31
|
-
export type CustomSqlFilterBuilderFunction = (builder: CustomSqlFilterBuilder) => void | Promise<any>;
|
|
32
31
|
export interface CustomSqlFilterObject {
|
|
33
32
|
buildSql: CustomSqlFilterBuilderFunction;
|
|
34
33
|
}
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Represents a custom SQL filter builder function.
|
|
36
|
+
* @callback CustomSqlFilterBuilderFunction
|
|
37
|
+
* @param {CustomSqlFilterBuilder} builder - The custom SQL filter builder instance.
|
|
38
|
+
* @returns {void | string | Promise<string | void> } - The result of the custom SQL filter builder function.
|
|
39
|
+
*/
|
|
40
|
+
export type CustomSqlFilterBuilderFunction = (builder: CustomSqlFilterBuilder) => void | string | Promise<string | void>;
|
|
41
|
+
/**
|
|
42
|
+
* Represents a custom SQL filter builder.
|
|
43
|
+
*/
|
|
44
|
+
export declare class CustomSqlFilterBuilder implements SqlCommandWithParameters, HasWrapIdentifier {
|
|
36
45
|
private r;
|
|
37
|
-
|
|
46
|
+
wrapIdentifier: (name: string) => string;
|
|
47
|
+
constructor(r: SqlCommandWithParameters, wrapIdentifier: (name: string) => string);
|
|
38
48
|
sql: string;
|
|
39
|
-
/** @deprecated
|
|
49
|
+
/** @deprecated use `param` instead*/
|
|
40
50
|
addParameterAndReturnSqlToken(val: any): string;
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Adds a parameter value.
|
|
53
|
+
* @param {valueType} val - The value to add as a parameter.
|
|
54
|
+
* @param {FieldMetadata<valueType>} [field] - The field metadata.
|
|
55
|
+
* @returns {string} - The SQL token.
|
|
56
|
+
*/
|
|
57
|
+
param: <valueType>(val: valueType, field?: FieldMetadata<valueType, any>) => string;
|
|
58
|
+
/**
|
|
59
|
+
* Converts an entity filter into a raw SQL condition - and appends to it any `backendPrefilter` and `backendPreprocessFilter`
|
|
60
|
+
* @param {RepositoryOverloads<entityType>} repo - The repository.
|
|
61
|
+
* @param {EntityFilter<entityType>} condition - The entity filter.
|
|
62
|
+
* @returns {Promise<string>} - The raw SQL.
|
|
63
|
+
*/
|
|
64
|
+
filterToRaw: <entityType>(repo: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>) => Promise<string>;
|
|
43
65
|
}
|
|
44
66
|
export declare function isDbReadonly<entityType>(field: FieldMetadata, dbNames: EntityDbNames<entityType>): boolean;
|
|
45
67
|
export declare function shouldNotCreateField<entityType>(field: FieldMetadata, dbNames: EntityDbNames<entityType>): boolean;
|
|
68
|
+
export declare function shouldCreateEntity(entity: EntityMetadata<any>, e: EntityDbNamesBase): boolean;
|
|
46
69
|
export declare type EntityDbNamesBase = {
|
|
47
70
|
$entityName: string;
|
|
48
71
|
$dbNameOf(field: FieldMetadata<any> | string): string;
|
|
49
72
|
toString(): string;
|
|
73
|
+
wrapIdentifier: (name: string) => string;
|
|
50
74
|
};
|
|
51
75
|
export declare type EntityDbNames<entityType> = {
|
|
52
76
|
[Properties in keyof Required<MembersOnly<entityType>>]: 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.shouldNotCreateField = exports.isDbReadonly = exports.CustomSqlFilterBuilder = exports.FilterConsumerBridgeToSqlRequest = void 0;
|
|
3
|
+
exports.fieldDbName = exports.entityDbName = 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");
|
|
@@ -215,17 +215,19 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
215
215
|
FilterConsumerBridgeToSqlRequest.prototype.databaseCustom = function (databaseCustom) {
|
|
216
216
|
var _this = this;
|
|
217
217
|
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
218
|
-
var item;
|
|
218
|
+
var item, sql;
|
|
219
219
|
return tslib_1.__generator(this, function (_a) {
|
|
220
220
|
switch (_a.label) {
|
|
221
221
|
case 0:
|
|
222
222
|
if (!(databaseCustom === null || databaseCustom === void 0 ? void 0 : databaseCustom.buildSql)) return [3 /*break*/, 2];
|
|
223
|
-
item = new CustomSqlFilterBuilder(this.r);
|
|
223
|
+
item = new CustomSqlFilterBuilder(this.r, this.nameProvider.wrapIdentifier);
|
|
224
224
|
return [4 /*yield*/, databaseCustom.buildSql(item)];
|
|
225
225
|
case 1:
|
|
226
|
-
_a.sent();
|
|
227
|
-
if (
|
|
228
|
-
|
|
226
|
+
sql = _a.sent();
|
|
227
|
+
if (typeof sql !== 'string')
|
|
228
|
+
sql = item.sql;
|
|
229
|
+
if (sql) {
|
|
230
|
+
this.addToWhere('(' + sql + ')');
|
|
229
231
|
}
|
|
230
232
|
_a.label = 2;
|
|
231
233
|
case 2: return [2 /*return*/];
|
|
@@ -236,28 +238,45 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
236
238
|
return FilterConsumerBridgeToSqlRequest;
|
|
237
239
|
}());
|
|
238
240
|
exports.FilterConsumerBridgeToSqlRequest = FilterConsumerBridgeToSqlRequest;
|
|
241
|
+
/**
|
|
242
|
+
* Represents a custom SQL filter builder.
|
|
243
|
+
*/
|
|
239
244
|
var CustomSqlFilterBuilder = /** @class */ (function () {
|
|
240
|
-
function CustomSqlFilterBuilder(r) {
|
|
245
|
+
function CustomSqlFilterBuilder(r, wrapIdentifier) {
|
|
246
|
+
var _this = this;
|
|
241
247
|
this.r = r;
|
|
248
|
+
this.wrapIdentifier = wrapIdentifier;
|
|
242
249
|
this.sql = '';
|
|
250
|
+
/**
|
|
251
|
+
* Adds a parameter value.
|
|
252
|
+
* @param {valueType} val - The value to add as a parameter.
|
|
253
|
+
* @param {FieldMetadata<valueType>} [field] - The field metadata.
|
|
254
|
+
* @returns {string} - The SQL token.
|
|
255
|
+
*/
|
|
256
|
+
this.param = function (val, field) {
|
|
257
|
+
if (typeof field === 'object' && field.valueConverter.toDb) {
|
|
258
|
+
val = field.valueConverter.toDb(val);
|
|
259
|
+
}
|
|
260
|
+
return _this.r.param(val);
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Converts an entity filter into a raw SQL condition - and appends to it any `backendPrefilter` and `backendPreprocessFilter`
|
|
264
|
+
* @param {RepositoryOverloads<entityType>} repo - The repository.
|
|
265
|
+
* @param {EntityFilter<entityType>} condition - The entity filter.
|
|
266
|
+
* @returns {Promise<string>} - The raw SQL.
|
|
267
|
+
*/
|
|
268
|
+
this.filterToRaw = function (repo, condition) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
269
|
+
return tslib_1.__generator(this, function (_a) {
|
|
270
|
+
return [2 /*return*/, sql_database_js_1.SqlDatabase.filterToRaw(repo, condition, this, undefined, this.wrapIdentifier)];
|
|
271
|
+
});
|
|
272
|
+
}); };
|
|
273
|
+
this.param.bind(this);
|
|
274
|
+
this.filterToRaw.bind(this);
|
|
243
275
|
}
|
|
244
|
-
/** @deprecated
|
|
276
|
+
/** @deprecated use `param` instead*/
|
|
245
277
|
CustomSqlFilterBuilder.prototype.addParameterAndReturnSqlToken = function (val) {
|
|
246
278
|
return this.param(val);
|
|
247
279
|
};
|
|
248
|
-
CustomSqlFilterBuilder.prototype.param = function (val, field) {
|
|
249
|
-
if (typeof field === 'object' && field.valueConverter.toDb) {
|
|
250
|
-
val = field.valueConverter.toDb(val);
|
|
251
|
-
}
|
|
252
|
-
return this.r.param(val);
|
|
253
|
-
};
|
|
254
|
-
CustomSqlFilterBuilder.prototype.filterToRaw = function (repo, condition) {
|
|
255
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
256
|
-
return tslib_1.__generator(this, function (_a) {
|
|
257
|
-
return [2 /*return*/, sql_database_js_1.SqlDatabase.filterToRaw(repo, condition, this)];
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
};
|
|
261
280
|
return CustomSqlFilterBuilder;
|
|
262
281
|
}());
|
|
263
282
|
exports.CustomSqlFilterBuilder = CustomSqlFilterBuilder;
|
|
@@ -272,6 +291,11 @@ function shouldNotCreateField(field, dbNames) {
|
|
|
272
291
|
(field.options.sqlExpression && field.dbName != dbNames.$dbNameOf(field)));
|
|
273
292
|
}
|
|
274
293
|
exports.shouldNotCreateField = shouldNotCreateField;
|
|
294
|
+
function shouldCreateEntity(entity, e) {
|
|
295
|
+
return (!entity.options.sqlExpression &&
|
|
296
|
+
e.$entityName.toLowerCase().indexOf('from ') < 0);
|
|
297
|
+
}
|
|
298
|
+
exports.shouldCreateEntity = shouldCreateEntity;
|
|
275
299
|
function dbNamesOf(repo, wrapIdentifierOrOptions) {
|
|
276
300
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
277
301
|
var options, meta, result, _a, _b, field, r, e_3_1;
|
|
@@ -301,6 +325,7 @@ function dbNamesOf(repo, wrapIdentifierOrOptions) {
|
|
|
301
325
|
key = field.key;
|
|
302
326
|
return result[key];
|
|
303
327
|
},
|
|
328
|
+
_c.wrapIdentifier = options.wrapIdentifier,
|
|
304
329
|
_c);
|
|
305
330
|
_e.label = 2;
|
|
306
331
|
case 2:
|
|
@@ -1,78 +1,124 @@
|
|
|
1
1
|
import type { FieldMetadata } from '../column-interfaces.js';
|
|
2
2
|
import type { Remult } from '../context.js';
|
|
3
|
-
import type { EntityFilter, EntityMetadata } from '../remult3/remult3.js';
|
|
3
|
+
import type { EntityFilter, EntityMetadata, MembersOnly } from '../remult3/remult3.js';
|
|
4
4
|
/**
|
|
5
5
|
* The `Filter` class is a helper class that focuses on filter-related concerns. It provides methods
|
|
6
6
|
* for creating and applying filters in queries.
|
|
7
7
|
*/
|
|
8
8
|
export declare class Filter {
|
|
9
9
|
private apply;
|
|
10
|
+
/**
|
|
11
|
+
* Retrieves precise values for each property in a filter for an entity.
|
|
12
|
+
* @template entityType The type of the entity being filtered.
|
|
13
|
+
* @param metadata The metadata of the entity being filtered.
|
|
14
|
+
* @param filter The filter to analyze.
|
|
15
|
+
* @returns A promise that resolves to a FilterPreciseValues object containing the precise values for each property.
|
|
16
|
+
* @example
|
|
17
|
+
* const preciseValues = await Filter.getPreciseValues(meta, {
|
|
18
|
+
* status: { $ne: 'active' },
|
|
19
|
+
* $or: [
|
|
20
|
+
* { customerId: ["1", "2"] },
|
|
21
|
+
* { customerId: "3" }
|
|
22
|
+
* ]
|
|
23
|
+
* });
|
|
24
|
+
* console.log(preciseValues);
|
|
25
|
+
* // Output:
|
|
26
|
+
* // {
|
|
27
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
28
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
29
|
+
* // }
|
|
30
|
+
|
|
31
|
+
*/
|
|
32
|
+
static getPreciseValues<entityType>(metadata: EntityMetadata<entityType>, filter: EntityFilter<entityType>): Promise<FilterPreciseValues<entityType>>;
|
|
33
|
+
/**
|
|
34
|
+
* Retrieves precise values for each property in a filter for an entity.
|
|
35
|
+
* @template entityType The type of the entity being filtered.
|
|
36
|
+
* @param metadata The metadata of the entity being filtered.
|
|
37
|
+
* @param filter The filter to analyze.
|
|
38
|
+
* @returns A promise that resolves to a FilterPreciseValues object containing the precise values for each property.
|
|
39
|
+
* @example
|
|
40
|
+
* const preciseValues = await where.getPreciseValues();
|
|
41
|
+
* console.log(preciseValues);
|
|
42
|
+
* // Output:
|
|
43
|
+
* // {
|
|
44
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
45
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
46
|
+
* // }
|
|
47
|
+
|
|
48
|
+
*/
|
|
49
|
+
getPreciseValues<entityType>(): Promise<FilterPreciseValues<entityType>>;
|
|
10
50
|
/**
|
|
11
51
|
* Creates a custom filter. Custom filters are evaluated on the backend, ensuring security and efficiency.
|
|
12
52
|
* When the filter is used in the frontend, only its name is sent to the backend via the API,
|
|
13
53
|
* where the filter gets translated and applied in a safe manner.
|
|
14
54
|
*
|
|
15
55
|
* @template entityType The entity type for the filter.
|
|
16
|
-
* @param {function(): EntityFilter<entityType>}
|
|
56
|
+
* @param {function(): EntityFilter<entityType>} translator A function that returns an `EntityFilter`.
|
|
17
57
|
* @param {string} [key] An optional unique identifier for the custom filter.
|
|
18
58
|
* @returns {function(): EntityFilter<entityType>} A function that returns an `EntityFilter` of type `entityType`.
|
|
19
59
|
*
|
|
20
60
|
* @example
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
61
|
+
* class Order {
|
|
62
|
+
* //...
|
|
63
|
+
* static activeOrdersFor = Filter.createCustom<Order, { year: number }>(
|
|
64
|
+
* async ({ year }) => {
|
|
65
|
+
* return {
|
|
66
|
+
* status: ['created', 'confirmed', 'pending', 'blocked', 'delayed'],
|
|
67
|
+
* createdAt: {
|
|
68
|
+
* $gte: new Date(year, 0, 1),
|
|
69
|
+
* $lt: new Date(year + 1, 0, 1),
|
|
70
|
+
* },
|
|
71
|
+
* }
|
|
72
|
+
* },
|
|
73
|
+
* )
|
|
74
|
+
*}
|
|
28
75
|
* // Usage
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
|
|
76
|
+
* await repo(Order).find({
|
|
77
|
+
* where: Order.activeOrders({ year }),
|
|
78
|
+
*})
|
|
79
|
+
|
|
80
|
+
|
|
34
81
|
* @see
|
|
35
82
|
* [Sql filter and Custom filter](/docs/custom-filter.html)
|
|
36
83
|
* [Filtering and Relations](/docs/filtering-and-relations.html)
|
|
37
84
|
*/
|
|
38
|
-
static createCustom<entityType>(
|
|
85
|
+
static createCustom<entityType>(translator: (unused: never, r: Remult) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>, key?: string): (() => EntityFilter<entityType>) & customFilterInfo<entityType>;
|
|
39
86
|
/**
|
|
40
87
|
* Creates a custom filter. Custom filters are evaluated on the backend, ensuring security and efficiency.
|
|
41
|
-
* When the filter is used in the frontend, only its name
|
|
88
|
+
* When the filter is used in the frontend, only its name is sent to the backend via the API,
|
|
42
89
|
* where the filter gets translated and applied in a safe manner.
|
|
43
90
|
*
|
|
44
91
|
* @template entityType The entity type for the filter.
|
|
45
|
-
* @
|
|
46
|
-
* @param {function(argsType, Remult): EntityFilter<entityType>} rawFilterTranslator A function that takes an argument of type `argsType` and an instance of `Remult`, and returns an `EntityFilter`.
|
|
92
|
+
* @param {function(): EntityFilter<entityType>} translator A function that returns an `EntityFilter`.
|
|
47
93
|
* @param {string} [key] An optional unique identifier for the custom filter.
|
|
48
|
-
* @returns {function(
|
|
94
|
+
* @returns {function(): EntityFilter<entityType>} A function that returns an `EntityFilter` of type `entityType`.
|
|
49
95
|
*
|
|
50
96
|
* @example
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
97
|
+
* class Order {
|
|
98
|
+
* //...
|
|
99
|
+
* static activeOrdersFor = Filter.createCustom<Order, { year: number }>(
|
|
100
|
+
* async ({ year }) => {
|
|
101
|
+
* return {
|
|
102
|
+
* status: ['created', 'confirmed', 'pending', 'blocked', 'delayed'],
|
|
103
|
+
* createdAt: {
|
|
104
|
+
* $gte: new Date(year, 0, 1),
|
|
105
|
+
* $lt: new Date(year + 1, 0, 1),
|
|
106
|
+
* },
|
|
107
|
+
* }
|
|
108
|
+
* },
|
|
109
|
+
* )
|
|
110
|
+
*}
|
|
65
111
|
* // Usage
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
112
|
+
* await repo(Order).find({
|
|
113
|
+
* where: Order.activeOrders({ year }),
|
|
114
|
+
*})
|
|
115
|
+
|
|
116
|
+
|
|
71
117
|
* @see
|
|
72
118
|
* [Sql filter and Custom filter](/docs/custom-filter.html)
|
|
73
119
|
* [Filtering and Relations](/docs/filtering-and-relations.html)
|
|
74
120
|
*/
|
|
75
|
-
static createCustom<entityType, argsType>(
|
|
121
|
+
static createCustom<entityType, argsType>(translator: (args: argsType, r: Remult) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>, key?: string): ((y: argsType) => EntityFilter<entityType>) & customFilterInfo<entityType>;
|
|
76
122
|
/**
|
|
77
123
|
* Translates an `EntityFilter` to a plain JSON object that can be stored or transported.
|
|
78
124
|
*
|
|
@@ -135,6 +181,7 @@ export declare class Filter {
|
|
|
135
181
|
* @returns {Promise<EntityFilter<entityType>>} The resolved entity filter.
|
|
136
182
|
*/
|
|
137
183
|
static resolve<entityType>(filter: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>)): Promise<EntityFilter<entityType>>;
|
|
184
|
+
toJson(): any;
|
|
138
185
|
}
|
|
139
186
|
export interface FilterConsumer {
|
|
140
187
|
or(orElements: Filter[]): any;
|
|
@@ -194,3 +241,23 @@ export interface customFilterInfo<entityType> {
|
|
|
194
241
|
};
|
|
195
242
|
}
|
|
196
243
|
export declare function __updateEntityBasedOnWhere<T>(entityDefs: EntityMetadata<T>, where: EntityFilter<T>, r: T): void;
|
|
244
|
+
/**
|
|
245
|
+
* A mapping of property names to arrays of precise values for those properties.
|
|
246
|
+
* @example
|
|
247
|
+
* const preciseValues = await getPreciseValues(meta, {
|
|
248
|
+
* status: { $ne: 'active' },
|
|
249
|
+
* $or: [
|
|
250
|
+
* { customerId: ["1", "2"] },
|
|
251
|
+
* { customerId: "3" }
|
|
252
|
+
* ]
|
|
253
|
+
* });
|
|
254
|
+
* console.log(preciseValues);
|
|
255
|
+
* // Output:
|
|
256
|
+
* // {
|
|
257
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
258
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
259
|
+
* // }
|
|
260
|
+
*/
|
|
261
|
+
export type FilterPreciseValues<entityType> = {
|
|
262
|
+
[Properties in keyof MembersOnly<entityType>]?: Partial<entityType[Properties]>[];
|
|
263
|
+
};
|