remult 3.4.0-next.7 → 3.4.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/esm/internals.js +1 -0
- package/esm/remult-knex/index.js +46 -73
- package/esm/src/data-api.js +42 -31
- package/esm/src/data-providers/sql-database.js +46 -42
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +35 -34
- package/esm/src/filter/walk-filter.js +29 -0
- package/esm/src/remult-proxy.js +6 -6
- package/esm/src/remult3/RepositoryImplementation.js +49 -29
- package/esm/src/sort.js +0 -3
- package/esm/src/valueConverters.js +11 -0
- package/index.d.ts +1 -1
- package/internals.d.ts +1 -0
- package/internals.js +4 -1
- package/package.json +1 -1
- package/remult-knex/index.d.ts +3 -2
- package/remult-knex/index.js +118 -164
- package/src/data-api.d.ts +4 -0
- package/src/data-api.js +51 -48
- package/src/data-providers/sql-database.d.ts +16 -8
- package/src/data-providers/sql-database.js +90 -81
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +8 -3
- package/src/filter/filter-consumer-bridge-to-sql-request.js +40 -47
- package/src/filter/walk-filter.d.ts +3 -0
- package/src/filter/walk-filter.js +56 -0
- package/src/remult-proxy.js +12 -27
- package/src/remult3/RepositoryImplementation.d.ts +4 -2
- package/src/remult3/RepositoryImplementation.js +48 -30
- package/src/remult3/remult3.d.ts +37 -0
- package/src/sort.js +0 -3
- package/src/sql-command.d.ts +5 -0
- package/src/valueConverters.d.ts +4 -1
- package/src/valueConverters.js +13 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CustomSqlFilterBuilder = exports.FilterConsumerBridgeToSqlRequest = void 0;
|
|
3
|
+
exports.CustomSqlFilterBuilder = exports.FilterConsumerBridgeToSqlRequest = exports.LIKE_ESCAPE_SQL = void 0;
|
|
4
|
+
exports.escapeLike = escapeLike;
|
|
4
5
|
exports.isDbReadonly = isDbReadonly;
|
|
5
6
|
exports.shouldNotCreateField = shouldNotCreateField;
|
|
6
7
|
exports.shouldCreateEntity = shouldCreateEntity;
|
|
@@ -11,12 +12,24 @@ var tslib_1 = require("tslib");
|
|
|
11
12
|
var sql_database_js_1 = require("../data-providers/sql-database.js");
|
|
12
13
|
var remult_proxy_js_1 = require("../remult-proxy.js");
|
|
13
14
|
var RepositoryImplementation_js_1 = require("../remult3/RepositoryImplementation.js");
|
|
15
|
+
var valueConverters_js_1 = require("../valueConverters.js");
|
|
14
16
|
var entityDbName_js_1 = require("./entityDbName.js");
|
|
15
17
|
var fieldDbName_js_1 = require("./fieldDbName.js");
|
|
18
|
+
// `[` starts a character class in sql server's like. `]` on its own is a literal
|
|
19
|
+
// everywhere, so escaping the opening bracket is enough. The other engines treat
|
|
20
|
+
// an escaped non-wildcard as that literal, so one escape set works for all of them.
|
|
21
|
+
var REGEX_LIKE_SPECIAL = /[!%_\[]/g;
|
|
22
|
+
// `!` not `\`: a backslash in a string literal is an escape in mysql and in pg without standard_conforming_strings
|
|
23
|
+
exports.LIKE_ESCAPE_SQL = " escape '!'";
|
|
24
|
+
function escapeLike(val) {
|
|
25
|
+
return val.replace(REGEX_LIKE_SPECIAL, '!$&');
|
|
26
|
+
}
|
|
16
27
|
var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
17
|
-
function FilterConsumerBridgeToSqlRequest(r, nameProvider) {
|
|
28
|
+
function FilterConsumerBridgeToSqlRequest(r, nameProvider, jsonColumnStorage) {
|
|
29
|
+
if (jsonColumnStorage === void 0) { jsonColumnStorage = 'native'; }
|
|
18
30
|
this.r = r;
|
|
19
31
|
this.nameProvider = nameProvider;
|
|
32
|
+
this.jsonColumnStorage = jsonColumnStorage;
|
|
20
33
|
this.where = '';
|
|
21
34
|
this._addWhere = true;
|
|
22
35
|
this.promises = [];
|
|
@@ -81,7 +94,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
81
94
|
case 1:
|
|
82
95
|
if (!!orElements_1_1.done) return [3 /*break*/, 4];
|
|
83
96
|
element = orElements_1_1.value;
|
|
84
|
-
f = new FilterConsumerBridgeToSqlRequest(this.r, this.nameProvider);
|
|
97
|
+
f = new FilterConsumerBridgeToSqlRequest(this.r, this.nameProvider, this.jsonColumnStorage);
|
|
85
98
|
f._addWhere = false;
|
|
86
99
|
element.__applyToConsumer(f);
|
|
87
100
|
return [4 /*yield*/, f.resolveWhere()];
|
|
@@ -128,7 +141,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
128
141
|
return tslib_1.__generator(this, function (_a) {
|
|
129
142
|
switch (_a.label) {
|
|
130
143
|
case 0:
|
|
131
|
-
f = new FilterConsumerBridgeToSqlRequest(this.r, this.nameProvider);
|
|
144
|
+
f = new FilterConsumerBridgeToSqlRequest(this.r, this.nameProvider, this.jsonColumnStorage);
|
|
132
145
|
f._addWhere = false;
|
|
133
146
|
element.__applyToConsumer(f);
|
|
134
147
|
return [4 /*yield*/, f.resolveWhere()];
|
|
@@ -163,7 +176,9 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
163
176
|
this.addToWhere(this.nameProvider.$dbNameOf(col) +
|
|
164
177
|
' in (' +
|
|
165
178
|
val
|
|
166
|
-
.map(function (x) {
|
|
179
|
+
.map(function (x) {
|
|
180
|
+
return toDbSql(_this.r, col, (0, valueConverters_js_1.toDbColumn)(col, x, _this.jsonColumnStorage));
|
|
181
|
+
})
|
|
167
182
|
.join(',') +
|
|
168
183
|
')');
|
|
169
184
|
else
|
|
@@ -191,53 +206,29 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
191
206
|
this.add(col, val, '<');
|
|
192
207
|
};
|
|
193
208
|
FilterConsumerBridgeToSqlRequest.prototype.containsCaseInsensitive = function (col, val) {
|
|
194
|
-
|
|
195
|
-
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
196
|
-
return tslib_1.__generator(this, function (_a) {
|
|
197
|
-
this.addToWhere('lower (' +
|
|
198
|
-
this.nameProvider.$dbNameOf(col) +
|
|
199
|
-
") like lower ('%" +
|
|
200
|
-
val.replace(/'/g, "''") +
|
|
201
|
-
"%')");
|
|
202
|
-
return [2 /*return*/];
|
|
203
|
-
});
|
|
204
|
-
}); })());
|
|
209
|
+
this.like(col, '%' + escapeLike(val) + '%');
|
|
205
210
|
};
|
|
206
211
|
FilterConsumerBridgeToSqlRequest.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
207
|
-
|
|
208
|
-
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
209
|
-
return tslib_1.__generator(this, function (_a) {
|
|
210
|
-
this.addToWhere('not lower (' +
|
|
211
|
-
this.nameProvider.$dbNameOf(col) +
|
|
212
|
-
") like lower ('%" +
|
|
213
|
-
val.replace(/'/g, "''") +
|
|
214
|
-
"%')");
|
|
215
|
-
return [2 /*return*/];
|
|
216
|
-
});
|
|
217
|
-
}); })());
|
|
212
|
+
this.like(col, '%' + escapeLike(val) + '%', 'not ');
|
|
218
213
|
};
|
|
219
214
|
FilterConsumerBridgeToSqlRequest.prototype.startsWithCaseInsensitive = function (col, val) {
|
|
220
|
-
|
|
221
|
-
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
222
|
-
return tslib_1.__generator(this, function (_a) {
|
|
223
|
-
this.addToWhere('lower (' +
|
|
224
|
-
this.nameProvider.$dbNameOf(col) +
|
|
225
|
-
") like lower ('" +
|
|
226
|
-
val.replace(/'/g, "''") +
|
|
227
|
-
"%')");
|
|
228
|
-
return [2 /*return*/];
|
|
229
|
-
});
|
|
230
|
-
}); })());
|
|
215
|
+
this.like(col, escapeLike(val) + '%');
|
|
231
216
|
};
|
|
232
217
|
FilterConsumerBridgeToSqlRequest.prototype.endsWithCaseInsensitive = function (col, val) {
|
|
218
|
+
this.like(col, '%' + escapeLike(val));
|
|
219
|
+
};
|
|
220
|
+
FilterConsumerBridgeToSqlRequest.prototype.like = function (col, pattern, not) {
|
|
233
221
|
var _this = this;
|
|
222
|
+
if (not === void 0) { not = ''; }
|
|
234
223
|
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
235
224
|
return tslib_1.__generator(this, function (_a) {
|
|
236
|
-
this.addToWhere(
|
|
225
|
+
this.addToWhere(not +
|
|
226
|
+
'lower (' +
|
|
237
227
|
this.nameProvider.$dbNameOf(col) +
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
228
|
+
') like lower (' +
|
|
229
|
+
this.r.param(pattern) +
|
|
230
|
+
')' +
|
|
231
|
+
exports.LIKE_ESCAPE_SQL);
|
|
241
232
|
return [2 /*return*/];
|
|
242
233
|
});
|
|
243
234
|
}); })());
|
|
@@ -251,7 +242,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
251
242
|
' ' +
|
|
252
243
|
operator +
|
|
253
244
|
' ' +
|
|
254
|
-
toDbSql(this.r, col,
|
|
245
|
+
toDbSql(this.r, col, (0, valueConverters_js_1.toDbColumn)(col, val, this.jsonColumnStorage));
|
|
255
246
|
this.addToWhere(x);
|
|
256
247
|
return [2 /*return*/];
|
|
257
248
|
});
|
|
@@ -274,7 +265,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
274
265
|
switch (_a.label) {
|
|
275
266
|
case 0:
|
|
276
267
|
if (!(databaseCustom === null || databaseCustom === void 0 ? void 0 : databaseCustom.buildSql)) return [3 /*break*/, 2];
|
|
277
|
-
item = new CustomSqlFilterBuilder(this.r, this.nameProvider.wrapIdentifier);
|
|
268
|
+
item = new CustomSqlFilterBuilder(this.r, this.nameProvider.wrapIdentifier, this.jsonColumnStorage);
|
|
278
269
|
return [4 /*yield*/, databaseCustom.buildSql(item)];
|
|
279
270
|
case 1:
|
|
280
271
|
sql = _a.sent();
|
|
@@ -296,10 +287,12 @@ exports.FilterConsumerBridgeToSqlRequest = FilterConsumerBridgeToSqlRequest;
|
|
|
296
287
|
* Represents a custom SQL filter builder.
|
|
297
288
|
*/
|
|
298
289
|
var CustomSqlFilterBuilder = /** @class */ (function () {
|
|
299
|
-
function CustomSqlFilterBuilder(r, wrapIdentifier) {
|
|
290
|
+
function CustomSqlFilterBuilder(r, wrapIdentifier, jsonColumnStorage) {
|
|
291
|
+
if (jsonColumnStorage === void 0) { jsonColumnStorage = 'native'; }
|
|
300
292
|
var _this = this;
|
|
301
293
|
this.r = r;
|
|
302
294
|
this.wrapIdentifier = wrapIdentifier;
|
|
295
|
+
this.jsonColumnStorage = jsonColumnStorage;
|
|
303
296
|
this.sql = '';
|
|
304
297
|
/**
|
|
305
298
|
* Adds a parameter value.
|
|
@@ -308,8 +301,8 @@ var CustomSqlFilterBuilder = /** @class */ (function () {
|
|
|
308
301
|
* @returns {string} - The SQL token.
|
|
309
302
|
*/
|
|
310
303
|
this.param = function (val, field) {
|
|
311
|
-
if (
|
|
312
|
-
val =
|
|
304
|
+
if (field) {
|
|
305
|
+
val = (0, valueConverters_js_1.toDbColumn)(field, val, _this.jsonColumnStorage);
|
|
313
306
|
}
|
|
314
307
|
return _this.r.param(val);
|
|
315
308
|
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.omitFilterField = void 0;
|
|
4
|
+
exports.walkFilter = walkFilter;
|
|
5
|
+
var tslib_1 = require("tslib");
|
|
6
|
+
/** Return this from {@link walkFilter}'s visitor to drop that field key. */
|
|
7
|
+
exports.omitFilterField = Symbol('omitFilterField');
|
|
8
|
+
function isCompoundFilterKey(key) {
|
|
9
|
+
return key === '$and' || key === '$or' || key === '$not';
|
|
10
|
+
}
|
|
11
|
+
// `$and`, `$or`, and `$not` are entered. Every other key is a field, passed to `visit`.
|
|
12
|
+
// `visit` returns the value to keep, or `omitFilterField` to drop the key.
|
|
13
|
+
function walkFilter(filter, visit) {
|
|
14
|
+
var e_1, _a, e_2, _b;
|
|
15
|
+
if (Array.isArray(filter)) {
|
|
16
|
+
var result_1 = [];
|
|
17
|
+
try {
|
|
18
|
+
for (var filter_1 = tslib_1.__values(filter), filter_1_1 = filter_1.next(); !filter_1_1.done; filter_1_1 = filter_1.next()) {
|
|
19
|
+
var item = filter_1_1.value;
|
|
20
|
+
result_1.push(walkFilter(item, visit));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
24
|
+
finally {
|
|
25
|
+
try {
|
|
26
|
+
if (filter_1_1 && !filter_1_1.done && (_a = filter_1.return)) _a.call(filter_1);
|
|
27
|
+
}
|
|
28
|
+
finally { if (e_1) throw e_1.error; }
|
|
29
|
+
}
|
|
30
|
+
return result_1;
|
|
31
|
+
}
|
|
32
|
+
if (!filter || typeof filter !== 'object')
|
|
33
|
+
return filter;
|
|
34
|
+
var result = {};
|
|
35
|
+
try {
|
|
36
|
+
for (var _c = tslib_1.__values(Object.keys(filter)), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
37
|
+
var key = _d.value;
|
|
38
|
+
var value = filter[key];
|
|
39
|
+
if (isCompoundFilterKey(key)) {
|
|
40
|
+
result[key] = walkFilter(value, visit);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
var next = visit(key, value);
|
|
44
|
+
if (next !== exports.omitFilterField)
|
|
45
|
+
result[key] = next;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
49
|
+
finally {
|
|
50
|
+
try {
|
|
51
|
+
if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
|
|
52
|
+
}
|
|
53
|
+
finally { if (e_2) throw e_2.error; }
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
package/src/remult-proxy.js
CHANGED
|
@@ -112,16 +112,11 @@ var RemultProxy = /** @class */ (function () {
|
|
|
112
112
|
.repo.apply(_b, tslib_1.__spreadArray([], tslib_1.__read(args), false)))
|
|
113
113
|
.updateMany.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args2), false));
|
|
114
114
|
},
|
|
115
|
-
_a.find = function () {
|
|
116
|
-
var _a
|
|
117
|
-
|
|
118
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
119
|
-
args2[_i] = arguments[_i];
|
|
120
|
-
}
|
|
121
|
-
return (_a = (_b = self
|
|
115
|
+
_a.find = function (options) {
|
|
116
|
+
var _a;
|
|
117
|
+
return (_a = self
|
|
122
118
|
.remultFactory())
|
|
123
|
-
.repo.apply(
|
|
124
|
-
.find.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args2), false));
|
|
119
|
+
.repo.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args), false)).find(options);
|
|
125
120
|
},
|
|
126
121
|
_a.groupBy = function () {
|
|
127
122
|
var _a, _b;
|
|
@@ -145,27 +140,17 @@ var RemultProxy = /** @class */ (function () {
|
|
|
145
140
|
.repo.apply(_b, tslib_1.__spreadArray([], tslib_1.__read(args), false)))
|
|
146
141
|
.aggregate.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args2), false));
|
|
147
142
|
},
|
|
148
|
-
_a.findFirst = function () {
|
|
149
|
-
var _a
|
|
150
|
-
|
|
151
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
152
|
-
args2[_i] = arguments[_i];
|
|
153
|
-
}
|
|
154
|
-
return (_a = (_b = self
|
|
143
|
+
_a.findFirst = function (where, options) {
|
|
144
|
+
var _a;
|
|
145
|
+
return (_a = self
|
|
155
146
|
.remultFactory())
|
|
156
|
-
.repo.apply(
|
|
157
|
-
.findFirst.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args2), false));
|
|
147
|
+
.repo.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args), false)).findFirst(where, options);
|
|
158
148
|
},
|
|
159
|
-
_a.findOne = function () {
|
|
160
|
-
var _a
|
|
161
|
-
|
|
162
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
163
|
-
args2[_i] = arguments[_i];
|
|
164
|
-
}
|
|
165
|
-
return (_a = (_b = self
|
|
149
|
+
_a.findOne = function (options) {
|
|
150
|
+
var _a;
|
|
151
|
+
return (_a = self
|
|
166
152
|
.remultFactory())
|
|
167
|
-
.repo.apply(
|
|
168
|
-
.findOne.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args2), false));
|
|
153
|
+
.repo.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(args), false)).findOne(options);
|
|
169
154
|
},
|
|
170
155
|
_a.findId = function (a, b) {
|
|
171
156
|
var _a;
|
|
@@ -106,6 +106,7 @@ declare abstract class rowHelperBase<T> {
|
|
|
106
106
|
* must not be serialized by {@link toApiJson}. */
|
|
107
107
|
_fieldsExcludedBySelect?: Set<string>;
|
|
108
108
|
constructor(fieldsMetadata: FieldMetadata[], instance: T, remult: Remult, isNewRow: boolean, excludeRelationMembers?: Set<string>);
|
|
109
|
+
_skipRelationFieldSync: boolean;
|
|
109
110
|
_subscribers?: SubscribableImp;
|
|
110
111
|
subscribe(listener: RefSubscriber): Unsubscribe;
|
|
111
112
|
_isLoading: boolean;
|
|
@@ -302,7 +303,7 @@ export declare function isAutoIncrement(f: FieldMetadata): boolean;
|
|
|
302
303
|
export declare function ValueListFieldType<valueType extends ValueListItem = ValueListItem>(...options: (ValueListFieldOptions<any, valueType> | ((options: FieldOptions<any, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>, context?: any) => void;
|
|
303
304
|
export interface ValueListFieldOptions<entityType, valueType> extends FieldOptions<entityType, valueType> {
|
|
304
305
|
getValues?: () => valueType[];
|
|
305
|
-
/** Value used when a stored id is not in the list. A value, or `(id) => value`. @default undefined */
|
|
306
|
+
/** Value used when a stored id is not in the list. A value, or `(id) => value`. Only `null` and `undefined` stay `undefined`; a blank `''` uses this, which is the usual legacy column. A declared id of `''` is unaffected. @default undefined */
|
|
306
307
|
unknownIdValue?: valueType | ((id: any) => valueType | undefined);
|
|
307
308
|
}
|
|
308
309
|
export declare class ValueListInfo<T extends ValueListItem> implements ValueConverter<T> {
|
|
@@ -314,7 +315,8 @@ export declare class ValueListInfo<T extends ValueListItem> implements ValueConv
|
|
|
314
315
|
private unknownIdValue?;
|
|
315
316
|
private constructor();
|
|
316
317
|
getValues(): T[];
|
|
317
|
-
|
|
318
|
+
/** Declared id only. Pass `useUnknownIdValue` to also apply `unknownIdValue` (`null` and `undefined` still return `undefined`). */
|
|
319
|
+
byId(key: any, useUnknownIdValue?: boolean): T | undefined;
|
|
318
320
|
fromJson(val: any): T;
|
|
319
321
|
toJson(val: T): any;
|
|
320
322
|
fromDb(val: any): T;
|
|
@@ -57,6 +57,18 @@ var classValidatorValidate = undefined;
|
|
|
57
57
|
// })
|
|
58
58
|
// .catch(() => {
|
|
59
59
|
// });
|
|
60
|
+
// Assigning a `toOne` also writes its `field`/`fields`, which would wipe the FK of a row whose
|
|
61
|
+
// target is missing.
|
|
62
|
+
function setMissingRelationToNull(row, key) {
|
|
63
|
+
var ref = (0, getEntityRef_js_1.getEntityRef)(row);
|
|
64
|
+
ref._skipRelationFieldSync = true;
|
|
65
|
+
try {
|
|
66
|
+
row[key] = null;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
ref._skipRelationFieldSync = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
60
72
|
var RepositoryImplementation = /** @class */ (function () {
|
|
61
73
|
function RepositoryImplementation(_entity, _remult, _dataProvider, _info, _defaultFindOptions) {
|
|
62
74
|
this._entity = _entity;
|
|
@@ -954,7 +966,7 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
954
966
|
};
|
|
955
967
|
RepositoryImplementation.prototype._rawFind = function (options_1) {
|
|
956
968
|
return tslib_1.__awaiter(this, arguments, void 0, function (options, skipOrderByAndLimit, loader, actualFind) {
|
|
957
|
-
var opt, rawRows, result;
|
|
969
|
+
var findOptions, opt, rawRows, result;
|
|
958
970
|
if (skipOrderByAndLimit === void 0) { skipOrderByAndLimit = false; }
|
|
959
971
|
return tslib_1.__generator(this, function (_a) {
|
|
960
972
|
switch (_a.label) {
|
|
@@ -964,7 +976,13 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
964
976
|
if (this._defaultFindOptions) {
|
|
965
977
|
options = tslib_1.__assign(tslib_1.__assign({}, this._defaultFindOptions), options);
|
|
966
978
|
}
|
|
967
|
-
|
|
979
|
+
findOptions = options;
|
|
980
|
+
if ((!findOptions.orderBy || Object.keys(findOptions.orderBy).length === 0) &&
|
|
981
|
+
!this._dataProvider.isProxy &&
|
|
982
|
+
this._info.entityInfo.defaultOrderBy) {
|
|
983
|
+
findOptions = tslib_1.__assign(tslib_1.__assign({}, findOptions), { orderBy: this._info.entityInfo.defaultOrderBy });
|
|
984
|
+
}
|
|
985
|
+
return [4 /*yield*/, this._buildEntityDataProviderFindOptions(findOptions)];
|
|
968
986
|
case 1:
|
|
969
987
|
opt = _a.sent();
|
|
970
988
|
if (skipOrderByAndLimit) {
|
|
@@ -1029,10 +1047,6 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1029
1047
|
return f.key;
|
|
1030
1048
|
});
|
|
1031
1049
|
}
|
|
1032
|
-
if (!options.orderBy || Object.keys(options.orderBy).length === 0) {
|
|
1033
|
-
if (!this._dataProvider.isProxy)
|
|
1034
|
-
options.orderBy = this._info.entityInfo.defaultOrderBy;
|
|
1035
|
-
}
|
|
1036
1050
|
_a = opt;
|
|
1037
1051
|
return [4 /*yield*/, this._translateWhereToFilter(options.where)];
|
|
1038
1052
|
case 1:
|
|
@@ -1225,10 +1239,12 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1225
1239
|
var _loop_2 = function (row) {
|
|
1226
1240
|
var _e = this_1._findOptionsBasedOnRelation(rel, col, incl, row, otherRepo), findOptions = _e.findOptions, returnNull = _e.returnNull, returnUndefined = _e.returnUndefined;
|
|
1227
1241
|
var colKey = col.key;
|
|
1228
|
-
if (returnNull)
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1242
|
+
if (returnNull || returnUndefined) {
|
|
1243
|
+
if (rel.type === 'toMany')
|
|
1244
|
+
row[colKey] = (returnNull ? null : undefined);
|
|
1245
|
+
else
|
|
1246
|
+
setMissingRelationToNull(row, colKey);
|
|
1247
|
+
}
|
|
1232
1248
|
else {
|
|
1233
1249
|
var entityType = rel.toEntity;
|
|
1234
1250
|
var toRepo_1 = otherRepo;
|
|
@@ -1243,14 +1259,12 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1243
1259
|
metadata: toRepo_1.metadata,
|
|
1244
1260
|
}, findOptions)
|
|
1245
1261
|
.then(function (result) {
|
|
1246
|
-
if (
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
: result[0]
|
|
1253
|
-
: result;
|
|
1262
|
+
if (rel.type === 'toMany')
|
|
1263
|
+
row[colKey] = result;
|
|
1264
|
+
else if (result.length == 0)
|
|
1265
|
+
setMissingRelationToNull(row, colKey);
|
|
1266
|
+
else
|
|
1267
|
+
row[colKey] = result[0];
|
|
1254
1268
|
});
|
|
1255
1269
|
}
|
|
1256
1270
|
};
|
|
@@ -1894,6 +1908,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1894
1908
|
this.instance = instance;
|
|
1895
1909
|
this.remult = remult;
|
|
1896
1910
|
this.isNewRow = isNewRow;
|
|
1911
|
+
this._skipRelationFieldSync = false;
|
|
1897
1912
|
this._isLoading = false;
|
|
1898
1913
|
this.lookups = new Map();
|
|
1899
1914
|
this.originalValues = {};
|
|
@@ -1953,7 +1968,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1953
1968
|
},
|
|
1954
1969
|
set: function (newVal) {
|
|
1955
1970
|
val_1 = newVal;
|
|
1956
|
-
if (newVal === undefined)
|
|
1971
|
+
if (newVal === undefined || _this._skipRelationFieldSync)
|
|
1957
1972
|
return;
|
|
1958
1973
|
var op = col.options;
|
|
1959
1974
|
if (op.field) {
|
|
@@ -2804,7 +2819,9 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2804
2819
|
finally { if (e_41) throw e_41.error; }
|
|
2805
2820
|
return [7 /*endfinally*/];
|
|
2806
2821
|
case 12:
|
|
2807
|
-
this.repo._remult.liveQueryPublisher.itemChanged(this.repo.metadata.key, [
|
|
2822
|
+
this.repo._remult.liveQueryPublisher.itemChanged(this.repo.metadata.key, [
|
|
2823
|
+
{ id: this.getId(), oldId: this.getOriginalId(), deleted: false },
|
|
2824
|
+
]);
|
|
2808
2825
|
this.saveOriginalData();
|
|
2809
2826
|
this._isNew = false;
|
|
2810
2827
|
return [2 /*return*/, this.instance];
|
|
@@ -4045,21 +4062,22 @@ var ValueListInfo = /** @class */ (function () {
|
|
|
4045
4062
|
ValueListInfo.prototype.getValues = function () {
|
|
4046
4063
|
return this.values;
|
|
4047
4064
|
};
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
var known = this.byId(val);
|
|
4055
|
-
if (known !== undefined)
|
|
4065
|
+
/** Declared id only. Pass `useUnknownIdValue` to also apply `unknownIdValue` (`null` and `undefined` still return `undefined`). */
|
|
4066
|
+
ValueListInfo.prototype.byId = function (key, useUnknownIdValue) {
|
|
4067
|
+
if (useUnknownIdValue === void 0) { useUnknownIdValue = false; }
|
|
4068
|
+
var lookupKey = this.isNumeric ? +key : key;
|
|
4069
|
+
var known = this.byIdMap.get(lookupKey);
|
|
4070
|
+
if (known !== undefined || !useUnknownIdValue)
|
|
4056
4071
|
return known;
|
|
4057
|
-
if (
|
|
4072
|
+
if (key == null)
|
|
4058
4073
|
return undefined;
|
|
4059
4074
|
var fallback = this.unknownIdValue;
|
|
4060
4075
|
if (typeof fallback !== 'function')
|
|
4061
4076
|
return fallback;
|
|
4062
|
-
return fallback(
|
|
4077
|
+
return fallback(lookupKey);
|
|
4078
|
+
};
|
|
4079
|
+
ValueListInfo.prototype.fromJson = function (val) {
|
|
4080
|
+
return this.byId(val, true);
|
|
4063
4081
|
};
|
|
4064
4082
|
ValueListInfo.prototype.toJson = function (val) {
|
|
4065
4083
|
if (!val)
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -395,6 +395,10 @@ export type GroupByResult<entityType, groupByFields extends (keyof entityType)[]
|
|
|
395
395
|
};
|
|
396
396
|
/** used to perform CRUD operations on an `entityType` */
|
|
397
397
|
export interface Repository<entityType> {
|
|
398
|
+
/** returns an array based on the provided options. Included relations drop their `?`, see {@link Loaded} */
|
|
399
|
+
find<const include extends MembersToInclude<entityType>>(options: FindOptions<entityType> & {
|
|
400
|
+
include: include;
|
|
401
|
+
}): Promise<Loaded<entityType, include>[]>;
|
|
398
402
|
/** returns an array based on the provided options */
|
|
399
403
|
find(options?: FindOptions<entityType>): Promise<entityType[]>;
|
|
400
404
|
/** Using the same options as the {@link find} method, but subscribing to entity changes.
|
|
@@ -410,6 +414,9 @@ export interface Repository<entityType> {
|
|
|
410
414
|
* @example
|
|
411
415
|
* await taskRepo.findFirst({ completed:false },{ createIfNotFound: true })
|
|
412
416
|
* */
|
|
417
|
+
findFirst<const include extends MembersToInclude<entityType>>(where: EntityFilter<entityType> | undefined, options: FindFirstOptions<entityType> & {
|
|
418
|
+
include: include;
|
|
419
|
+
}): Promise<Loaded<entityType, include> | undefined>;
|
|
413
420
|
findFirst(where?: EntityFilter<entityType>, options?: FindFirstOptions<entityType>): Promise<entityType | undefined>;
|
|
414
421
|
/** returns the first item that matchers the `where` condition
|
|
415
422
|
* @example
|
|
@@ -417,8 +424,14 @@ export interface Repository<entityType> {
|
|
|
417
424
|
* @example
|
|
418
425
|
* await taskRepo.findFirst({ where:{ completed:false }, createIfNotFound: true })
|
|
419
426
|
* */
|
|
427
|
+
findOne<const include extends MembersToInclude<entityType>>(options: FindFirstOptions<entityType> & {
|
|
428
|
+
include: include;
|
|
429
|
+
}): Promise<Loaded<entityType, include> | undefined>;
|
|
420
430
|
findOne(options?: FindFirstOptions<entityType>): Promise<entityType | undefined>;
|
|
421
431
|
/** returns the items that matches the id. If id is undefined | null, returns null */
|
|
432
|
+
findId<const include extends MembersToInclude<entityType>>(id: idType<entityType>, options: FindFirstOptionsBase<entityType> & {
|
|
433
|
+
include: include;
|
|
434
|
+
}): Promise<Loaded<entityType, include> | undefined | null>;
|
|
422
435
|
findId(id: idType<entityType>, options?: FindFirstOptionsBase<entityType>): Promise<entityType | undefined | null>;
|
|
423
436
|
/**
|
|
424
437
|
* Performs an aggregation on the repository's entity type based on the specified options.
|
|
@@ -1183,6 +1196,29 @@ export type ObjectMembersOnly<T> = MembersOnly<{
|
|
|
1183
1196
|
export type MembersToInclude<T> = {
|
|
1184
1197
|
[K in keyof ObjectMembersOnly<T>]?: boolean | (NonNullable<T[K]> extends Array<any> ? FindOptions<NonNullable<T[K]>[number]> : FindFirstOptions<NonNullable<T[K]>>);
|
|
1185
1198
|
};
|
|
1199
|
+
type LoadedTarget<target, include> = include extends {
|
|
1200
|
+
include: infer nested;
|
|
1201
|
+
} ? Loaded<target, nested> : target;
|
|
1202
|
+
type LoadedRelation<value, include> = NonNullable<value> extends (infer target)[] ? LoadedTarget<target, include>[] : null extends value ? LoadedTarget<NonNullable<value>, include> | null : LoadedTarget<NonNullable<value>, include>;
|
|
1203
|
+
type LoadedKeys<entityType, include> = {
|
|
1204
|
+
[K in keyof include & keyof entityType]-?: [include[K]] extends [
|
|
1205
|
+
true | object
|
|
1206
|
+
] ? K : never;
|
|
1207
|
+
}[keyof include & keyof entityType];
|
|
1208
|
+
/**
|
|
1209
|
+
* The entity type `find` returns for a given `include`.
|
|
1210
|
+
* Included relations drop their `?`, and nested `include`s work the same way.
|
|
1211
|
+
* A relation declared `| null` stays nullable.
|
|
1212
|
+
* A relation included with `false` or a widened `boolean` keeps its declared type.
|
|
1213
|
+
* An included relation whose target row is missing loads as `null`.
|
|
1214
|
+
* Declare it `| null` when that can happen, e.g. an optional FK or a target a `backendPrefilter` can hide.
|
|
1215
|
+
* @example
|
|
1216
|
+
* const tasks = await repo(Task).find({ include: { category: true } })
|
|
1217
|
+
* tasks[0].category.name // `category` is loaded, no `?.` needed
|
|
1218
|
+
*/
|
|
1219
|
+
export type Loaded<entityType, include> = 0 extends 1 & (entityType | include) ? entityType : [LoadedKeys<entityType, include>] extends [never] ? entityType : Omit<entityType, LoadedKeys<entityType, include>> & {
|
|
1220
|
+
[K in LoadedKeys<entityType, include>]-?: LoadedRelation<Exclude<entityType[K], undefined>, include[K]>;
|
|
1221
|
+
};
|
|
1186
1222
|
export type RepositoryRelations<entityType> = {
|
|
1187
1223
|
[K in keyof ObjectMembersOnly<entityType>]-?: NonNullable<entityType[K]> extends Array<infer R> ? Repository<R> : entityType[K] extends infer R ? {
|
|
1188
1224
|
findOne: (options?: FindOptionsBase<R>) => Promise<R>;
|
|
@@ -1229,3 +1265,4 @@ export declare const flags: {
|
|
|
1229
1265
|
/** Version poll while SSE is stale */
|
|
1230
1266
|
liveQueryPollWhenStaleMs: number;
|
|
1231
1267
|
};
|
|
1268
|
+
export {};
|
package/src/sort.js
CHANGED
|
@@ -159,9 +159,6 @@ var Sort = /** @class */ (function () {
|
|
|
159
159
|
*/
|
|
160
160
|
Sort.createUniqueSort = function (entityMetadata, orderBy) {
|
|
161
161
|
var e_3, _a;
|
|
162
|
-
if ((!orderBy || Object.keys(orderBy).length === 0) &&
|
|
163
|
-
entityMetadata.options.defaultOrderBy)
|
|
164
|
-
orderBy = Sort.translateOrderByToSort(entityMetadata, entityMetadata.options.defaultOrderBy);
|
|
165
162
|
if (!orderBy)
|
|
166
163
|
orderBy = new Sort();
|
|
167
164
|
var _loop_2 = function (field) {
|
package/src/sql-command.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export interface SqlImplementation extends HasWrapIdentifier {
|
|
|
18
18
|
export interface HasWrapIdentifier {
|
|
19
19
|
wrapIdentifier?(name: string): string;
|
|
20
20
|
}
|
|
21
|
+
/** How a provider stores `Fields.json`: a real json column, a text column, or text only on write (mysql2 parses on read). */
|
|
22
|
+
export type JsonColumnStorage = 'native' | 'text' | 'textOnWrite';
|
|
23
|
+
export interface HasJsonColumnStorage {
|
|
24
|
+
jsonColumnStorage: JsonColumnStorage;
|
|
25
|
+
}
|
|
21
26
|
export interface SqlCommandFactory extends HasWrapIdentifier {
|
|
22
27
|
createCommand(): SqlCommand;
|
|
23
28
|
execute(sql: string): Promise<SqlResult>;
|
package/src/valueConverters.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ValueConverter } from './column-interfaces.js';
|
|
1
|
+
import type { FieldMetadata, ValueConverter } from './column-interfaces.js';
|
|
2
|
+
import type { JsonColumnStorage } from './sql-command.js';
|
|
2
3
|
export declare class ValueConverters {
|
|
3
4
|
static readonly Date: ValueConverter<Date>;
|
|
4
5
|
static readonly DateOnly: ValueConverter<Date>;
|
|
@@ -13,3 +14,5 @@ export declare class ValueConverters {
|
|
|
13
14
|
static readonly JsonString: ValueConverter<any>;
|
|
14
15
|
static readonly JsonValue: ValueConverter<any>;
|
|
15
16
|
}
|
|
17
|
+
export declare function fromDbColumn(field: FieldMetadata, value: any, storage: JsonColumnStorage): any;
|
|
18
|
+
export declare function toDbColumn(field: FieldMetadata, value: any, storage: JsonColumnStorage): any;
|
package/src/valueConverters.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ValueConverters = void 0;
|
|
4
|
+
exports.fromDbColumn = fromDbColumn;
|
|
5
|
+
exports.toDbColumn = toDbColumn;
|
|
4
6
|
var tslib_1 = require("tslib");
|
|
5
7
|
var inputTypes_js_1 = require("../inputTypes.js");
|
|
6
8
|
var zeroDate = new Date('0000-01-01');
|
|
@@ -213,6 +215,17 @@ var ValueConverters = /** @class */ (function () {
|
|
|
213
215
|
return ValueConverters;
|
|
214
216
|
}());
|
|
215
217
|
exports.ValueConverters = ValueConverters;
|
|
218
|
+
function fromDbColumn(field, value, storage) {
|
|
219
|
+
if (storage === 'text' && field.valueConverter.fieldTypeInDb === 'json')
|
|
220
|
+
return ValueConverters.JsonString.fromDb(value);
|
|
221
|
+
return field.valueConverter.fromDb(value);
|
|
222
|
+
}
|
|
223
|
+
function toDbColumn(field, value, storage) {
|
|
224
|
+
if ((storage === 'text' || storage === 'textOnWrite') &&
|
|
225
|
+
field.valueConverter.fieldTypeInDb === 'json')
|
|
226
|
+
return ValueConverters.JsonString.toDb(value);
|
|
227
|
+
return field.valueConverter.toDb(value);
|
|
228
|
+
}
|
|
216
229
|
function enforceString(value) {
|
|
217
230
|
if (value === null || value === undefined)
|
|
218
231
|
return value;
|