remult 0.23.0-exp.35 → 0.23.0-exp.37

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/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { ClassType } from './classType';
2
2
  export type { ClassType } from './classType';
3
- export { MembersOnly, FieldsMetadata, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, QueryResult, QueryOptions, Repository, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, EntityRef, SortSegments, Paginator, LiveQuery, LiveQueryChangeInfo, Subscribable, RefSubscriber, RefSubscriberBase, RelationOptions, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, ClassFieldDecorator, ClassFieldDecoratorContextStub, //n1 consider removing in ts5
4
- LifecycleEvent, } from './src/remult3/remult3';
3
+ export { MembersOnly, FieldsMetadata, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, FindOptionsBase, QueryResult, QueryOptions, Repository, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, EntityRef, SortSegments, Paginator, LiveQuery, LiveQueryChangeInfo, Subscribable, RefSubscriber, RefSubscriberBase, RelationOptions, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, ClassFieldDecorator, ClassFieldDecoratorContextStub, //n1 consider removing in ts5
4
+ LifecycleEvent, FieldsRefBase, FieldsRefForEntityBase, RepositoryRelationsForEntityBase, ControllerRefForControllerBase, ControllerRefBase, ControllerRef, EntityRefForEntityBase, IdMetadata, FindFirstOptionsBase, } from './src/remult3/remult3';
5
5
  export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation';
6
6
  export { Entity } from './src/remult3/entity';
7
7
  export { getEntityRef } from './src/remult3/getEntityRef';
@@ -10,7 +10,7 @@ export { IdEntity } from './src/remult3/IdEntity';
10
10
  export { describeClass } from './src/remult3/DecoratorReplacer';
11
11
  export { EntityOptions } from './src/entity';
12
12
  export { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo, RestDataProviderHttpProvider, } from './src/data-interfaces';
13
- export { SqlCommand, SqlImplementation, SqlResult } from './src/sql-command';
13
+ export { SqlCommand, SqlCommandWithParameters, SqlImplementation, SqlResult, } from './src/sql-command';
14
14
  export { FieldMetadata, FieldOptions, FieldValidator, ValueConverter, ValueListItem, // reconsider, maybe it should go to remult angular as the abstraction ?
15
15
  ValueOrExpression, } from './src/column-interfaces';
16
16
  export { RestDataProvider } from './src/data-providers/rest-data-provider';
@@ -18,14 +18,14 @@ export { InMemoryDataProvider } from './src/data-providers/in-memory-database';
18
18
  export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider';
19
19
  export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider';
20
20
  export { SqlDatabase } from './src/data-providers/sql-database';
21
- export { CustomSqlFilterObject, CustomSqlFilterBuilder, dbNamesOf, } from './src/filter/filter-consumer-bridge-to-sql-request';
21
+ export { CustomSqlFilterObject, CustomSqlFilterBuilder, dbNamesOf, CustomSqlFilterBuilderFunction, EntityDbNames, } from './src/filter/filter-consumer-bridge-to-sql-request';
22
22
  export { JsonDataProvider, JsonEntityStorage, } from './src/data-providers/json-data-provider';
23
23
  export { Controller, BackendMethodOptions, BackendMethod, ProgressListener, } from './src/server-action';
24
24
  export { Allowed, Allow, Remult, RemultContext, ApiClient, isBackend, AllowedForInstance, EventDispatcher, EventSource, UserInfo, } from './src/context';
25
25
  export { ExternalHttpProvider } from './src/buildRestDataProvider';
26
26
  export { SortSegment, Sort } from './src/sort';
27
27
  export { CompoundIdField } from './src/CompoundIdField';
28
- export { Filter } from './src/filter/filter-interfaces';
28
+ export { Filter, FilterConsumer, customFilterInfo, } from './src/filter/filter-interfaces';
29
29
  export { UrlBuilder } from './urlBuilder';
30
30
  export { Validators } from './src/validators';
31
31
  export { ValueConverters } from './src/valueConverters';
package/esm/index.js CHANGED
@@ -16,7 +16,7 @@ export { Controller, BackendMethod, ProgressListener, } from './src/server-actio
16
16
  export { Allow, Remult, isBackend, EventSource, } from './src/context';
17
17
  export { Sort } from './src/sort';
18
18
  export { CompoundIdField } from './src/CompoundIdField';
19
- export { Filter } from './src/filter/filter-interfaces';
19
+ export { Filter, } from './src/filter/filter-interfaces';
20
20
  export { UrlBuilder } from './urlBuilder';
21
21
  export { Validators } from './src/validators';
22
22
  export { ValueConverters } from './src/valueConverters';
@@ -3,6 +3,7 @@ export declare function makeTitle(name: string): string;
3
3
  export declare class LookupColumn<T> {
4
4
  private repository;
5
5
  private isReferenceRelation;
6
+ private allowNull;
6
7
  toJson(): any;
7
8
  setId(val: any): void;
8
9
  waitLoadOf(id: any): Promise<T>;
@@ -12,7 +13,7 @@ export declare class LookupColumn<T> {
12
13
  };
13
14
  set(item: T): void;
14
15
  id: idType<T>;
15
- constructor(repository: Repository<T>, isReferenceRelation: any);
16
+ constructor(repository: Repository<T>, isReferenceRelation: any, allowNull: any);
16
17
  get item(): T;
17
18
  waitLoad(): Promise<T>;
18
19
  }
package/esm/src/column.js CHANGED
@@ -12,6 +12,7 @@ export function makeTitle(name) {
12
12
  export class LookupColumn {
13
13
  repository;
14
14
  isReferenceRelation;
15
+ allowNull;
15
16
  toJson() {
16
17
  if (!this.storedItem)
17
18
  return undefined;
@@ -32,12 +33,23 @@ export class LookupColumn {
32
33
  get(id) {
33
34
  if (id === undefined || id === null)
34
35
  return null;
35
- if (this.isReferenceRelation && !this.storedItem)
36
+ const result = getRepositoryInternals(this.repository).getCachedById(id, this.isReferenceRelation);
37
+ if (this.isReferenceRelation && !this.storedItem) {
38
+ if (!this.allowNull && (this.id === 0 || this.id === ''))
39
+ return null;
36
40
  return undefined;
37
- return getRepositoryInternals(this.repository).getCachedById(id, this.isReferenceRelation);
41
+ }
42
+ return result;
38
43
  }
39
44
  storedItem;
40
45
  set(item) {
46
+ if (item === null &&
47
+ !this.allowNull &&
48
+ this.isReferenceRelation &&
49
+ (this.id == 0 || this.id == '')) {
50
+ this.storedItem = { item: null };
51
+ return;
52
+ }
41
53
  this.storedItem = undefined;
42
54
  if (item) {
43
55
  if (typeof item === 'string' || typeof item === 'number')
@@ -62,9 +74,10 @@ export class LookupColumn {
62
74
  }
63
75
  }
64
76
  id;
65
- constructor(repository, isReferenceRelation) {
77
+ constructor(repository, isReferenceRelation, allowNull) {
66
78
  this.repository = repository;
67
79
  this.isReferenceRelation = isReferenceRelation;
80
+ this.allowNull = allowNull;
68
81
  }
69
82
  get item() {
70
83
  if (this.storedItem)
@@ -3,7 +3,7 @@ import { LookupColumn } from '../column';
3
3
  import type { FieldMetadata, FieldOptions, ValueConverter, ValueListItem } from '../column-interfaces';
4
4
  import { Remult } from '../context';
5
5
  import type { EntityOptions } from '../entity';
6
- import type { ControllerRef, EntityFilter, EntityMetadata, EntityOrderBy, EntityRef, FieldRef, FieldsMetadata, FieldsRef, FindFirstOptions, FindFirstOptionsBase, FindOptions, IdMetadata, LiveQuery, LoadOptions, MembersOnly, QueryOptions, QueryResult, Repository, RepositoryRelations, Subscribable } from './remult3';
6
+ import type { ControllerRef, ControllerRefForControllerBase, EntityFilter, EntityMetadata, EntityOrderBy, EntityRef, EntityRefForEntityBase, FieldRef, FieldsMetadata, FieldsRef, FieldsRefForEntityBase, FindFirstOptions, FindFirstOptionsBase, FindOptions, IdMetadata, LiveQuery, LoadOptions, MembersOnly, QueryOptions, QueryResult, Repository, RepositoryRelations, Subscribable } from './remult3';
7
7
  import type { RefSubscriber } from './remult3';
8
8
  import type { entityEventListener } from '../__EntityValueProvider';
9
9
  import type { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo } from '../data-interfaces';
@@ -98,7 +98,7 @@ declare abstract class rowHelperBase<T> {
98
98
  __clearErrorsAndReportChanged(): void;
99
99
  _reportChangedToEntityAndFields(): void;
100
100
  hasErrors(): boolean;
101
- copyDataToObject(): any;
101
+ copyDataToObject(isNew?: boolean): any;
102
102
  originalValues: any;
103
103
  saveOriginalData(): void;
104
104
  saveMoreOriginalData(): void;
@@ -259,20 +259,19 @@ export declare const storableMember: unique symbol;
259
259
  export declare function buildOptions<entityType = any, valueType = any>(options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[], remult: Remult): FieldOptions<entityType, valueType>;
260
260
  export declare function decorateColumnSettings<valueType>(settings: FieldOptions<any, valueType>, remult: Remult): FieldOptions<any, valueType>;
261
261
  export declare class EntityBase {
262
- ['י'](): EntityRef<this>;
263
- get _(): ReturnType<this["י"]>;
262
+ get _(): EntityRefForEntityBase<this>;
264
263
  save(): Promise<this>;
265
264
  assign(values: Partial<Omit<this, keyof EntityBase>>): this;
266
265
  delete(): Promise<void>;
267
266
  isNew(): boolean;
268
- get $(): this["_"]["fields"];
267
+ get $(): FieldsRefForEntityBase<this>;
269
268
  }
270
269
  export declare class ControllerBase {
271
270
  protected remult: Remult;
272
271
  constructor(remult?: Remult);
273
272
  assign(values: Partial<Omit<this, keyof EntityBase>>): this;
274
- get $(): FieldsRef<this>;
275
- get _(): ControllerRef<this>;
273
+ get $(): FieldsRefForEntityBase<this>;
274
+ get _(): ControllerRefForControllerBase<this>;
276
275
  }
277
276
  declare class SubscribableImp implements Subscribable {
278
277
  reportChanged(): void;
@@ -560,6 +560,8 @@ export class RepositoryImplementation {
560
560
  let val = rel.type === 'reference'
561
561
  ? getEntityRef(row).fields.find(requireField(field.key, this.metadata)).getId()
562
562
  : row[field.key];
563
+ if (!field.allowNull && (val === 0 || val === ''))
564
+ val = null;
563
565
  if (val === null)
564
566
  returnNull = true;
565
567
  if (val === undefined)
@@ -828,7 +830,7 @@ class rowHelperBase {
828
830
  for (const col of columnsInfo) {
829
831
  let ei = getEntitySettings(col.valueType, false);
830
832
  if (ei && remult) {
831
- let lookup = new LookupColumn(remult.repo(col.valueType), Boolean(col?.[relationInfoMember]));
833
+ let lookup = new LookupColumn(remult.repo(col.valueType), Boolean(col?.[relationInfoMember]), col.allowNull);
832
834
  this.lookups.set(col.key, lookup);
833
835
  let val = instance[col.key];
834
836
  let refImpl;
@@ -1004,21 +1006,28 @@ class rowHelperBase {
1004
1006
  this._subscribers?.reportObserved();
1005
1007
  return !!!this.error && this.errors == undefined;
1006
1008
  }
1007
- copyDataToObject() {
1009
+ copyDataToObject(isNew = false) {
1008
1010
  let d = {};
1009
1011
  for (const col of this.columnsInfo) {
1010
1012
  let lu = this.lookups.get(col.key);
1011
1013
  let val = undefined;
1014
+ const rel = getRelationInfo(col);
1012
1015
  if (lu)
1013
1016
  val = lu.id;
1014
1017
  else
1015
1018
  val = this.instance[col.key];
1019
+ if (rel && isNew && !col.allowNull && (val === undefined || null)) {
1020
+ if (this.remult.repo(rel.toType()).metadata.idMetadata.field.valueType ===
1021
+ Number)
1022
+ val = 0;
1023
+ else
1024
+ val = '';
1025
+ }
1016
1026
  if (val !== undefined) {
1017
1027
  val = col.valueConverter.toJson(val);
1018
1028
  if (val !== undefined && val !== null)
1019
1029
  val = col.valueConverter.fromJson(JSON.parse(JSON.stringify(val)));
1020
1030
  }
1021
- const rel = getRelationInfo(col);
1022
1031
  if (!rel || rel.type === 'reference')
1023
1032
  d[col.key] = val;
1024
1033
  }
@@ -1217,7 +1226,7 @@ export class rowHelperImplementation extends rowHelperBase {
1217
1226
  }
1218
1227
  }
1219
1228
  this.__assertValidity();
1220
- let d = this.copyDataToObject();
1229
+ let d = this.copyDataToObject(this.isNew());
1221
1230
  let ignoreKeys = [];
1222
1231
  for (const field of this.metadata.fields) {
1223
1232
  if (field.dbReadOnly ||
@@ -2115,9 +2124,6 @@ export function decorateColumnSettings(settings, remult) {
2115
2124
  return settings;
2116
2125
  }
2117
2126
  export class EntityBase {
2118
- ['י']() {
2119
- return getEntityRef(this);
2120
- }
2121
2127
  get _() {
2122
2128
  return getEntityRef(this);
2123
2129
  }
@@ -6,7 +6,7 @@ import type { EntityOptions } from '../entity';
6
6
  import type { LiveQueryChange, SubscriptionListener, Unsubscribe } from '../live-query/SubscriptionChannel';
7
7
  import type { SortSegment } from '../sort';
8
8
  import type { EntityBase } from './RepositoryImplementation';
9
- export interface EntityRef<entityType> extends Subscribable {
9
+ export interface EntityRefBase<entityType> extends Subscribable {
10
10
  hasErrors(): boolean;
11
11
  undoChanges(): any;
12
12
  save(): Promise<entityType>;
@@ -15,7 +15,6 @@ export interface EntityRef<entityType> extends Subscribable {
15
15
  isNew(): boolean;
16
16
  wasChanged(): boolean;
17
17
  wasDeleted(): boolean;
18
- fields: FieldsRef<entityType>;
19
18
  error: string;
20
19
  getId(): idType<entityType>;
21
20
  getOriginalId(): idType<entityType>;
@@ -23,12 +22,19 @@ export interface EntityRef<entityType> extends Subscribable {
23
22
  metadata: EntityMetadata<entityType>;
24
23
  toApiJson(): any;
25
24
  validate(): Promise<ErrorInfo<entityType> | undefined>;
26
- relations: RepositoryRelations<entityType>;
27
25
  readonly apiUpdateAllowed: boolean;
28
26
  readonly apiDeleteAllowed: boolean;
29
27
  readonly apiInsertAllowed: boolean;
30
28
  readonly isLoading: boolean;
31
29
  }
30
+ export interface EntityRef<entityType> extends EntityRefBase<entityType> {
31
+ fields: FieldsRef<entityType>;
32
+ relations: RepositoryRelations<entityType>;
33
+ }
34
+ export interface EntityRefForEntityBase<entityType> extends EntityRefBase<entityType> {
35
+ fields: FieldsRefForEntityBase<entityType>;
36
+ relations: RepositoryRelationsForEntityBase<entityType>;
37
+ }
32
38
  /**
33
39
  * Represents a lifecycle event associated with an entity instance. These events
34
40
  * are triggered during various stages of the entity's lifecycle, such as validation,
@@ -73,13 +79,18 @@ export interface LifecycleEvent<entityType> {
73
79
  */
74
80
  relations: RepositoryRelations<entityType>;
75
81
  }
76
- export interface ControllerRef<entityType> extends Subscribable {
82
+ export interface ControllerRefBase<entityType> extends Subscribable {
77
83
  hasErrors(): boolean;
78
- fields: FieldsRef<entityType>;
79
84
  error: string;
80
85
  validate(): Promise<ErrorInfo<entityType> | undefined>;
81
86
  readonly isLoading: boolean;
82
87
  }
88
+ export interface ControllerRef<entityType> extends ControllerRefBase<entityType> {
89
+ fields: FieldsRef<entityType>;
90
+ }
91
+ export interface ControllerRefForControllerBase<entityType> extends ControllerRefBase<entityType> {
92
+ fields: FieldsRefForEntityBase<entityType>;
93
+ }
83
94
  export interface RefSubscriberBase {
84
95
  reportChanged: () => void;
85
96
  reportObserved: () => void;
@@ -88,11 +99,7 @@ export declare type RefSubscriber = (() => void) | RefSubscriberBase;
88
99
  export interface Subscribable {
89
100
  subscribe(listener: RefSubscriber): Unsubscribe;
90
101
  }
91
- export type FieldsRef<entityType> = {
92
- [Properties in keyof MembersOnly<entityType>]: NonNullable<entityType[Properties]> extends {
93
- id?: number | string;
94
- } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
95
- } & {
102
+ export type FieldsRefBase<entityType> = {
96
103
  find(fieldMetadataOrKey: FieldMetadata | string): FieldRef<entityType, any>;
97
104
  [Symbol.iterator]: () => IterableIterator<FieldRef<entityType, any>>;
98
105
  toArray(): FieldRef<entityType, any>[];
@@ -104,6 +111,16 @@ export type FieldsMetadata<entityType> = {
104
111
  [Symbol.iterator]: () => IterableIterator<FieldMetadata<any, entityType>>;
105
112
  toArray(): FieldMetadata<any, entityType>[];
106
113
  };
114
+ export type FieldsRef<entityType> = FieldsRefBase<entityType> & {
115
+ [Properties in keyof MembersOnly<entityType>]: NonNullable<entityType[Properties]> extends {
116
+ id?: number | string;
117
+ } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
118
+ };
119
+ export type FieldsRefForEntityBase<entityType> = FieldsRefBase<entityType> & {
120
+ [Properties in keyof Omit<entityType, keyof EntityBase>]: NonNullable<entityType[Properties]> extends {
121
+ id?: number | string;
122
+ } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
123
+ };
107
124
  export type SortSegments<entityType> = {
108
125
  [Properties in keyof entityType]: SortSegment & {
109
126
  descending(): SortSegment;
@@ -200,7 +217,7 @@ export interface EntityMetadata<entityType = any> {
200
217
  readonly idMetadata: IdMetadata<entityType>;
201
218
  }
202
219
  export declare type MembersOnly<T> = {
203
- [K in keyof Omit<T, keyof Pick<EntityBase, '$' | '_' | 'י'>> as T[K] extends Function ? never : K]: T[K];
220
+ [K in keyof T as T[K] extends Function ? never : K]: T[K];
204
221
  };
205
222
  export declare type idType<entityType> = entityType extends {
206
223
  id?: number;
@@ -537,6 +554,11 @@ export type RepositoryRelations<entityType> = {
537
554
  findOne: (options?: FindOptionsBase<R>) => Promise<R>;
538
555
  } : never;
539
556
  };
557
+ export type RepositoryRelationsForEntityBase<entityType> = {
558
+ [K in keyof Omit<entityType, keyof EntityBase>]-?: NonNullable<entityType[K]> extends Array<infer R> ? Repository<R> : entityType[K] extends infer R ? {
559
+ findOne: (options?: FindOptionsBase<R>) => Promise<R>;
560
+ } : never;
561
+ };
540
562
  export declare type EntityIdFields<entityType> = {
541
563
  [Properties in keyof Partial<MembersOnly<entityType>>]?: true;
542
564
  };
@@ -571,4 +593,11 @@ remult.apiClient.httpClient = (
571
593
  remult.apiClient.url='localhost:3007/api
572
594
 
573
595
 
596
+ */
597
+ /**
598
+ * our default is allow null false.
599
+ * for sql databases we add a db default of 0/''/false
600
+ * when we set a relation to null - we update the related field to null
601
+ * we do not enforce allow null false (mongo, json it'll get stored)
602
+
574
603
  */
@@ -50,3 +50,15 @@ remult.apiClient.url='localhost:3007/api
50
50
  //y2 - remove __dirname from tutorials
51
51
  //y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
52
52
  //y2 - I tihnk there should be a way to throw a forbidden exception
53
+ //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
+ //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
+ /**
58
+ * our default is allow null false.
59
+ * for sql databases we add a db default of 0/''/false
60
+ * when we set a relation to null - we update the related field to null
61
+ * we do not enforce allow null false (mongo, json it'll get stored)
62
+
63
+ */
64
+ //y2 - i had a question about find first's different syntax from find that confused a user
package/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { ClassType } from './classType';
2
2
  export type { ClassType } from './classType';
3
- export { MembersOnly, FieldsMetadata, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, QueryResult, QueryOptions, Repository, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, EntityRef, SortSegments, Paginator, LiveQuery, LiveQueryChangeInfo, Subscribable, RefSubscriber, RefSubscriberBase, RelationOptions, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, ClassFieldDecorator, ClassFieldDecoratorContextStub, //n1 consider removing in ts5
4
- LifecycleEvent, } from './src/remult3/remult3';
3
+ export { MembersOnly, FieldsMetadata, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, FindOptionsBase, QueryResult, QueryOptions, Repository, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, EntityRef, SortSegments, Paginator, LiveQuery, LiveQueryChangeInfo, Subscribable, RefSubscriber, RefSubscriberBase, RelationOptions, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, ClassFieldDecorator, ClassFieldDecoratorContextStub, //n1 consider removing in ts5
4
+ LifecycleEvent, FieldsRefBase, FieldsRefForEntityBase, RepositoryRelationsForEntityBase, ControllerRefForControllerBase, ControllerRefBase, ControllerRef, EntityRefForEntityBase, IdMetadata, FindFirstOptionsBase, } from './src/remult3/remult3';
5
5
  export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation';
6
6
  export { Entity } from './src/remult3/entity';
7
7
  export { getEntityRef } from './src/remult3/getEntityRef';
@@ -10,7 +10,7 @@ export { IdEntity } from './src/remult3/IdEntity';
10
10
  export { describeClass } from './src/remult3/DecoratorReplacer';
11
11
  export { EntityOptions } from './src/entity';
12
12
  export { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo, RestDataProviderHttpProvider, } from './src/data-interfaces';
13
- export { SqlCommand, SqlImplementation, SqlResult } from './src/sql-command';
13
+ export { SqlCommand, SqlCommandWithParameters, SqlImplementation, SqlResult, } from './src/sql-command';
14
14
  export { FieldMetadata, FieldOptions, FieldValidator, ValueConverter, ValueListItem, // reconsider, maybe it should go to remult angular as the abstraction ?
15
15
  ValueOrExpression, } from './src/column-interfaces';
16
16
  export { RestDataProvider } from './src/data-providers/rest-data-provider';
@@ -18,14 +18,14 @@ export { InMemoryDataProvider } from './src/data-providers/in-memory-database';
18
18
  export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider';
19
19
  export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider';
20
20
  export { SqlDatabase } from './src/data-providers/sql-database';
21
- export { CustomSqlFilterObject, CustomSqlFilterBuilder, dbNamesOf, } from './src/filter/filter-consumer-bridge-to-sql-request';
21
+ export { CustomSqlFilterObject, CustomSqlFilterBuilder, dbNamesOf, CustomSqlFilterBuilderFunction, EntityDbNames, } from './src/filter/filter-consumer-bridge-to-sql-request';
22
22
  export { JsonDataProvider, JsonEntityStorage, } from './src/data-providers/json-data-provider';
23
23
  export { Controller, BackendMethodOptions, BackendMethod, ProgressListener, } from './src/server-action';
24
24
  export { Allowed, Allow, Remult, RemultContext, ApiClient, isBackend, AllowedForInstance, EventDispatcher, EventSource, UserInfo, } from './src/context';
25
25
  export { ExternalHttpProvider } from './src/buildRestDataProvider';
26
26
  export { SortSegment, Sort } from './src/sort';
27
27
  export { CompoundIdField } from './src/CompoundIdField';
28
- export { Filter } from './src/filter/filter-interfaces';
28
+ export { Filter, FilterConsumer, customFilterInfo, } from './src/filter/filter-interfaces';
29
29
  export { UrlBuilder } from './urlBuilder';
30
30
  export { Validators } from './src/validators';
31
31
  export { ValueConverters } from './src/valueConverters';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.23.0-exp.35",
3
+ "version": "0.23.0-exp.37",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "types": "index.d.ts",
6
6
  "module": "esm/index.js",
package/src/column.d.ts CHANGED
@@ -3,6 +3,7 @@ export declare function makeTitle(name: string): string;
3
3
  export declare class LookupColumn<T> {
4
4
  private repository;
5
5
  private isReferenceRelation;
6
+ private allowNull;
6
7
  toJson(): any;
7
8
  setId(val: any): void;
8
9
  waitLoadOf(id: any): Promise<T>;
@@ -12,7 +13,7 @@ export declare class LookupColumn<T> {
12
13
  };
13
14
  set(item: T): void;
14
15
  id: idType<T>;
15
- constructor(repository: Repository<T>, isReferenceRelation: any);
16
+ constructor(repository: Repository<T>, isReferenceRelation: any, allowNull: any);
16
17
  get item(): T;
17
18
  waitLoad(): Promise<T>;
18
19
  }
package/src/column.js CHANGED
@@ -15,9 +15,10 @@ function makeTitle(name) {
15
15
  }
16
16
  exports.makeTitle = makeTitle;
17
17
  var LookupColumn = /** @class */ (function () {
18
- function LookupColumn(repository, isReferenceRelation) {
18
+ function LookupColumn(repository, isReferenceRelation, allowNull) {
19
19
  this.repository = repository;
20
20
  this.isReferenceRelation = isReferenceRelation;
21
+ this.allowNull = allowNull;
21
22
  }
22
23
  LookupColumn.prototype.toJson = function () {
23
24
  if (!this.storedItem)
@@ -39,11 +40,22 @@ var LookupColumn = /** @class */ (function () {
39
40
  LookupColumn.prototype.get = function (id) {
40
41
  if (id === undefined || id === null)
41
42
  return null;
42
- if (this.isReferenceRelation && !this.storedItem)
43
+ var result = (0, repository_internals_1.getRepositoryInternals)(this.repository).getCachedById(id, this.isReferenceRelation);
44
+ if (this.isReferenceRelation && !this.storedItem) {
45
+ if (!this.allowNull && (this.id === 0 || this.id === ''))
46
+ return null;
43
47
  return undefined;
44
- return (0, repository_internals_1.getRepositoryInternals)(this.repository).getCachedById(id, this.isReferenceRelation);
48
+ }
49
+ return result;
45
50
  };
46
51
  LookupColumn.prototype.set = function (item) {
52
+ if (item === null &&
53
+ !this.allowNull &&
54
+ this.isReferenceRelation &&
55
+ (this.id == 0 || this.id == '')) {
56
+ this.storedItem = { item: null };
57
+ return;
58
+ }
47
59
  this.storedItem = undefined;
48
60
  if (item) {
49
61
  if (typeof item === 'string' || typeof item === 'number')
@@ -3,7 +3,7 @@ import { LookupColumn } from '../column';
3
3
  import type { FieldMetadata, FieldOptions, ValueConverter, ValueListItem } from '../column-interfaces';
4
4
  import { Remult } from '../context';
5
5
  import type { EntityOptions } from '../entity';
6
- import type { ControllerRef, EntityFilter, EntityMetadata, EntityOrderBy, EntityRef, FieldRef, FieldsMetadata, FieldsRef, FindFirstOptions, FindFirstOptionsBase, FindOptions, IdMetadata, LiveQuery, LoadOptions, MembersOnly, QueryOptions, QueryResult, Repository, RepositoryRelations, Subscribable } from './remult3';
6
+ import type { ControllerRef, ControllerRefForControllerBase, EntityFilter, EntityMetadata, EntityOrderBy, EntityRef, EntityRefForEntityBase, FieldRef, FieldsMetadata, FieldsRef, FieldsRefForEntityBase, FindFirstOptions, FindFirstOptionsBase, FindOptions, IdMetadata, LiveQuery, LoadOptions, MembersOnly, QueryOptions, QueryResult, Repository, RepositoryRelations, Subscribable } from './remult3';
7
7
  import type { RefSubscriber } from './remult3';
8
8
  import type { entityEventListener } from '../__EntityValueProvider';
9
9
  import type { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo } from '../data-interfaces';
@@ -98,7 +98,7 @@ declare abstract class rowHelperBase<T> {
98
98
  __clearErrorsAndReportChanged(): void;
99
99
  _reportChangedToEntityAndFields(): void;
100
100
  hasErrors(): boolean;
101
- copyDataToObject(): any;
101
+ copyDataToObject(isNew?: boolean): any;
102
102
  originalValues: any;
103
103
  saveOriginalData(): void;
104
104
  saveMoreOriginalData(): void;
@@ -259,20 +259,19 @@ export declare const storableMember: unique symbol;
259
259
  export declare function buildOptions<entityType = any, valueType = any>(options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[], remult: Remult): FieldOptions<entityType, valueType>;
260
260
  export declare function decorateColumnSettings<valueType>(settings: FieldOptions<any, valueType>, remult: Remult): FieldOptions<any, valueType>;
261
261
  export declare class EntityBase {
262
- ['י'](): EntityRef<this>;
263
- get _(): ReturnType<this["י"]>;
262
+ get _(): EntityRefForEntityBase<this>;
264
263
  save(): Promise<this>;
265
264
  assign(values: Partial<Omit<this, keyof EntityBase>>): this;
266
265
  delete(): Promise<void>;
267
266
  isNew(): boolean;
268
- get $(): this["_"]["fields"];
267
+ get $(): FieldsRefForEntityBase<this>;
269
268
  }
270
269
  export declare class ControllerBase {
271
270
  protected remult: Remult;
272
271
  constructor(remult?: Remult);
273
272
  assign(values: Partial<Omit<this, keyof EntityBase>>): this;
274
- get $(): FieldsRef<this>;
275
- get _(): ControllerRef<this>;
273
+ get $(): FieldsRefForEntityBase<this>;
274
+ get _(): ControllerRefForControllerBase<this>;
276
275
  }
277
276
  declare class SubscribableImp implements Subscribable {
278
277
  reportChanged(): void;
@@ -913,6 +913,8 @@ var RepositoryImplementation = /** @class */ (function () {
913
913
  var val = rel.type === 'reference'
914
914
  ? (0, getEntityRef_1.getEntityRef)(row).fields.find(requireField(field.key, this.metadata)).getId()
915
915
  : row[field.key];
916
+ if (!field.allowNull && (val === 0 || val === ''))
917
+ val = null;
916
918
  if (val === null)
917
919
  returnNull = true;
918
920
  if (val === undefined)
@@ -1300,7 +1302,7 @@ var rowHelperBase = /** @class */ (function () {
1300
1302
  var _loop_5 = function (col) {
1301
1303
  var ei = (0, getEntityRef_1.getEntitySettings)(col.valueType, false);
1302
1304
  if (ei && remult) {
1303
- var lookup_1 = new column_1.LookupColumn(remult.repo(col.valueType), Boolean(col === null || col === void 0 ? void 0 : col[relationInfoMember_1.relationInfoMember]));
1305
+ var lookup_1 = new column_1.LookupColumn(remult.repo(col.valueType), Boolean(col === null || col === void 0 ? void 0 : col[relationInfoMember_1.relationInfoMember]), col.allowNull);
1304
1306
  this_2.lookups.set(col.key, lookup_1);
1305
1307
  var val = instance[col.key];
1306
1308
  var refImpl_1;
@@ -1556,24 +1558,32 @@ var rowHelperBase = /** @class */ (function () {
1556
1558
  (_a = this._subscribers) === null || _a === void 0 ? void 0 : _a.reportObserved();
1557
1559
  return !!!this.error && this.errors == undefined;
1558
1560
  };
1559
- rowHelperBase.prototype.copyDataToObject = function () {
1561
+ rowHelperBase.prototype.copyDataToObject = function (isNew) {
1560
1562
  var e_25, _a;
1563
+ if (isNew === void 0) { isNew = false; }
1561
1564
  var d = {};
1562
1565
  try {
1563
1566
  for (var _b = tslib_1.__values(this.columnsInfo), _c = _b.next(); !_c.done; _c = _b.next()) {
1564
1567
  var col = _c.value;
1565
1568
  var lu = this.lookups.get(col.key);
1566
1569
  var val = undefined;
1570
+ var rel = (0, relationInfoMember_1.getRelationInfo)(col);
1567
1571
  if (lu)
1568
1572
  val = lu.id;
1569
1573
  else
1570
1574
  val = this.instance[col.key];
1575
+ if (rel && isNew && !col.allowNull && (val === undefined || null)) {
1576
+ if (this.remult.repo(rel.toType()).metadata.idMetadata.field.valueType ===
1577
+ Number)
1578
+ val = 0;
1579
+ else
1580
+ val = '';
1581
+ }
1571
1582
  if (val !== undefined) {
1572
1583
  val = col.valueConverter.toJson(val);
1573
1584
  if (val !== undefined && val !== null)
1574
1585
  val = col.valueConverter.fromJson(JSON.parse(JSON.stringify(val)));
1575
1586
  }
1576
- var rel = (0, relationInfoMember_1.getRelationInfo)(col);
1577
1587
  if (!rel || rel.type === 'reference')
1578
1588
  d[col.key] = val;
1579
1589
  }
@@ -1943,7 +1953,7 @@ var rowHelperImplementation = /** @class */ (function (_super) {
1943
1953
  _l.label = 12;
1944
1954
  case 12:
1945
1955
  this.__assertValidity();
1946
- d = this.copyDataToObject();
1956
+ d = this.copyDataToObject(this.isNew());
1947
1957
  ignoreKeys = [];
1948
1958
  try {
1949
1959
  for (_d = tslib_1.__values(this.metadata.fields), _e = _d.next(); !_e.done; _e = _d.next()) {
@@ -3283,9 +3293,6 @@ exports.decorateColumnSettings = decorateColumnSettings;
3283
3293
  var EntityBase = /** @class */ (function () {
3284
3294
  function EntityBase() {
3285
3295
  }
3286
- EntityBase.prototype['י'] = function () {
3287
- return (0, getEntityRef_1.getEntityRef)(this);
3288
- };
3289
3296
  Object.defineProperty(EntityBase.prototype, "_", {
3290
3297
  get: function () {
3291
3298
  return (0, getEntityRef_1.getEntityRef)(this);
@@ -6,7 +6,7 @@ import type { EntityOptions } from '../entity';
6
6
  import type { LiveQueryChange, SubscriptionListener, Unsubscribe } from '../live-query/SubscriptionChannel';
7
7
  import type { SortSegment } from '../sort';
8
8
  import type { EntityBase } from './RepositoryImplementation';
9
- export interface EntityRef<entityType> extends Subscribable {
9
+ export interface EntityRefBase<entityType> extends Subscribable {
10
10
  hasErrors(): boolean;
11
11
  undoChanges(): any;
12
12
  save(): Promise<entityType>;
@@ -15,7 +15,6 @@ export interface EntityRef<entityType> extends Subscribable {
15
15
  isNew(): boolean;
16
16
  wasChanged(): boolean;
17
17
  wasDeleted(): boolean;
18
- fields: FieldsRef<entityType>;
19
18
  error: string;
20
19
  getId(): idType<entityType>;
21
20
  getOriginalId(): idType<entityType>;
@@ -23,12 +22,19 @@ export interface EntityRef<entityType> extends Subscribable {
23
22
  metadata: EntityMetadata<entityType>;
24
23
  toApiJson(): any;
25
24
  validate(): Promise<ErrorInfo<entityType> | undefined>;
26
- relations: RepositoryRelations<entityType>;
27
25
  readonly apiUpdateAllowed: boolean;
28
26
  readonly apiDeleteAllowed: boolean;
29
27
  readonly apiInsertAllowed: boolean;
30
28
  readonly isLoading: boolean;
31
29
  }
30
+ export interface EntityRef<entityType> extends EntityRefBase<entityType> {
31
+ fields: FieldsRef<entityType>;
32
+ relations: RepositoryRelations<entityType>;
33
+ }
34
+ export interface EntityRefForEntityBase<entityType> extends EntityRefBase<entityType> {
35
+ fields: FieldsRefForEntityBase<entityType>;
36
+ relations: RepositoryRelationsForEntityBase<entityType>;
37
+ }
32
38
  /**
33
39
  * Represents a lifecycle event associated with an entity instance. These events
34
40
  * are triggered during various stages of the entity's lifecycle, such as validation,
@@ -73,13 +79,18 @@ export interface LifecycleEvent<entityType> {
73
79
  */
74
80
  relations: RepositoryRelations<entityType>;
75
81
  }
76
- export interface ControllerRef<entityType> extends Subscribable {
82
+ export interface ControllerRefBase<entityType> extends Subscribable {
77
83
  hasErrors(): boolean;
78
- fields: FieldsRef<entityType>;
79
84
  error: string;
80
85
  validate(): Promise<ErrorInfo<entityType> | undefined>;
81
86
  readonly isLoading: boolean;
82
87
  }
88
+ export interface ControllerRef<entityType> extends ControllerRefBase<entityType> {
89
+ fields: FieldsRef<entityType>;
90
+ }
91
+ export interface ControllerRefForControllerBase<entityType> extends ControllerRefBase<entityType> {
92
+ fields: FieldsRefForEntityBase<entityType>;
93
+ }
83
94
  export interface RefSubscriberBase {
84
95
  reportChanged: () => void;
85
96
  reportObserved: () => void;
@@ -88,11 +99,7 @@ export declare type RefSubscriber = (() => void) | RefSubscriberBase;
88
99
  export interface Subscribable {
89
100
  subscribe(listener: RefSubscriber): Unsubscribe;
90
101
  }
91
- export type FieldsRef<entityType> = {
92
- [Properties in keyof MembersOnly<entityType>]: NonNullable<entityType[Properties]> extends {
93
- id?: number | string;
94
- } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
95
- } & {
102
+ export type FieldsRefBase<entityType> = {
96
103
  find(fieldMetadataOrKey: FieldMetadata | string): FieldRef<entityType, any>;
97
104
  [Symbol.iterator]: () => IterableIterator<FieldRef<entityType, any>>;
98
105
  toArray(): FieldRef<entityType, any>[];
@@ -104,6 +111,16 @@ export type FieldsMetadata<entityType> = {
104
111
  [Symbol.iterator]: () => IterableIterator<FieldMetadata<any, entityType>>;
105
112
  toArray(): FieldMetadata<any, entityType>[];
106
113
  };
114
+ export type FieldsRef<entityType> = FieldsRefBase<entityType> & {
115
+ [Properties in keyof MembersOnly<entityType>]: NonNullable<entityType[Properties]> extends {
116
+ id?: number | string;
117
+ } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
118
+ };
119
+ export type FieldsRefForEntityBase<entityType> = FieldsRefBase<entityType> & {
120
+ [Properties in keyof Omit<entityType, keyof EntityBase>]: NonNullable<entityType[Properties]> extends {
121
+ id?: number | string;
122
+ } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
123
+ };
107
124
  export type SortSegments<entityType> = {
108
125
  [Properties in keyof entityType]: SortSegment & {
109
126
  descending(): SortSegment;
@@ -200,7 +217,7 @@ export interface EntityMetadata<entityType = any> {
200
217
  readonly idMetadata: IdMetadata<entityType>;
201
218
  }
202
219
  export declare type MembersOnly<T> = {
203
- [K in keyof Omit<T, keyof Pick<EntityBase, '$' | '_' | 'י'>> as T[K] extends Function ? never : K]: T[K];
220
+ [K in keyof T as T[K] extends Function ? never : K]: T[K];
204
221
  };
205
222
  export declare type idType<entityType> = entityType extends {
206
223
  id?: number;
@@ -537,6 +554,11 @@ export type RepositoryRelations<entityType> = {
537
554
  findOne: (options?: FindOptionsBase<R>) => Promise<R>;
538
555
  } : never;
539
556
  };
557
+ export type RepositoryRelationsForEntityBase<entityType> = {
558
+ [K in keyof Omit<entityType, keyof EntityBase>]-?: NonNullable<entityType[K]> extends Array<infer R> ? Repository<R> : entityType[K] extends infer R ? {
559
+ findOne: (options?: FindOptionsBase<R>) => Promise<R>;
560
+ } : never;
561
+ };
540
562
  export declare type EntityIdFields<entityType> = {
541
563
  [Properties in keyof Partial<MembersOnly<entityType>>]?: true;
542
564
  };
@@ -571,4 +593,11 @@ remult.apiClient.httpClient = (
571
593
  remult.apiClient.url='localhost:3007/api
572
594
 
573
595
 
596
+ */
597
+ /**
598
+ * our default is allow null false.
599
+ * for sql databases we add a db default of 0/''/false
600
+ * when we set a relation to null - we update the related field to null
601
+ * we do not enforce allow null false (mongo, json it'll get stored)
602
+
574
603
  */
@@ -51,3 +51,15 @@ remult.apiClient.url='localhost:3007/api
51
51
  //y2 - remove __dirname from tutorials
52
52
  //y2 - add some api testing framework for user unit tests (will help with codesandbox based discussions)
53
53
  //y2 - I tihnk there should be a way to throw a forbidden exception
54
+ //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
+ //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
+ /**
59
+ * our default is allow null false.
60
+ * for sql databases we add a db default of 0/''/false
61
+ * when we set a relation to null - we update the related field to null
62
+ * we do not enforce allow null false (mongo, json it'll get stored)
63
+
64
+ */
65
+ //y2 - i had a question about find first's different syntax from find that confused a user