remult 3.4.0-next.9 → 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 +44 -39
- 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 +29 -14
- 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 -7
- package/src/data-providers/sql-database.js +100 -90
- 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 +1 -0
- package/src/remult3/RepositoryImplementation.js +29 -14
- package/src/remult3/remult3.d.ts +37 -0
- 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;
|
|
@@ -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;
|
|
@@ -1227,10 +1239,12 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1227
1239
|
var _loop_2 = function (row) {
|
|
1228
1240
|
var _e = this_1._findOptionsBasedOnRelation(rel, col, incl, row, otherRepo), findOptions = _e.findOptions, returnNull = _e.returnNull, returnUndefined = _e.returnUndefined;
|
|
1229
1241
|
var colKey = col.key;
|
|
1230
|
-
if (returnNull)
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1242
|
+
if (returnNull || returnUndefined) {
|
|
1243
|
+
if (rel.type === 'toMany')
|
|
1244
|
+
row[colKey] = (returnNull ? null : undefined);
|
|
1245
|
+
else
|
|
1246
|
+
setMissingRelationToNull(row, colKey);
|
|
1247
|
+
}
|
|
1234
1248
|
else {
|
|
1235
1249
|
var entityType = rel.toEntity;
|
|
1236
1250
|
var toRepo_1 = otherRepo;
|
|
@@ -1245,14 +1259,12 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1245
1259
|
metadata: toRepo_1.metadata,
|
|
1246
1260
|
}, findOptions)
|
|
1247
1261
|
.then(function (result) {
|
|
1248
|
-
if (
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
: result[0]
|
|
1255
|
-
: 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];
|
|
1256
1268
|
});
|
|
1257
1269
|
}
|
|
1258
1270
|
};
|
|
@@ -1896,6 +1908,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1896
1908
|
this.instance = instance;
|
|
1897
1909
|
this.remult = remult;
|
|
1898
1910
|
this.isNewRow = isNewRow;
|
|
1911
|
+
this._skipRelationFieldSync = false;
|
|
1899
1912
|
this._isLoading = false;
|
|
1900
1913
|
this.lookups = new Map();
|
|
1901
1914
|
this.originalValues = {};
|
|
@@ -1955,7 +1968,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1955
1968
|
},
|
|
1956
1969
|
set: function (newVal) {
|
|
1957
1970
|
val_1 = newVal;
|
|
1958
|
-
if (newVal === undefined)
|
|
1971
|
+
if (newVal === undefined || _this._skipRelationFieldSync)
|
|
1959
1972
|
return;
|
|
1960
1973
|
var op = col.options;
|
|
1961
1974
|
if (op.field) {
|
|
@@ -2806,7 +2819,9 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2806
2819
|
finally { if (e_41) throw e_41.error; }
|
|
2807
2820
|
return [7 /*endfinally*/];
|
|
2808
2821
|
case 12:
|
|
2809
|
-
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
|
+
]);
|
|
2810
2825
|
this.saveOriginalData();
|
|
2811
2826
|
this._isNew = false;
|
|
2812
2827
|
return [2 /*return*/, this.instance];
|
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/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;
|