remult 0.23.2 → 0.23.4
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/graphql.js +2 -1
- package/esm/remult-knex/index.js +8 -0
- package/esm/remult-mongo.js +10 -4
- package/esm/server/expressBridge.js +39 -43
- package/esm/src/context.js +0 -2
- package/esm/src/data-api.js +1 -0
- package/esm/src/data-providers/array-entity-data-provider.js +14 -0
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +1 -0
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +9 -0
- package/esm/src/filter/filter-interfaces.d.ts +2 -0
- package/esm/src/filter/filter-interfaces.js +18 -0
- package/esm/src/live-query/SubscriptionServer.js +0 -1
- package/esm/src/remult3/RepositoryImplementation.js +1 -2
- package/esm/src/remult3/__updateEntityBasedOnWhere.js +1 -0
- package/esm/src/remult3/remult3.d.ts +10 -9
- package/esm/src/remult3/remult3.js +55 -38
- package/graphql.js +2 -1
- package/package.json +1 -1
- package/remult-knex/index.js +13 -0
- package/remult-mongo.js +14 -4
- package/server/expressBridge.js +89 -94
- package/src/context.js +0 -2
- package/src/data-api.js +1 -0
- package/src/data-providers/array-entity-data-provider.js +14 -0
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +1 -0
- package/src/filter/filter-consumer-bridge-to-sql-request.js +13 -0
- package/src/filter/filter-interfaces.d.ts +2 -0
- package/src/filter/filter-interfaces.js +21 -0
- package/src/live-query/SubscriptionServer.js +1 -4
- package/src/remult3/RepositoryImplementation.js +1 -2
- package/src/remult3/__updateEntityBasedOnWhere.js +1 -0
- package/src/remult3/remult3.d.ts +10 -9
- package/src/remult3/remult3.js +55 -38
package/esm/graphql.js
CHANGED
|
@@ -88,7 +88,7 @@ export function remultGraphql(options) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
if (whereType === 'String') {
|
|
91
|
-
for (const operator of ['contains']) {
|
|
91
|
+
for (const operator of ['contains', 'notContains']) {
|
|
92
92
|
const field = {
|
|
93
93
|
key: operator,
|
|
94
94
|
value: whereType,
|
|
@@ -820,6 +820,7 @@ export function translateWhereToRestBody(fields, { where }) {
|
|
|
820
820
|
tr('nin', (x) => (result[field.key + '.ne'] = x));
|
|
821
821
|
tr('eq', (x) => (result[field.key] = x));
|
|
822
822
|
tr('contains', (x) => (result[field.key + '.contains'] = x));
|
|
823
|
+
tr('notContains', (x) => (result[field.key + '.notContains'] = x));
|
|
823
824
|
}
|
|
824
825
|
}
|
|
825
826
|
if (where.OR) {
|
package/esm/remult-knex/index.js
CHANGED
|
@@ -296,6 +296,14 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
296
296
|
"%')"));
|
|
297
297
|
this.promises.push((async () => { })());
|
|
298
298
|
}
|
|
299
|
+
notContainsCaseInsensitive(col, val) {
|
|
300
|
+
this.result.push((b) => b.whereRaw('not lower (' +
|
|
301
|
+
b.client.ref(this.nameProvider.$dbNameOf(col)) +
|
|
302
|
+
") like lower ('%" +
|
|
303
|
+
val.replace(/'/g, "''") +
|
|
304
|
+
"%')"));
|
|
305
|
+
this.promises.push((async () => { })());
|
|
306
|
+
}
|
|
299
307
|
add(col, val, operator) {
|
|
300
308
|
this.result.push((b) => b.where(this.nameProvider.$dbNameOf(col), operator, translateValueAndHandleArrayAndHandleArray(col, val)));
|
|
301
309
|
}
|
package/esm/remult-mongo.js
CHANGED
|
@@ -246,10 +246,16 @@ class FilterConsumerBridgeToMongo {
|
|
|
246
246
|
}
|
|
247
247
|
containsCaseInsensitive(col, val) {
|
|
248
248
|
this.add(col, val, '$regex', { $options: 'i' });
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
}
|
|
250
|
+
notContainsCaseInsensitive(col, val) {
|
|
251
|
+
this.result.push(() => ({
|
|
252
|
+
[this.nameProvider.$dbNameOf(col)]: {
|
|
253
|
+
$not: {
|
|
254
|
+
$regex: isNull(val) ? val : toDb(col, val),
|
|
255
|
+
$options: 'i',
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
}));
|
|
253
259
|
}
|
|
254
260
|
add(col, val, operator, moreOptions) {
|
|
255
261
|
this.result.push(() => ({
|
|
@@ -31,43 +31,6 @@ export function createRemultServerCore(options, serverCoreOptions) {
|
|
|
31
31
|
if (options.ensureSchema === undefined)
|
|
32
32
|
options.ensureSchema = true;
|
|
33
33
|
RemultAsyncLocalStorage.enable();
|
|
34
|
-
const entitiesMetaData = [];
|
|
35
|
-
dataProvider = dataProvider.then(async (dp) => {
|
|
36
|
-
var remult = new Remult(dp);
|
|
37
|
-
await new Promise((res) => {
|
|
38
|
-
RemultAsyncLocalStorage.instance.run(remult, async () => {
|
|
39
|
-
if (options.ensureSchema) {
|
|
40
|
-
let started = false;
|
|
41
|
-
const startConsoleLog = () => {
|
|
42
|
-
if (started)
|
|
43
|
-
return;
|
|
44
|
-
started = true;
|
|
45
|
-
console.time('Schema ensured');
|
|
46
|
-
};
|
|
47
|
-
entitiesMetaData.push(...options.entities.map((e) => remult.repo(e).metadata));
|
|
48
|
-
if (dp.ensureSchema) {
|
|
49
|
-
startConsoleLog();
|
|
50
|
-
await dp.ensureSchema(entitiesMetaData);
|
|
51
|
-
}
|
|
52
|
-
for (const item of [
|
|
53
|
-
options.liveQueryStorage,
|
|
54
|
-
options.queueStorage,
|
|
55
|
-
]) {
|
|
56
|
-
if (item?.ensureSchema) {
|
|
57
|
-
startConsoleLog();
|
|
58
|
-
await item.ensureSchema();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (started)
|
|
62
|
-
console.timeEnd('Schema ensured');
|
|
63
|
-
}
|
|
64
|
-
if (options.initApi)
|
|
65
|
-
await options.initApi(remult);
|
|
66
|
-
res({});
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
return dp;
|
|
70
|
-
});
|
|
71
34
|
{
|
|
72
35
|
let allControllers = [];
|
|
73
36
|
if (!options.entities)
|
|
@@ -81,7 +44,7 @@ export function createRemultServerCore(options, serverCoreOptions) {
|
|
|
81
44
|
if (options.rootPath === undefined)
|
|
82
45
|
options.rootPath = '/api';
|
|
83
46
|
actionInfo.runningOnServer = true;
|
|
84
|
-
let bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider, serverCoreOptions
|
|
47
|
+
let bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider, serverCoreOptions);
|
|
85
48
|
return bridge;
|
|
86
49
|
}
|
|
87
50
|
/* @internal*/
|
|
@@ -90,18 +53,50 @@ export class RemultServerImplementation {
|
|
|
90
53
|
options;
|
|
91
54
|
dataProvider;
|
|
92
55
|
coreOptions;
|
|
93
|
-
entitiesMetaData;
|
|
94
56
|
liveQueryStorage = new InMemoryLiveQueryStorage();
|
|
95
|
-
constructor(queue, options, dataProvider, coreOptions
|
|
57
|
+
constructor(queue, options, dataProvider, coreOptions) {
|
|
96
58
|
this.queue = queue;
|
|
97
59
|
this.options = options;
|
|
98
60
|
this.dataProvider = dataProvider;
|
|
99
61
|
this.coreOptions = coreOptions;
|
|
100
|
-
this.entitiesMetaData = entitiesMetaData;
|
|
101
62
|
if (options.liveQueryStorage)
|
|
102
63
|
this.liveQueryStorage = options.liveQueryStorage;
|
|
103
64
|
if (options.subscriptionServer)
|
|
104
65
|
this.subscriptionServer = options.subscriptionServer;
|
|
66
|
+
const entitiesMetaData = [];
|
|
67
|
+
this.dataProvider = dataProvider.then(async (dp) => {
|
|
68
|
+
await this.runWithRemult(async (remult) => {
|
|
69
|
+
remult.dataProvider = dp;
|
|
70
|
+
if (options.ensureSchema) {
|
|
71
|
+
let started = false;
|
|
72
|
+
const startConsoleLog = () => {
|
|
73
|
+
if (started)
|
|
74
|
+
return;
|
|
75
|
+
started = true;
|
|
76
|
+
console.time('Schema ensured');
|
|
77
|
+
};
|
|
78
|
+
entitiesMetaData.push(...options.entities.map((e) => remult.repo(e).metadata));
|
|
79
|
+
if (dp.ensureSchema) {
|
|
80
|
+
startConsoleLog();
|
|
81
|
+
await dp.ensureSchema(entitiesMetaData);
|
|
82
|
+
}
|
|
83
|
+
for (const item of [
|
|
84
|
+
options.liveQueryStorage,
|
|
85
|
+
options.queueStorage,
|
|
86
|
+
]) {
|
|
87
|
+
if (item?.ensureSchema) {
|
|
88
|
+
startConsoleLog();
|
|
89
|
+
await item.ensureSchema();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (started)
|
|
93
|
+
console.timeEnd('Schema ensured');
|
|
94
|
+
}
|
|
95
|
+
if (options.initApi)
|
|
96
|
+
await options.initApi(remult);
|
|
97
|
+
}, { skipDataProvider: true });
|
|
98
|
+
return dp;
|
|
99
|
+
});
|
|
105
100
|
}
|
|
106
101
|
withRemultPromise(request, what) {
|
|
107
102
|
return new Promise((resolve, error) => {
|
|
@@ -250,10 +245,11 @@ export class RemultServerImplementation {
|
|
|
250
245
|
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, orig.params.id)));
|
|
251
246
|
}
|
|
252
247
|
//runs with remult but without init request
|
|
253
|
-
async runWithRemult(what) {
|
|
248
|
+
async runWithRemult(what, options) {
|
|
254
249
|
let remult = new Remult();
|
|
255
250
|
remult.liveQueryPublisher = new LiveQueryPublisher(() => remult.subscriptionServer, () => remult.liveQueryStorage, this.runWithSerializedJsonContextData);
|
|
256
|
-
|
|
251
|
+
if (!options?.skipDataProvider)
|
|
252
|
+
remult.dataProvider = await this.dataProvider;
|
|
257
253
|
remult.subscriptionServer = this.subscriptionServer;
|
|
258
254
|
remult.liveQueryStorage = this.liveQueryStorage;
|
|
259
255
|
await new Promise((res) => {
|
package/esm/src/context.js
CHANGED
|
@@ -286,5 +286,3 @@ class transactionLiveQueryPublisher {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
|
-
//p2 - when value changes for field with error, clear error - so the user will feel comfortable
|
|
290
|
-
//y2 - require filter argument - and perform validation checks for it - site, id etc.. changelog, status changes etc...,
|
package/esm/src/data-api.js
CHANGED
|
@@ -274,4 +274,18 @@ class FilterConsumerBridgeToObject {
|
|
|
274
274
|
if (s.toLowerCase().indexOf(val) < 0)
|
|
275
275
|
this.ok = false;
|
|
276
276
|
}
|
|
277
|
+
notContainsCaseInsensitive(col, val) {
|
|
278
|
+
let v = this.row[this.dbNames.$dbNameOf(col)];
|
|
279
|
+
if (!v) {
|
|
280
|
+
this.ok = false;
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
let s = '' + v;
|
|
284
|
+
if (val)
|
|
285
|
+
val = col.valueConverter.toJson(val);
|
|
286
|
+
if (val)
|
|
287
|
+
val = val.toString().toLowerCase();
|
|
288
|
+
if (s.toLowerCase().indexOf(val) >= 0)
|
|
289
|
+
this.ok = false;
|
|
290
|
+
}
|
|
277
291
|
}
|
|
@@ -23,6 +23,7 @@ export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer
|
|
|
23
23
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
24
24
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
25
25
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
26
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
26
27
|
private add;
|
|
27
28
|
private addToWhere;
|
|
28
29
|
databaseCustom(databaseCustom: CustomSqlFilterObject): void;
|
|
@@ -93,6 +93,15 @@ export class FilterConsumerBridgeToSqlRequest {
|
|
|
93
93
|
"%')");
|
|
94
94
|
})());
|
|
95
95
|
}
|
|
96
|
+
notContainsCaseInsensitive(col, val) {
|
|
97
|
+
this.promises.push((async () => {
|
|
98
|
+
this.addToWhere('not lower (' +
|
|
99
|
+
this.nameProvider.$dbNameOf(col) +
|
|
100
|
+
") like lower ('%" +
|
|
101
|
+
val.replace(/'/g, "''") +
|
|
102
|
+
"%')");
|
|
103
|
+
})());
|
|
104
|
+
}
|
|
96
105
|
add(col, val, operator) {
|
|
97
106
|
this.promises.push((async () => {
|
|
98
107
|
let x = this.nameProvider.$dbNameOf(col) +
|
|
@@ -25,6 +25,7 @@ export interface FilterConsumer {
|
|
|
25
25
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
26
26
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
27
27
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
28
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
28
29
|
isIn(col: FieldMetadata, val: any[]): void;
|
|
29
30
|
custom(key: string, customItem: any): void;
|
|
30
31
|
databaseCustom(databaseCustom: any): void;
|
|
@@ -58,6 +59,7 @@ export declare class FilterSerializer implements FilterConsumer {
|
|
|
58
59
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
59
60
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
60
61
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
62
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
61
63
|
}
|
|
62
64
|
export declare function entityFilterToJson<T>(entityDefs: EntityMetadata<T>, where: EntityFilter<T>): any;
|
|
63
65
|
export declare function buildFilterFromRequestParameters(entity: EntityMetadata, filterInfo: {
|
|
@@ -101,6 +101,10 @@ export class Filter {
|
|
|
101
101
|
found = true;
|
|
102
102
|
result.push(fh.contains(element));
|
|
103
103
|
break;
|
|
104
|
+
case '$notContains':
|
|
105
|
+
found = true;
|
|
106
|
+
result.push(fh.notContains(element));
|
|
107
|
+
break;
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
}
|
|
@@ -171,6 +175,9 @@ class filterHelper {
|
|
|
171
175
|
contains(val) {
|
|
172
176
|
return new Filter((add) => add.containsCaseInsensitive(this.metadata, val));
|
|
173
177
|
}
|
|
178
|
+
notContains(val) {
|
|
179
|
+
return new Filter((add) => add.notContainsCaseInsensitive(this.metadata, val));
|
|
180
|
+
}
|
|
174
181
|
isLessThan(val) {
|
|
175
182
|
val = this.processVal(val);
|
|
176
183
|
return new Filter((add) => add.isLessThan(this.metadata, val));
|
|
@@ -237,6 +244,9 @@ class manyToOneFilterHelper {
|
|
|
237
244
|
contains(val) {
|
|
238
245
|
throw new Error('Invalid for Many To One Relation Field');
|
|
239
246
|
}
|
|
247
|
+
notContains(val) {
|
|
248
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
249
|
+
}
|
|
240
250
|
isLessThan(val) {
|
|
241
251
|
throw new Error('Invalid for Many To One Relation Field');
|
|
242
252
|
}
|
|
@@ -383,6 +393,9 @@ export class FilterSerializer {
|
|
|
383
393
|
containsCaseInsensitive(col, val) {
|
|
384
394
|
this.add(col.key + '.contains', val);
|
|
385
395
|
}
|
|
396
|
+
notContainsCaseInsensitive(col, val) {
|
|
397
|
+
this.add(col.key + '.notContains', val);
|
|
398
|
+
}
|
|
386
399
|
}
|
|
387
400
|
export function entityFilterToJson(entityDefs, where) {
|
|
388
401
|
if (!where)
|
|
@@ -452,6 +465,7 @@ export function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
452
465
|
}
|
|
453
466
|
}
|
|
454
467
|
addFilter('.contains', (val) => ({ $contains: val }), false, true);
|
|
468
|
+
addFilter('.notContains', (val) => ({ $notContains: val }), false, true);
|
|
455
469
|
});
|
|
456
470
|
let val = filterInfo.get('OR');
|
|
457
471
|
if (val) {
|
|
@@ -555,6 +569,9 @@ class customTranslator {
|
|
|
555
569
|
containsCaseInsensitive(col, val) {
|
|
556
570
|
this.commands.push((x) => x.containsCaseInsensitive(col, val));
|
|
557
571
|
}
|
|
572
|
+
notContainsCaseInsensitive(col, val) {
|
|
573
|
+
this.commands.push((x) => x.notContainsCaseInsensitive(col, val));
|
|
574
|
+
}
|
|
558
575
|
isIn(col, val) {
|
|
559
576
|
this.commands.push((x) => x.isIn(col, val));
|
|
560
577
|
}
|
|
@@ -587,6 +604,7 @@ export function __updateEntityBasedOnWhere(entityDefs, where, r) {
|
|
|
587
604
|
custom: emptyFunction,
|
|
588
605
|
databaseCustom: emptyFunction,
|
|
589
606
|
containsCaseInsensitive: emptyFunction,
|
|
607
|
+
notContainsCaseInsensitive: emptyFunction,
|
|
590
608
|
isDifferentFrom: emptyFunction,
|
|
591
609
|
isEqualTo: (col, val) => {
|
|
592
610
|
r[col.key] = val;
|
|
@@ -12,7 +12,6 @@ export class LiveQueryPublisher {
|
|
|
12
12
|
runPromise(p) { }
|
|
13
13
|
debugFileSaver = (x) => { };
|
|
14
14
|
async itemChanged(entityKey, changes) {
|
|
15
|
-
//TODO 2 - optimize so that the user will get their messages first. Based on user id
|
|
16
15
|
await this.liveQueryStorage().forEach(entityKey, async ({ query: q, setData }) => {
|
|
17
16
|
let query = { ...q.data };
|
|
18
17
|
await this.performWithContext(query.requestJson, entityKey, async (repo) => {
|
|
@@ -143,7 +143,6 @@ export class RepositoryImplementation {
|
|
|
143
143
|
this.idCache.set(id, row);
|
|
144
144
|
return await row;
|
|
145
145
|
}
|
|
146
|
-
//TODO2 - Used to prevent unnecessary many to one relations
|
|
147
146
|
addToCache(item) {
|
|
148
147
|
if (item)
|
|
149
148
|
this.idCache.set(this.getEntityRef(item).getId() + '', item);
|
|
@@ -1804,7 +1803,7 @@ class EntityFullInfo {
|
|
|
1804
1803
|
}
|
|
1805
1804
|
get apiReadAllowed() {
|
|
1806
1805
|
if (this.options.allowApiRead === undefined)
|
|
1807
|
-
return true;
|
|
1806
|
+
return true;
|
|
1808
1807
|
return this.remult.isAllowed(this.options.allowApiRead);
|
|
1809
1808
|
}
|
|
1810
1809
|
apiDeleteAllowed(item) {
|
|
@@ -7,6 +7,7 @@ export function __updateEntityBasedOnWhere(entityDefs, where, r) {
|
|
|
7
7
|
custom: emptyFunction,
|
|
8
8
|
databaseCustom: emptyFunction,
|
|
9
9
|
containsCaseInsensitive: emptyFunction,
|
|
10
|
+
notContainsCaseInsensitive: emptyFunction,
|
|
10
11
|
isDifferentFrom: emptyFunction,
|
|
11
12
|
isEqualTo: (col, val) => {
|
|
12
13
|
r[col.key] = val;
|
|
@@ -388,6 +388,7 @@ export type ComparisonValueFilter<valueType> = ValueFilter<valueType> & {
|
|
|
388
388
|
};
|
|
389
389
|
export interface ContainsStringValueFilter {
|
|
390
390
|
$contains?: string;
|
|
391
|
+
$notContains?: string;
|
|
391
392
|
}
|
|
392
393
|
export type IdFilter<valueType> = ValueFilter<valueType> | {
|
|
393
394
|
$id: ValueFilter<valueType extends {
|
|
@@ -579,21 +580,21 @@ export type ClassFieldDecorator<entityType, valueType> = (target: any, context:
|
|
|
579
580
|
remult.apiClient.httpClient = (
|
|
580
581
|
input: RequestInfo | URL,
|
|
581
582
|
init?: RequestInit
|
|
582
|
-
) => {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
583
|
+
) => {
|
|
584
|
+
return fetch(input, {
|
|
585
|
+
...init,
|
|
586
|
+
headers: {
|
|
587
|
+
authorization: 'Bearer ' + sessionStorage.sessionId,
|
|
588
|
+
},
|
|
589
|
+
cache: 'no-store',
|
|
590
|
+
})
|
|
590
591
|
}
|
|
591
592
|
|
|
592
593
|
&&
|
|
593
594
|
remult.apiClient.url='localhost:3007/api
|
|
594
595
|
|
|
595
596
|
|
|
596
|
-
|
|
597
|
+
*/
|
|
597
598
|
/**
|
|
598
599
|
* our default is allow null false.
|
|
599
600
|
* for sql databases we add a db default of 0/''/false
|
|
@@ -1,58 +1,73 @@
|
|
|
1
1
|
export {};
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
//p1 - not contains - meni request
|
|
3
|
+
//p1 - sql-expression for knex
|
|
4
|
+
//p1 - postgres case sensitive
|
|
5
|
+
//p1 - filterToRaw should get a dbnames of - and we should create a dbnames of that supports an alias
|
|
6
|
+
/*p1 - with remult async for remultexpress
|
|
7
|
+
rename withremultpromise to that withRemultAsync
|
|
8
|
+
expose live query storage in remult
|
|
9
|
+
|
|
10
|
+
request optional - and depends on that run `getUser` & `initRequest`
|
|
11
|
+
*/
|
|
12
|
+
//y1 - consider moving the request to be second parameter of with remult async
|
|
13
|
+
//y1 - Add a with remult promise to Remult!
|
|
14
|
+
//y1 - Backend methods are transactions, it's not intuitive and maybe should be optional / opt in
|
|
15
|
+
//y1 - how to run a transaction as a user
|
|
16
|
+
//p1 - enum column
|
|
17
|
+
//p1 - fix sql log to console to make more sense
|
|
18
|
+
//p1 - add schema option to create postgres data provider
|
|
19
|
+
//p1 - find one i had a question about find first's different syntax from find that confused a user
|
|
20
|
+
//p1 - I think there should be a way to throw a forbidden exception
|
|
21
|
+
//y1 - Write some ctrl g
|
|
22
|
+
//y1 - get backend methods to work when specifying types for date, and entities as poco's
|
|
23
|
+
//y1 - required
|
|
24
|
+
//y1 - reconsider validators
|
|
25
|
+
//y1 - message for invalid valie
|
|
26
|
+
//y1 - message for relation that is missing
|
|
27
|
+
//p1 - more column types
|
|
28
|
+
//p2 - processError in remult express
|
|
29
|
+
//p2 - allow find options preprocessor for api calls, to use for authorization
|
|
30
|
+
//p1 - write doc about controlling updates of rows...
|
|
31
|
+
//p1 - need a way to extract the fields from the relation - for generating relation based sql
|
|
32
|
+
//p1 - add docs for apply changes
|
|
33
|
+
//p1 - when subscribe is forbidden - the query still runs after the renew process
|
|
34
|
+
//p1 - JSON FIELD LOST JSON STORAGE WHEN SET INPUT VALUE
|
|
35
|
+
//p1 - 'update tasks set where id = $1
|
|
36
|
+
//y2 - consider multi tenancies
|
|
37
|
+
//y2 - allow api read to also support instance and filter. - problem with promise
|
|
38
|
+
//p1 - doc this:
|
|
10
39
|
/**
|
|
11
40
|
* //p2 - doc this
|
|
12
41
|
remult.apiClient.httpClient = (
|
|
13
42
|
input: RequestInfo | URL,
|
|
14
43
|
init?: RequestInit
|
|
15
|
-
) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
) => {
|
|
45
|
+
return fetch(input, {
|
|
46
|
+
...init,
|
|
47
|
+
headers: {
|
|
48
|
+
authorization: 'Bearer ' + sessionStorage.sessionId,
|
|
49
|
+
},
|
|
50
|
+
cache: 'no-store',
|
|
51
|
+
})
|
|
23
52
|
}
|
|
24
53
|
|
|
25
54
|
&&
|
|
26
55
|
remult.apiClient.url='localhost:3007/api
|
|
27
56
|
|
|
28
57
|
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//p2 - with remult for remultexpress
|
|
36
|
-
//p2 - Add a with remult promise to Remult!
|
|
37
|
-
//p2 - filterToRaw should get a dbnames of - and we should create a dbnames of that supports an alias
|
|
58
|
+
*/
|
|
59
|
+
//y2 - discuss a default date formatter
|
|
60
|
+
//y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
|
|
61
|
+
//y2 - live query refresh of view on table update
|
|
62
|
+
//y2 - Operator '>' cannot be applied to types 'Number' and 'number'.ts(2365) - change fields to <entityType,number> (now it's Number)
|
|
63
|
+
//y2 - Field(()=>String) - doesn't play nice with strict mode - it prevents people from extending basic types
|
|
38
64
|
//y2 - livequery for findfirst (@JY)
|
|
39
65
|
//y2 - #239 - (@JY) add a way to get from fieldMetadata back to entity repo (like we have in fieldRef)
|
|
40
66
|
//p2 - constraints (@JY)
|
|
41
|
-
//p2 - Add ability to process query that comes from the api
|
|
42
|
-
//p2 - too much data by mistake
|
|
43
|
-
//p2 - postgres case sensitive
|
|
44
|
-
//p2 - fix sql log to console to make more sense
|
|
45
67
|
//p2 - type metadata.key - to keyof entity - based on cwis input
|
|
46
|
-
//p2 - processError in remult express
|
|
47
|
-
//y2 - Backend methods are transactions, it's not intuitive and maybe should be optional / opt in
|
|
48
|
-
//p2 - get backend methods to work when specifying types for date, and entities as poco's
|
|
49
|
-
//p2 - allow find options preprocessor for api calls, to use for authorization
|
|
50
68
|
//y2 - remove __dirname from tutorials
|
|
51
|
-
//
|
|
52
|
-
//y2 - I tihnk there should be a way to throw a forbidden exception
|
|
69
|
+
//p2 - when value changes for field with error, clear error - so the user will feel comfortable
|
|
53
70
|
//p2 - conside law-q db based on schema issue - I think that while running the dataProvider function, we should have a valid remult - maybe even have a valid remult, that will be valid until api is run
|
|
54
|
-
//p2 - allow api read to also support instance and filter.
|
|
55
|
-
//p2 - investigate why did lawq didn't run after build - even though it ran with tsx
|
|
56
71
|
//y2 - we should really reconsider allow null by default to be true - I think that what we're doing is confusing for most . In my case I added a volunteer relation, and didn't set any value to it - and I get an error that null value is not allowed for it
|
|
57
72
|
/**
|
|
58
73
|
* our default is allow null false.
|
|
@@ -61,5 +76,7 @@ remult.apiClient.url='localhost:3007/api
|
|
|
61
76
|
* we do not enforce allow null false (mongo, json it'll get stored)
|
|
62
77
|
|
|
63
78
|
*/
|
|
64
|
-
//y2 - i had a question about find first's different syntax from find that confused a user
|
|
65
79
|
//p2 - allowApiUpdate should be false for include in api false
|
|
80
|
+
//[ ] V2 - what to do about for relations count?
|
|
81
|
+
//[ ] V2 - condition? not to fetch if null etc....
|
|
82
|
+
//[ ] V3 - all these fields will also appear in the where etc... in the typescript api - but we will not enforce them
|
package/graphql.js
CHANGED
|
@@ -118,7 +118,7 @@ function remultGraphql(options) {
|
|
|
118
118
|
}
|
|
119
119
|
if (whereType === 'String') {
|
|
120
120
|
try {
|
|
121
|
-
for (var _p = (e_4 = void 0, tslib_1.__values(['contains'])), _q = _p.next(); !_q.done; _q = _p.next()) {
|
|
121
|
+
for (var _p = (e_4 = void 0, tslib_1.__values(['contains', 'notContains'])), _q = _p.next(); !_q.done; _q = _p.next()) {
|
|
122
122
|
var operator = _q.value;
|
|
123
123
|
var field = {
|
|
124
124
|
key: operator,
|
|
@@ -944,6 +944,7 @@ function translateWhereToRestBody(fields, _a) {
|
|
|
944
944
|
tr('nin', function (x) { return (result[field.key + '.ne'] = x); });
|
|
945
945
|
tr('eq', function (x) { return (result[field.key] = x); });
|
|
946
946
|
tr('contains', function (x) { return (result[field.key + '.contains'] = x); });
|
|
947
|
+
tr('notContains', function (x) { return (result[field.key + '.notContains'] = x); });
|
|
947
948
|
}
|
|
948
949
|
};
|
|
949
950
|
try {
|
package/package.json
CHANGED
package/remult-knex/index.js
CHANGED
|
@@ -575,6 +575,19 @@ var FilterConsumerBridgeToKnexRequest = /** @class */ (function () {
|
|
|
575
575
|
return [2 /*return*/];
|
|
576
576
|
}); }); })());
|
|
577
577
|
};
|
|
578
|
+
FilterConsumerBridgeToKnexRequest.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
579
|
+
var _this = this;
|
|
580
|
+
this.result.push(function (b) {
|
|
581
|
+
return b.whereRaw('not lower (' +
|
|
582
|
+
b.client.ref(_this.nameProvider.$dbNameOf(col)) +
|
|
583
|
+
") like lower ('%" +
|
|
584
|
+
val.replace(/'/g, "''") +
|
|
585
|
+
"%')");
|
|
586
|
+
});
|
|
587
|
+
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
|
|
588
|
+
return [2 /*return*/];
|
|
589
|
+
}); }); })());
|
|
590
|
+
};
|
|
578
591
|
FilterConsumerBridgeToKnexRequest.prototype.add = function (col, val, operator) {
|
|
579
592
|
var _this = this;
|
|
580
593
|
this.result.push(function (b) {
|
package/remult-mongo.js
CHANGED
|
@@ -488,10 +488,20 @@ var FilterConsumerBridgeToMongo = /** @class */ (function () {
|
|
|
488
488
|
};
|
|
489
489
|
FilterConsumerBridgeToMongo.prototype.containsCaseInsensitive = function (col, val) {
|
|
490
490
|
this.add(col, val, '$regex', { $options: 'i' });
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
491
|
+
};
|
|
492
|
+
FilterConsumerBridgeToMongo.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
493
|
+
var _this = this;
|
|
494
|
+
this.result.push(function () {
|
|
495
|
+
var _a;
|
|
496
|
+
return (_a = {},
|
|
497
|
+
_a[_this.nameProvider.$dbNameOf(col)] = {
|
|
498
|
+
$not: {
|
|
499
|
+
$regex: isNull(val) ? val : toDb(col, val),
|
|
500
|
+
$options: 'i',
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
_a);
|
|
504
|
+
});
|
|
495
505
|
};
|
|
496
506
|
FilterConsumerBridgeToMongo.prototype.add = function (col, val, operator, moreOptions) {
|
|
497
507
|
var _this = this;
|
package/server/expressBridge.js
CHANGED
|
@@ -15,7 +15,6 @@ var server_action_1 = require("../src/server-action");
|
|
|
15
15
|
var server_action_info_1 = require("../src/server-action-info");
|
|
16
16
|
var initDataProvider_1 = require("./initDataProvider");
|
|
17
17
|
function createRemultServerCore(options, serverCoreOptions) {
|
|
18
|
-
var _this = this;
|
|
19
18
|
if (!options) {
|
|
20
19
|
options = {};
|
|
21
20
|
}
|
|
@@ -35,89 +34,6 @@ function createRemultServerCore(options, serverCoreOptions) {
|
|
|
35
34
|
if (options.ensureSchema === undefined)
|
|
36
35
|
options.ensureSchema = true;
|
|
37
36
|
context_1.RemultAsyncLocalStorage.enable();
|
|
38
|
-
var entitiesMetaData = [];
|
|
39
|
-
dataProvider = dataProvider.then(function (dp) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
40
|
-
var remult;
|
|
41
|
-
var _this = this;
|
|
42
|
-
return tslib_1.__generator(this, function (_a) {
|
|
43
|
-
switch (_a.label) {
|
|
44
|
-
case 0:
|
|
45
|
-
remult = new context_1.Remult(dp);
|
|
46
|
-
return [4 /*yield*/, new Promise(function (res) {
|
|
47
|
-
context_1.RemultAsyncLocalStorage.instance.run(remult, function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
48
|
-
var started_1, startConsoleLog, _a, _b, item, e_1_1;
|
|
49
|
-
var e_1, _c;
|
|
50
|
-
return tslib_1.__generator(this, function (_d) {
|
|
51
|
-
switch (_d.label) {
|
|
52
|
-
case 0:
|
|
53
|
-
if (!options.ensureSchema) return [3 /*break*/, 10];
|
|
54
|
-
started_1 = false;
|
|
55
|
-
startConsoleLog = function () {
|
|
56
|
-
if (started_1)
|
|
57
|
-
return;
|
|
58
|
-
started_1 = true;
|
|
59
|
-
console.time('Schema ensured');
|
|
60
|
-
};
|
|
61
|
-
entitiesMetaData.push.apply(entitiesMetaData, tslib_1.__spreadArray([], tslib_1.__read(options.entities.map(function (e) { return remult.repo(e).metadata; })), false));
|
|
62
|
-
if (!dp.ensureSchema) return [3 /*break*/, 2];
|
|
63
|
-
startConsoleLog();
|
|
64
|
-
return [4 /*yield*/, dp.ensureSchema(entitiesMetaData)];
|
|
65
|
-
case 1:
|
|
66
|
-
_d.sent();
|
|
67
|
-
_d.label = 2;
|
|
68
|
-
case 2:
|
|
69
|
-
_d.trys.push([2, 7, 8, 9]);
|
|
70
|
-
_a = tslib_1.__values([
|
|
71
|
-
options.liveQueryStorage,
|
|
72
|
-
options.queueStorage,
|
|
73
|
-
]), _b = _a.next();
|
|
74
|
-
_d.label = 3;
|
|
75
|
-
case 3:
|
|
76
|
-
if (!!_b.done) return [3 /*break*/, 6];
|
|
77
|
-
item = _b.value;
|
|
78
|
-
if (!(item === null || item === void 0 ? void 0 : item.ensureSchema)) return [3 /*break*/, 5];
|
|
79
|
-
startConsoleLog();
|
|
80
|
-
return [4 /*yield*/, item.ensureSchema()];
|
|
81
|
-
case 4:
|
|
82
|
-
_d.sent();
|
|
83
|
-
_d.label = 5;
|
|
84
|
-
case 5:
|
|
85
|
-
_b = _a.next();
|
|
86
|
-
return [3 /*break*/, 3];
|
|
87
|
-
case 6: return [3 /*break*/, 9];
|
|
88
|
-
case 7:
|
|
89
|
-
e_1_1 = _d.sent();
|
|
90
|
-
e_1 = { error: e_1_1 };
|
|
91
|
-
return [3 /*break*/, 9];
|
|
92
|
-
case 8:
|
|
93
|
-
try {
|
|
94
|
-
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
95
|
-
}
|
|
96
|
-
finally { if (e_1) throw e_1.error; }
|
|
97
|
-
return [7 /*endfinally*/];
|
|
98
|
-
case 9:
|
|
99
|
-
if (started_1)
|
|
100
|
-
console.timeEnd('Schema ensured');
|
|
101
|
-
_d.label = 10;
|
|
102
|
-
case 10:
|
|
103
|
-
if (!options.initApi) return [3 /*break*/, 12];
|
|
104
|
-
return [4 /*yield*/, options.initApi(remult)];
|
|
105
|
-
case 11:
|
|
106
|
-
_d.sent();
|
|
107
|
-
_d.label = 12;
|
|
108
|
-
case 12:
|
|
109
|
-
res({});
|
|
110
|
-
return [2 /*return*/];
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}); });
|
|
114
|
-
})];
|
|
115
|
-
case 1:
|
|
116
|
-
_a.sent();
|
|
117
|
-
return [2 /*return*/, dp];
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}); });
|
|
121
37
|
{
|
|
122
38
|
var allControllers = [];
|
|
123
39
|
if (!options.entities)
|
|
@@ -131,23 +47,22 @@ function createRemultServerCore(options, serverCoreOptions) {
|
|
|
131
47
|
if (options.rootPath === undefined)
|
|
132
48
|
options.rootPath = '/api';
|
|
133
49
|
server_action_info_1.actionInfo.runningOnServer = true;
|
|
134
|
-
var bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider, serverCoreOptions
|
|
50
|
+
var bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider, serverCoreOptions);
|
|
135
51
|
return bridge;
|
|
136
52
|
}
|
|
137
53
|
exports.createRemultServerCore = createRemultServerCore;
|
|
138
54
|
/* @internal*/
|
|
139
55
|
var RemultServerImplementation = /** @class */ (function () {
|
|
140
|
-
function RemultServerImplementation(queue, options, dataProvider, coreOptions
|
|
56
|
+
function RemultServerImplementation(queue, options, dataProvider, coreOptions) {
|
|
141
57
|
var _this = this;
|
|
142
58
|
this.queue = queue;
|
|
143
59
|
this.options = options;
|
|
144
60
|
this.dataProvider = dataProvider;
|
|
145
61
|
this.coreOptions = coreOptions;
|
|
146
|
-
this.entitiesMetaData = entitiesMetaData;
|
|
147
62
|
this.liveQueryStorage = new SubscriptionServer_1.InMemoryLiveQueryStorage();
|
|
148
63
|
this.runWithSerializedJsonContextData = function (jsonContextData, entityKey, what) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
149
|
-
var _loop_1, this_1, _a, _b, e, state_1,
|
|
150
|
-
var
|
|
64
|
+
var _loop_1, this_1, _a, _b, e, state_1, e_1_1;
|
|
65
|
+
var e_1, _c;
|
|
151
66
|
var _this = this;
|
|
152
67
|
return tslib_1.__generator(this, function (_d) {
|
|
153
68
|
switch (_d.label) {
|
|
@@ -211,14 +126,14 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
211
126
|
return [3 /*break*/, 2];
|
|
212
127
|
case 5: return [3 /*break*/, 8];
|
|
213
128
|
case 6:
|
|
214
|
-
|
|
215
|
-
|
|
129
|
+
e_1_1 = _d.sent();
|
|
130
|
+
e_1 = { error: e_1_1 };
|
|
216
131
|
return [3 /*break*/, 8];
|
|
217
132
|
case 7:
|
|
218
133
|
try {
|
|
219
134
|
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
220
135
|
}
|
|
221
|
-
finally { if (
|
|
136
|
+
finally { if (e_1) throw e_1.error; }
|
|
222
137
|
return [7 /*endfinally*/];
|
|
223
138
|
case 8: throw new Error("Couldn't find entity " + entityKey);
|
|
224
139
|
}
|
|
@@ -240,6 +155,83 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
240
155
|
this.liveQueryStorage = options.liveQueryStorage;
|
|
241
156
|
if (options.subscriptionServer)
|
|
242
157
|
this.subscriptionServer = options.subscriptionServer;
|
|
158
|
+
var entitiesMetaData = [];
|
|
159
|
+
this.dataProvider = dataProvider.then(function (dp) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
160
|
+
var _this = this;
|
|
161
|
+
return tslib_1.__generator(this, function (_a) {
|
|
162
|
+
switch (_a.label) {
|
|
163
|
+
case 0: return [4 /*yield*/, this.runWithRemult(function (remult) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
164
|
+
var started_1, startConsoleLog, _a, _b, item, e_2_1;
|
|
165
|
+
var e_2, _c;
|
|
166
|
+
return tslib_1.__generator(this, function (_d) {
|
|
167
|
+
switch (_d.label) {
|
|
168
|
+
case 0:
|
|
169
|
+
remult.dataProvider = dp;
|
|
170
|
+
if (!options.ensureSchema) return [3 /*break*/, 10];
|
|
171
|
+
started_1 = false;
|
|
172
|
+
startConsoleLog = function () {
|
|
173
|
+
if (started_1)
|
|
174
|
+
return;
|
|
175
|
+
started_1 = true;
|
|
176
|
+
console.time('Schema ensured');
|
|
177
|
+
};
|
|
178
|
+
entitiesMetaData.push.apply(entitiesMetaData, tslib_1.__spreadArray([], tslib_1.__read(options.entities.map(function (e) { return remult.repo(e).metadata; })), false));
|
|
179
|
+
if (!dp.ensureSchema) return [3 /*break*/, 2];
|
|
180
|
+
startConsoleLog();
|
|
181
|
+
return [4 /*yield*/, dp.ensureSchema(entitiesMetaData)];
|
|
182
|
+
case 1:
|
|
183
|
+
_d.sent();
|
|
184
|
+
_d.label = 2;
|
|
185
|
+
case 2:
|
|
186
|
+
_d.trys.push([2, 7, 8, 9]);
|
|
187
|
+
_a = tslib_1.__values([
|
|
188
|
+
options.liveQueryStorage,
|
|
189
|
+
options.queueStorage,
|
|
190
|
+
]), _b = _a.next();
|
|
191
|
+
_d.label = 3;
|
|
192
|
+
case 3:
|
|
193
|
+
if (!!_b.done) return [3 /*break*/, 6];
|
|
194
|
+
item = _b.value;
|
|
195
|
+
if (!(item === null || item === void 0 ? void 0 : item.ensureSchema)) return [3 /*break*/, 5];
|
|
196
|
+
startConsoleLog();
|
|
197
|
+
return [4 /*yield*/, item.ensureSchema()];
|
|
198
|
+
case 4:
|
|
199
|
+
_d.sent();
|
|
200
|
+
_d.label = 5;
|
|
201
|
+
case 5:
|
|
202
|
+
_b = _a.next();
|
|
203
|
+
return [3 /*break*/, 3];
|
|
204
|
+
case 6: return [3 /*break*/, 9];
|
|
205
|
+
case 7:
|
|
206
|
+
e_2_1 = _d.sent();
|
|
207
|
+
e_2 = { error: e_2_1 };
|
|
208
|
+
return [3 /*break*/, 9];
|
|
209
|
+
case 8:
|
|
210
|
+
try {
|
|
211
|
+
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
212
|
+
}
|
|
213
|
+
finally { if (e_2) throw e_2.error; }
|
|
214
|
+
return [7 /*endfinally*/];
|
|
215
|
+
case 9:
|
|
216
|
+
if (started_1)
|
|
217
|
+
console.timeEnd('Schema ensured');
|
|
218
|
+
_d.label = 10;
|
|
219
|
+
case 10:
|
|
220
|
+
if (!options.initApi) return [3 /*break*/, 12];
|
|
221
|
+
return [4 /*yield*/, options.initApi(remult)];
|
|
222
|
+
case 11:
|
|
223
|
+
_d.sent();
|
|
224
|
+
_d.label = 12;
|
|
225
|
+
case 12: return [2 /*return*/];
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}); }, { skipDataProvider: true })];
|
|
229
|
+
case 1:
|
|
230
|
+
_a.sent();
|
|
231
|
+
return [2 /*return*/, dp];
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}); });
|
|
243
235
|
}
|
|
244
236
|
RemultServerImplementation.prototype.withRemultPromise = function (request, what) {
|
|
245
237
|
var _this = this;
|
|
@@ -482,7 +474,7 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
482
474
|
}); }); }));
|
|
483
475
|
};
|
|
484
476
|
//runs with remult but without init request
|
|
485
|
-
RemultServerImplementation.prototype.runWithRemult = function (what) {
|
|
477
|
+
RemultServerImplementation.prototype.runWithRemult = function (what, options) {
|
|
486
478
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
487
479
|
var remult, _a;
|
|
488
480
|
var _this = this;
|
|
@@ -491,10 +483,13 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
491
483
|
case 0:
|
|
492
484
|
remult = new context_1.Remult();
|
|
493
485
|
remult.liveQueryPublisher = new SubscriptionServer_1.LiveQueryPublisher(function () { return remult.subscriptionServer; }, function () { return remult.liveQueryStorage; }, this.runWithSerializedJsonContextData);
|
|
486
|
+
if (!!(options === null || options === void 0 ? void 0 : options.skipDataProvider)) return [3 /*break*/, 2];
|
|
494
487
|
_a = remult;
|
|
495
488
|
return [4 /*yield*/, this.dataProvider];
|
|
496
489
|
case 1:
|
|
497
490
|
_a.dataProvider = _b.sent();
|
|
491
|
+
_b.label = 2;
|
|
492
|
+
case 2:
|
|
498
493
|
remult.subscriptionServer = this.subscriptionServer;
|
|
499
494
|
remult.liveQueryStorage = this.liveQueryStorage;
|
|
500
495
|
return [4 /*yield*/, new Promise(function (res) {
|
|
@@ -512,7 +507,7 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
512
507
|
});
|
|
513
508
|
}); });
|
|
514
509
|
})];
|
|
515
|
-
case
|
|
510
|
+
case 3:
|
|
516
511
|
_b.sent();
|
|
517
512
|
return [2 /*return*/];
|
|
518
513
|
}
|
package/src/context.js
CHANGED
|
@@ -450,5 +450,3 @@ var transactionLiveQueryPublisher = /** @class */ (function () {
|
|
|
450
450
|
};
|
|
451
451
|
return transactionLiveQueryPublisher;
|
|
452
452
|
}());
|
|
453
|
-
//p2 - when value changes for field with error, clear error - so the user will feel comfortable
|
|
454
|
-
//y2 - require filter argument - and perform validation checks for it - site, id etc.. changelog, status changes etc...,
|
package/src/data-api.js
CHANGED
|
@@ -134,6 +134,7 @@ var DataApi = /** @class */ (function () {
|
|
|
134
134
|
if (w) {
|
|
135
135
|
w.__applyToConsumer({
|
|
136
136
|
containsCaseInsensitive: function () { },
|
|
137
|
+
notContainsCaseInsensitive: function () { },
|
|
137
138
|
isDifferentFrom: function () { },
|
|
138
139
|
isEqualTo: function (col, val) {
|
|
139
140
|
if (_this.repository.metadata.idMetadata.isIdField(col))
|
|
@@ -423,5 +423,19 @@ var FilterConsumerBridgeToObject = /** @class */ (function () {
|
|
|
423
423
|
if (s.toLowerCase().indexOf(val) < 0)
|
|
424
424
|
this.ok = false;
|
|
425
425
|
};
|
|
426
|
+
FilterConsumerBridgeToObject.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
427
|
+
var v = this.row[this.dbNames.$dbNameOf(col)];
|
|
428
|
+
if (!v) {
|
|
429
|
+
this.ok = false;
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
var s = '' + v;
|
|
433
|
+
if (val)
|
|
434
|
+
val = col.valueConverter.toJson(val);
|
|
435
|
+
if (val)
|
|
436
|
+
val = val.toString().toLowerCase();
|
|
437
|
+
if (s.toLowerCase().indexOf(val) >= 0)
|
|
438
|
+
this.ok = false;
|
|
439
|
+
};
|
|
426
440
|
return FilterConsumerBridgeToObject;
|
|
427
441
|
}());
|
|
@@ -23,6 +23,7 @@ export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer
|
|
|
23
23
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
24
24
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
25
25
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
26
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
26
27
|
private add;
|
|
27
28
|
private addToWhere;
|
|
28
29
|
databaseCustom(databaseCustom: CustomSqlFilterObject): void;
|
|
@@ -175,6 +175,19 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
|
|
|
175
175
|
});
|
|
176
176
|
}); })());
|
|
177
177
|
};
|
|
178
|
+
FilterConsumerBridgeToSqlRequest.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
179
|
+
var _this = this;
|
|
180
|
+
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
181
|
+
return tslib_1.__generator(this, function (_a) {
|
|
182
|
+
this.addToWhere('not lower (' +
|
|
183
|
+
this.nameProvider.$dbNameOf(col) +
|
|
184
|
+
") like lower ('%" +
|
|
185
|
+
val.replace(/'/g, "''") +
|
|
186
|
+
"%')");
|
|
187
|
+
return [2 /*return*/];
|
|
188
|
+
});
|
|
189
|
+
}); })());
|
|
190
|
+
};
|
|
178
191
|
FilterConsumerBridgeToSqlRequest.prototype.add = function (col, val, operator) {
|
|
179
192
|
var _this = this;
|
|
180
193
|
this.promises.push((function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
@@ -25,6 +25,7 @@ export interface FilterConsumer {
|
|
|
25
25
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
26
26
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
27
27
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
28
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
28
29
|
isIn(col: FieldMetadata, val: any[]): void;
|
|
29
30
|
custom(key: string, customItem: any): void;
|
|
30
31
|
databaseCustom(databaseCustom: any): void;
|
|
@@ -58,6 +59,7 @@ export declare class FilterSerializer implements FilterConsumer {
|
|
|
58
59
|
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
59
60
|
isLessThan(col: FieldMetadata, val: any): void;
|
|
60
61
|
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
62
|
+
notContainsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
61
63
|
}
|
|
62
64
|
export declare function entityFilterToJson<T>(entityDefs: EntityMetadata<T>, where: EntityFilter<T>): any;
|
|
63
65
|
export declare function buildFilterFromRequestParameters(entity: EntityMetadata, filterInfo: {
|
|
@@ -114,6 +114,10 @@ var Filter = /** @class */ (function () {
|
|
|
114
114
|
found = true;
|
|
115
115
|
result.push(fh.contains(element));
|
|
116
116
|
break;
|
|
117
|
+
case '$notContains':
|
|
118
|
+
found = true;
|
|
119
|
+
result.push(fh.notContains(element));
|
|
120
|
+
break;
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
}
|
|
@@ -223,6 +227,12 @@ var filterHelper = /** @class */ (function () {
|
|
|
223
227
|
var _this = this;
|
|
224
228
|
return new Filter(function (add) { return add.containsCaseInsensitive(_this.metadata, val); });
|
|
225
229
|
};
|
|
230
|
+
filterHelper.prototype.notContains = function (val) {
|
|
231
|
+
var _this = this;
|
|
232
|
+
return new Filter(function (add) {
|
|
233
|
+
return add.notContainsCaseInsensitive(_this.metadata, val);
|
|
234
|
+
});
|
|
235
|
+
};
|
|
226
236
|
filterHelper.prototype.isLessThan = function (val) {
|
|
227
237
|
var _this = this;
|
|
228
238
|
val = this.processVal(val);
|
|
@@ -311,6 +321,9 @@ var manyToOneFilterHelper = /** @class */ (function () {
|
|
|
311
321
|
manyToOneFilterHelper.prototype.contains = function (val) {
|
|
312
322
|
throw new Error('Invalid for Many To One Relation Field');
|
|
313
323
|
};
|
|
324
|
+
manyToOneFilterHelper.prototype.notContains = function (val) {
|
|
325
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
326
|
+
};
|
|
314
327
|
manyToOneFilterHelper.prototype.isLessThan = function (val) {
|
|
315
328
|
throw new Error('Invalid for Many To One Relation Field');
|
|
316
329
|
};
|
|
@@ -494,6 +507,9 @@ var FilterSerializer = /** @class */ (function () {
|
|
|
494
507
|
FilterSerializer.prototype.containsCaseInsensitive = function (col, val) {
|
|
495
508
|
this.add(col.key + '.contains', val);
|
|
496
509
|
};
|
|
510
|
+
FilterSerializer.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
511
|
+
this.add(col.key + '.notContains', val);
|
|
512
|
+
};
|
|
497
513
|
return FilterSerializer;
|
|
498
514
|
}());
|
|
499
515
|
exports.FilterSerializer = FilterSerializer;
|
|
@@ -583,6 +599,7 @@ function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
583
599
|
}
|
|
584
600
|
}
|
|
585
601
|
addFilter('.contains', function (val) { return ({ $contains: val }); }, false, true);
|
|
602
|
+
addFilter('.notContains', function (val) { return ({ $notContains: val }); }, false, true);
|
|
586
603
|
});
|
|
587
604
|
var val = filterInfo.get('OR');
|
|
588
605
|
if (val) {
|
|
@@ -712,6 +729,9 @@ var customTranslator = /** @class */ (function () {
|
|
|
712
729
|
customTranslator.prototype.containsCaseInsensitive = function (col, val) {
|
|
713
730
|
this.commands.push(function (x) { return x.containsCaseInsensitive(col, val); });
|
|
714
731
|
};
|
|
732
|
+
customTranslator.prototype.notContainsCaseInsensitive = function (col, val) {
|
|
733
|
+
this.commands.push(function (x) { return x.notContainsCaseInsensitive(col, val); });
|
|
734
|
+
};
|
|
715
735
|
customTranslator.prototype.isIn = function (col, val) {
|
|
716
736
|
this.commands.push(function (x) { return x.isIn(col, val); });
|
|
717
737
|
};
|
|
@@ -766,6 +786,7 @@ function __updateEntityBasedOnWhere(entityDefs, where, r) {
|
|
|
766
786
|
custom: emptyFunction,
|
|
767
787
|
databaseCustom: emptyFunction,
|
|
768
788
|
containsCaseInsensitive: emptyFunction,
|
|
789
|
+
notContainsCaseInsensitive: emptyFunction,
|
|
769
790
|
isDifferentFrom: emptyFunction,
|
|
770
791
|
isEqualTo: function (col, val) {
|
|
771
792
|
r[col.key] = val;
|
|
@@ -17,9 +17,7 @@ var LiveQueryPublisher = /** @class */ (function () {
|
|
|
17
17
|
var _this = this;
|
|
18
18
|
return tslib_1.__generator(this, function (_a) {
|
|
19
19
|
switch (_a.label) {
|
|
20
|
-
case 0:
|
|
21
|
-
//TODO 2 - optimize so that the user will get their messages first. Based on user id
|
|
22
|
-
return [4 /*yield*/, this.liveQueryStorage().forEach(entityKey, function (_a) {
|
|
20
|
+
case 0: return [4 /*yield*/, this.liveQueryStorage().forEach(entityKey, function (_a) {
|
|
23
21
|
var q = _a.query, setData = _a.setData;
|
|
24
22
|
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
25
23
|
var query;
|
|
@@ -123,7 +121,6 @@ var LiveQueryPublisher = /** @class */ (function () {
|
|
|
123
121
|
});
|
|
124
122
|
})];
|
|
125
123
|
case 1:
|
|
126
|
-
//TODO 2 - optimize so that the user will get their messages first. Based on user id
|
|
127
124
|
_a.sent();
|
|
128
125
|
return [2 /*return*/];
|
|
129
126
|
}
|
|
@@ -195,7 +195,6 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
195
195
|
});
|
|
196
196
|
});
|
|
197
197
|
};
|
|
198
|
-
//TODO2 - Used to prevent unnecessary many to one relations
|
|
199
198
|
RepositoryImplementation.prototype.addToCache = function (item) {
|
|
200
199
|
if (item)
|
|
201
200
|
this.idCache.set(this.getEntityRef(item).getId() + '', item);
|
|
@@ -2961,7 +2960,7 @@ var EntityFullInfo = /** @class */ (function () {
|
|
|
2961
2960
|
Object.defineProperty(EntityFullInfo.prototype, "apiReadAllowed", {
|
|
2962
2961
|
get: function () {
|
|
2963
2962
|
if (this.options.allowApiRead === undefined)
|
|
2964
|
-
return true;
|
|
2963
|
+
return true;
|
|
2965
2964
|
return this.remult.isAllowed(this.options.allowApiRead);
|
|
2966
2965
|
},
|
|
2967
2966
|
enumerable: false,
|
|
@@ -10,6 +10,7 @@ function __updateEntityBasedOnWhere(entityDefs, where, r) {
|
|
|
10
10
|
custom: emptyFunction,
|
|
11
11
|
databaseCustom: emptyFunction,
|
|
12
12
|
containsCaseInsensitive: emptyFunction,
|
|
13
|
+
notContainsCaseInsensitive: emptyFunction,
|
|
13
14
|
isDifferentFrom: emptyFunction,
|
|
14
15
|
isEqualTo: function (col, val) {
|
|
15
16
|
r[col.key] = val;
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -388,6 +388,7 @@ export type ComparisonValueFilter<valueType> = ValueFilter<valueType> & {
|
|
|
388
388
|
};
|
|
389
389
|
export interface ContainsStringValueFilter {
|
|
390
390
|
$contains?: string;
|
|
391
|
+
$notContains?: string;
|
|
391
392
|
}
|
|
392
393
|
export type IdFilter<valueType> = ValueFilter<valueType> | {
|
|
393
394
|
$id: ValueFilter<valueType extends {
|
|
@@ -579,21 +580,21 @@ export type ClassFieldDecorator<entityType, valueType> = (target: any, context:
|
|
|
579
580
|
remult.apiClient.httpClient = (
|
|
580
581
|
input: RequestInfo | URL,
|
|
581
582
|
init?: RequestInit
|
|
582
|
-
) => {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
583
|
+
) => {
|
|
584
|
+
return fetch(input, {
|
|
585
|
+
...init,
|
|
586
|
+
headers: {
|
|
587
|
+
authorization: 'Bearer ' + sessionStorage.sessionId,
|
|
588
|
+
},
|
|
589
|
+
cache: 'no-store',
|
|
590
|
+
})
|
|
590
591
|
}
|
|
591
592
|
|
|
592
593
|
&&
|
|
593
594
|
remult.apiClient.url='localhost:3007/api
|
|
594
595
|
|
|
595
596
|
|
|
596
|
-
|
|
597
|
+
*/
|
|
597
598
|
/**
|
|
598
599
|
* our default is allow null false.
|
|
599
600
|
* for sql databases we add a db default of 0/''/false
|
package/src/remult3/remult3.js
CHANGED
|
@@ -1,59 +1,74 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
//p1 - not contains - meni request
|
|
4
|
+
//p1 - sql-expression for knex
|
|
5
|
+
//p1 - postgres case sensitive
|
|
6
|
+
//p1 - filterToRaw should get a dbnames of - and we should create a dbnames of that supports an alias
|
|
7
|
+
/*p1 - with remult async for remultexpress
|
|
8
|
+
rename withremultpromise to that withRemultAsync
|
|
9
|
+
expose live query storage in remult
|
|
10
|
+
|
|
11
|
+
request optional - and depends on that run `getUser` & `initRequest`
|
|
12
|
+
*/
|
|
13
|
+
//y1 - consider moving the request to be second parameter of with remult async
|
|
14
|
+
//y1 - Add a with remult promise to Remult!
|
|
15
|
+
//y1 - Backend methods are transactions, it's not intuitive and maybe should be optional / opt in
|
|
16
|
+
//y1 - how to run a transaction as a user
|
|
17
|
+
//p1 - enum column
|
|
18
|
+
//p1 - fix sql log to console to make more sense
|
|
19
|
+
//p1 - add schema option to create postgres data provider
|
|
20
|
+
//p1 - find one i had a question about find first's different syntax from find that confused a user
|
|
21
|
+
//p1 - I think there should be a way to throw a forbidden exception
|
|
22
|
+
//y1 - Write some ctrl g
|
|
23
|
+
//y1 - get backend methods to work when specifying types for date, and entities as poco's
|
|
24
|
+
//y1 - required
|
|
25
|
+
//y1 - reconsider validators
|
|
26
|
+
//y1 - message for invalid valie
|
|
27
|
+
//y1 - message for relation that is missing
|
|
28
|
+
//p1 - more column types
|
|
29
|
+
//p2 - processError in remult express
|
|
30
|
+
//p2 - allow find options preprocessor for api calls, to use for authorization
|
|
31
|
+
//p1 - write doc about controlling updates of rows...
|
|
32
|
+
//p1 - need a way to extract the fields from the relation - for generating relation based sql
|
|
33
|
+
//p1 - add docs for apply changes
|
|
34
|
+
//p1 - when subscribe is forbidden - the query still runs after the renew process
|
|
35
|
+
//p1 - JSON FIELD LOST JSON STORAGE WHEN SET INPUT VALUE
|
|
36
|
+
//p1 - 'update tasks set where id = $1
|
|
37
|
+
//y2 - consider multi tenancies
|
|
38
|
+
//y2 - allow api read to also support instance and filter. - problem with promise
|
|
39
|
+
//p1 - doc this:
|
|
11
40
|
/**
|
|
12
41
|
* //p2 - doc this
|
|
13
42
|
remult.apiClient.httpClient = (
|
|
14
43
|
input: RequestInfo | URL,
|
|
15
44
|
init?: RequestInit
|
|
16
|
-
) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
45
|
+
) => {
|
|
46
|
+
return fetch(input, {
|
|
47
|
+
...init,
|
|
48
|
+
headers: {
|
|
49
|
+
authorization: 'Bearer ' + sessionStorage.sessionId,
|
|
50
|
+
},
|
|
51
|
+
cache: 'no-store',
|
|
52
|
+
})
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
&&
|
|
27
56
|
remult.apiClient.url='localhost:3007/api
|
|
28
57
|
|
|
29
58
|
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//p2 - with remult for remultexpress
|
|
37
|
-
//p2 - Add a with remult promise to Remult!
|
|
38
|
-
//p2 - filterToRaw should get a dbnames of - and we should create a dbnames of that supports an alias
|
|
59
|
+
*/
|
|
60
|
+
//y2 - discuss a default date formatter
|
|
61
|
+
//y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
|
|
62
|
+
//y2 - live query refresh of view on table update
|
|
63
|
+
//y2 - Operator '>' cannot be applied to types 'Number' and 'number'.ts(2365) - change fields to <entityType,number> (now it's Number)
|
|
64
|
+
//y2 - Field(()=>String) - doesn't play nice with strict mode - it prevents people from extending basic types
|
|
39
65
|
//y2 - livequery for findfirst (@JY)
|
|
40
66
|
//y2 - #239 - (@JY) add a way to get from fieldMetadata back to entity repo (like we have in fieldRef)
|
|
41
67
|
//p2 - constraints (@JY)
|
|
42
|
-
//p2 - Add ability to process query that comes from the api
|
|
43
|
-
//p2 - too much data by mistake
|
|
44
|
-
//p2 - postgres case sensitive
|
|
45
|
-
//p2 - fix sql log to console to make more sense
|
|
46
68
|
//p2 - type metadata.key - to keyof entity - based on cwis input
|
|
47
|
-
//p2 - processError in remult express
|
|
48
|
-
//y2 - Backend methods are transactions, it's not intuitive and maybe should be optional / opt in
|
|
49
|
-
//p2 - get backend methods to work when specifying types for date, and entities as poco's
|
|
50
|
-
//p2 - allow find options preprocessor for api calls, to use for authorization
|
|
51
69
|
//y2 - remove __dirname from tutorials
|
|
52
|
-
//
|
|
53
|
-
//y2 - I tihnk there should be a way to throw a forbidden exception
|
|
70
|
+
//p2 - when value changes for field with error, clear error - so the user will feel comfortable
|
|
54
71
|
//p2 - conside law-q db based on schema issue - I think that while running the dataProvider function, we should have a valid remult - maybe even have a valid remult, that will be valid until api is run
|
|
55
|
-
//p2 - allow api read to also support instance and filter.
|
|
56
|
-
//p2 - investigate why did lawq didn't run after build - even though it ran with tsx
|
|
57
72
|
//y2 - we should really reconsider allow null by default to be true - I think that what we're doing is confusing for most . In my case I added a volunteer relation, and didn't set any value to it - and I get an error that null value is not allowed for it
|
|
58
73
|
/**
|
|
59
74
|
* our default is allow null false.
|
|
@@ -62,5 +77,7 @@ remult.apiClient.url='localhost:3007/api
|
|
|
62
77
|
* we do not enforce allow null false (mongo, json it'll get stored)
|
|
63
78
|
|
|
64
79
|
*/
|
|
65
|
-
//y2 - i had a question about find first's different syntax from find that confused a user
|
|
66
80
|
//p2 - allowApiUpdate should be false for include in api false
|
|
81
|
+
//[ ] V2 - what to do about for relations count?
|
|
82
|
+
//[ ] V2 - condition? not to fetch if null etc....
|
|
83
|
+
//[ ] V3 - all these fields will also appear in the where etc... in the typescript api - but we will not enforce them
|