remult 0.23.2 → 0.23.3

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 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) {
@@ -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
  }
@@ -246,10 +246,16 @@ class FilterConsumerBridgeToMongo {
246
246
  }
247
247
  containsCaseInsensitive(col, val) {
248
248
  this.add(col, val, '$regex', { $options: 'i' });
249
- // this.promises.push(col.getDbName().then(colName => {
250
- // this.result.push(b => b.whereRaw(
251
- // 'lower (' + colName + ") like lower ('%" + val.replace(/'/g, '\'\'') + "%')"));
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(() => ({
@@ -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...,
@@ -80,6 +80,7 @@ export class DataApi {
80
80
  if (w) {
81
81
  w.__applyToConsumer({
82
82
  containsCaseInsensitive: () => { },
83
+ notContainsCaseInsensitive: () => { },
83
84
  isDifferentFrom: () => { },
84
85
  isEqualTo: (col, val) => {
85
86
  if (this.repository.metadata.idMetadata.isIdField(col))
@@ -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; //TODO2 - consider that this default may be confusing, since it's different from all others.
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
- return fetch(input, {
584
- ...init,
585
- headers: {
586
- authorization: 'Bearer ' + sessionStorage.sessionId,
587
- },
588
- cache: 'no-store',
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
- //p2 - write doc about controlling updates of rows...
3
- //p2 - need a way to extract the fields from the relation - for generating relation based sql
4
- //p2 - add docs for apply changes
5
- //y2 - discuss a default date formatter
6
- //[ ] - consider using this in saving etc...
7
- //p2 - when subscribe is forbidden - the query still runs after the renew process
8
- //p2 - JSON FIELD LOST JSON STORAGE WHEN SET INPUT VALUE
9
- //p2 - doc this:
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
- return fetch(input, {
17
- ...init,
18
- headers: {
19
- authorization: 'Bearer ' + sessionStorage.sessionId,
20
- },
21
- cache: 'no-store',
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
- //p2 - with remult promise for remultexpress
31
- //p2 - 'update tasks set where id = $1
32
- //p2 - live query refresh of view on table update
33
- //p2 - Operator '>' cannot be applied to types 'Number' and 'number'.ts(2365) - change fields to <entityType,number> (now it's Number)
34
- //p2 - Field(()=>String) - doesn't play nice with strict mode - it prevents people from extending basic types
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
- //y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.23.2",
3
+ "version": "0.23.3",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "types": "index.d.ts",
6
6
  "module": "esm/index.js",
@@ -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
- // this.promises.push(col.getDbName().then(colName => {
492
- // this.result.push(b => b.whereRaw(
493
- // 'lower (' + colName + ") like lower ('%" + val.replace(/'/g, '\'\'') + "%')"));
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/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; //TODO2 - consider that this default may be confusing, since it's different from all others.
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;
@@ -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
- return fetch(input, {
584
- ...init,
585
- headers: {
586
- authorization: 'Bearer ' + sessionStorage.sessionId,
587
- },
588
- cache: 'no-store',
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,59 +1,74 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- //p2 - write doc about controlling updates of rows...
4
- //p2 - need a way to extract the fields from the relation - for generating relation based sql
5
- //p2 - add docs for apply changes
6
- //y2 - discuss a default date formatter
7
- //[ ] - consider using this in saving etc...
8
- //p2 - when subscribe is forbidden - the query still runs after the renew process
9
- //p2 - JSON FIELD LOST JSON STORAGE WHEN SET INPUT VALUE
10
- //p2 - doc this:
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
- return fetch(input, {
18
- ...init,
19
- headers: {
20
- authorization: 'Bearer ' + sessionStorage.sessionId,
21
- },
22
- cache: 'no-store',
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
- //p2 - with remult promise for remultexpress
32
- //p2 - 'update tasks set where id = $1
33
- //p2 - live query refresh of view on table update
34
- //p2 - Operator '>' cannot be applied to types 'Number' and 'number'.ts(2365) - change fields to <entityType,number> (now it's Number)
35
- //p2 - Field(()=>String) - doesn't play nice with strict mode - it prevents people from extending basic types
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
- //y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
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