remult 0.23.0-exp.18 → 0.23.0-exp.19
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 +1 -1
- package/esm/index.d.ts +12 -0
- package/esm/index.js +12 -0
- package/esm/src/CompoundIdField.d.ts +1 -1
- package/esm/src/CompoundIdField.js +3 -1
- package/esm/src/column-interfaces.d.ts +5 -5
- package/esm/src/context.js +3 -0
- package/esm/src/entity.d.ts +47 -16
- package/esm/src/remult3/RepositoryImplementation.d.ts +1 -1
- package/esm/src/remult3/RepositoryImplementation.js +8 -6
- package/esm/src/remult3/remult3.d.ts +41 -1
- package/esm/src/remult3/remult3.js +28 -0
- package/graphql.js +1 -1
- package/index.d.ts +12 -0
- package/index.js +12 -0
- package/package.json +1 -1
- package/src/CompoundIdField.d.ts +1 -1
- package/src/CompoundIdField.js +3 -0
- package/src/column-interfaces.d.ts +5 -5
- package/src/context.js +3 -0
- package/src/entity.d.ts +47 -16
- package/src/remult3/RepositoryImplementation.d.ts +1 -1
- package/src/remult3/RepositoryImplementation.js +10 -13
- package/src/remult3/remult3.d.ts +41 -1
- package/src/remult3/remult3.js +28 -0
package/esm/graphql.js
CHANGED
|
@@ -794,7 +794,7 @@ export function translateWhereToRestBody(fields, { where }) {
|
|
|
794
794
|
return undefined;
|
|
795
795
|
const result = {};
|
|
796
796
|
for (const field of fields) {
|
|
797
|
-
if (field.
|
|
797
|
+
if (field.options.includeInApi === false)
|
|
798
798
|
continue;
|
|
799
799
|
const condition = where[field.key];
|
|
800
800
|
if (condition) {
|
package/esm/index.d.ts
CHANGED
|
@@ -30,4 +30,16 @@ export { ValueConverters } from './src/valueConverters';
|
|
|
30
30
|
export { remult } from './src/remult-proxy';
|
|
31
31
|
export { SubscriptionServer, LiveQueryStorage, StoredQuery, InMemoryLiveQueryStorage, } from './src/live-query/SubscriptionServer';
|
|
32
32
|
export { SubscriptionListener, SubscriptionClientConnection, SubscriptionClient, SubscriptionChannel, LiveQueryChange, Unsubscribe, } from './src/live-query/SubscriptionChannel';
|
|
33
|
+
/**
|
|
34
|
+
* A convenient shortcut function to quickly obtain a repository for a specific entity type in Remult.
|
|
35
|
+
*
|
|
36
|
+
* @param entity The entity class type for which you want to get a repository.
|
|
37
|
+
* @returns A repository instance for the specified entity type.
|
|
38
|
+
*
|
|
39
|
+
* Example usage:
|
|
40
|
+
* ```ts
|
|
41
|
+
* await repo(Task).find()
|
|
42
|
+
* await repo(Customer).insert()
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
33
45
|
export declare function repo<entityType>(entity: ClassType<entityType>): import("./src/remult3/remult3").Repository<entityType>;
|
package/esm/index.js
CHANGED
|
@@ -25,6 +25,18 @@ import { remult } from './src/remult-proxy';
|
|
|
25
25
|
//export { getId } from './src/remult3/getId';
|
|
26
26
|
export { InMemoryLiveQueryStorage, } from './src/live-query/SubscriptionServer';
|
|
27
27
|
export { SubscriptionChannel, } from './src/live-query/SubscriptionChannel';
|
|
28
|
+
/**
|
|
29
|
+
* A convenient shortcut function to quickly obtain a repository for a specific entity type in Remult.
|
|
30
|
+
*
|
|
31
|
+
* @param entity The entity class type for which you want to get a repository.
|
|
32
|
+
* @returns A repository instance for the specified entity type.
|
|
33
|
+
*
|
|
34
|
+
* Example usage:
|
|
35
|
+
* ```ts
|
|
36
|
+
* await repo(Task).find()
|
|
37
|
+
* await repo(Customer).insert()
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
28
40
|
export function repo(entity) {
|
|
29
41
|
return remult.repo(entity);
|
|
30
42
|
}
|
|
@@ -6,7 +6,7 @@ export declare class CompoundIdField implements FieldMetadata<string> {
|
|
|
6
6
|
constructor(...columns: FieldMetadata[]);
|
|
7
7
|
apiUpdateAllowed(item: any): boolean;
|
|
8
8
|
displayValue(item: any): string;
|
|
9
|
-
includedInApi: boolean;
|
|
9
|
+
includedInApi(item: any): boolean;
|
|
10
10
|
toInput(value: string, inputType?: string): string;
|
|
11
11
|
fromInput(inputValue: string, inputType?: string): string;
|
|
12
12
|
getDbName(): Promise<string>;
|
|
@@ -9,7 +9,9 @@ export class CompoundIdField {
|
|
|
9
9
|
displayValue(item) {
|
|
10
10
|
throw new Error('Method not implemented.');
|
|
11
11
|
}
|
|
12
|
-
includedInApi
|
|
12
|
+
includedInApi(item) {
|
|
13
|
+
throw new Error('Method not implemented.');
|
|
14
|
+
}
|
|
13
15
|
toInput(value, inputType) {
|
|
14
16
|
throw new Error('Method not implemented.');
|
|
15
17
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassType } from '../classType';
|
|
2
|
-
import type {
|
|
3
|
-
import type { EntityMetadata, FieldRef,
|
|
2
|
+
import type { AllowedForInstance } from './context';
|
|
3
|
+
import type { EntityMetadata, FieldRef, LifecycleEvent, OmitEB } from './remult3/remult3';
|
|
4
4
|
export interface FieldOptions<entityType = any, valueType = any> {
|
|
5
5
|
/** A human readable name for the field. Can be used to achieve a consistent caption for a field throughout the app
|
|
6
6
|
* @example
|
|
@@ -11,7 +11,7 @@ export interface FieldOptions<entityType = any, valueType = any> {
|
|
|
11
11
|
allowNull?: boolean;
|
|
12
12
|
/** If this field data is included in the api.
|
|
13
13
|
* @see [allowed](http://remult.dev/docs/allowed.html)*/
|
|
14
|
-
includeInApi?:
|
|
14
|
+
includeInApi?: AllowedForInstance<entityType>;
|
|
15
15
|
/** If this field data can be updated in the api.
|
|
16
16
|
* @see [allowed](http://remult.dev/docs/allowed.html)*/
|
|
17
17
|
allowApiUpdate?: AllowedForInstance<entityType>;
|
|
@@ -37,7 +37,7 @@ export interface FieldOptions<entityType = any, valueType = any> {
|
|
|
37
37
|
*/
|
|
38
38
|
validate?: ((entity: entityType, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>) | ((entity: entityType, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>)[];
|
|
39
39
|
/** Will be fired before this field is saved to the server/database */
|
|
40
|
-
saving?: (entity: entityType, e:
|
|
40
|
+
saving?: (entity: entityType, e: LifecycleEvent<entityType>, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>;
|
|
41
41
|
/** An expression that will determine this fields value on the backend and be provided to the front end*/
|
|
42
42
|
serverExpression?: (entity: entityType) => valueType | Promise<valueType>;
|
|
43
43
|
/** The name of the column in the database that holds the data for this field. If no name is set, the key will be used instead.
|
|
@@ -134,7 +134,7 @@ export interface FieldMetadata<valueType = any, entityType = any> {
|
|
|
134
134
|
*/
|
|
135
135
|
displayValue(item: Partial<OmitEB<entityType>>): string;
|
|
136
136
|
apiUpdateAllowed(item?: Partial<OmitEB<entityType>>): boolean;
|
|
137
|
-
|
|
137
|
+
includedInApi(item?: Partial<OmitEB<entityType>>): boolean;
|
|
138
138
|
/** Adapts the value for usage with html input
|
|
139
139
|
* @example
|
|
140
140
|
* @Fields.dateOnly()
|
package/esm/src/context.js
CHANGED
|
@@ -286,3 +286,6 @@ class transactionLiveQueryPublisher {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
|
+
//p1 - seems that after backend methods relations are loaded for some reason - see trempim - intake doRequest backend method
|
|
290
|
+
//p1 - reconsider the case in tremping where create user id was updated with some user and not the actual user
|
|
291
|
+
//[ ] - when value changes for field with error, clear error - so the user will feel comfortable
|
package/esm/src/entity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Allowed, AllowedForInstance } from './context';
|
|
2
2
|
import type { FieldMetadata } from './column-interfaces';
|
|
3
|
-
import type { EntityFilter, EntityIdFields, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata,
|
|
3
|
+
import type { EntityFilter, EntityIdFields, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata, LifecycleEvent } from './remult3/remult3';
|
|
4
4
|
export interface EntityOptions<entityType = any> {
|
|
5
5
|
/**A human readable name for the entity */
|
|
6
6
|
caption?: string;
|
|
@@ -55,20 +55,51 @@ export interface EntityOptions<entityType = any> {
|
|
|
55
55
|
* this is the place to run logic that we want to run in any case before an entity is saved.
|
|
56
56
|
* @example
|
|
57
57
|
* @Entity<Task>("tasks", {
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*}
|
|
58
|
+
* saving: async (task, e) => {
|
|
59
|
+
* if (e.isNew) {
|
|
60
|
+
* task.createdAt = new Date(); // Set the creation date for new tasks.
|
|
61
|
+
* }
|
|
62
|
+
* task.lastUpdated = new Date(); // Update the last updated date.
|
|
63
|
+
* },
|
|
64
|
+
* })
|
|
65
|
+
* @param entity - The instance of the entity being saved.
|
|
66
|
+
* @param event - an @link LifeCycleEvent object
|
|
67
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
62
68
|
*/
|
|
63
|
-
saving?: (
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
saving?: (entity: entityType, event: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
70
|
+
/**
|
|
71
|
+
* A hook that runs after an entity has been successfully saved.
|
|
72
|
+
*
|
|
73
|
+
* @param entity The instance of the entity that was saved.
|
|
74
|
+
* @param event - an @link LifeCycleEvent object
|
|
75
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
76
|
+
*/
|
|
77
|
+
saved?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
78
|
+
/**
|
|
79
|
+
* A hook that runs before an entity is deleted.
|
|
80
|
+
*
|
|
81
|
+
* @param entity The instance of the entity being deleted.
|
|
82
|
+
* @param event - an @link LifeCycleEvent object
|
|
83
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
84
|
+
*/
|
|
85
|
+
deleting?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
86
|
+
/**
|
|
87
|
+
* A hook that runs after an entity has been successfully deleted.
|
|
88
|
+
*
|
|
89
|
+
* @param entity The instance of the entity that was deleted.
|
|
90
|
+
* @param event - an @link LifeCycleEvent object
|
|
91
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
92
|
+
*/
|
|
93
|
+
deleted?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
94
|
+
/**
|
|
95
|
+
* A hook that runs to perform validation checks on an entity before saving.
|
|
96
|
+
* This hook is also executed on the frontend.
|
|
97
|
+
*
|
|
98
|
+
* @param entity The instance of the entity being validated.
|
|
99
|
+
* @param event - an @link LifeCycleEvent object
|
|
100
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
101
|
+
*/
|
|
102
|
+
validation?: (entity: entityType, ref: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
72
103
|
/** The name of the table in the database that holds the data for this entity.
|
|
73
104
|
* If no name is set, the `key` will be used instead.
|
|
74
105
|
* @example
|
|
@@ -84,10 +115,10 @@ export interface EntityOptions<entityType = any> {
|
|
|
84
115
|
/** An arrow function that identifies the `id` column to use for this entity
|
|
85
116
|
* @example
|
|
86
117
|
* //Single column id
|
|
87
|
-
* @Entity<Products>("products", { id:
|
|
118
|
+
* @Entity<Products>("products", { id: {productCode: true} })
|
|
88
119
|
* @example
|
|
89
120
|
* //Multiple columns id
|
|
90
|
-
* @Entity<OrderDetails>("orderDetails", { id:
|
|
121
|
+
* @Entity<OrderDetails>("orderDetails", { id:{ orderId:true, productCode:true} })
|
|
91
122
|
*/
|
|
92
123
|
id?: EntityIdFields<entityType> | ((entity: FieldsMetadata<entityType>) => FieldMetadata | FieldMetadata[]);
|
|
93
124
|
entityRefInit?: (ref: EntityRef<entityType>, row: entityType) => void;
|
|
@@ -190,7 +190,7 @@ export declare class columnDefsImpl implements FieldMetadata {
|
|
|
190
190
|
constructor(settings: FieldOptions, entityDefs: EntityFullInfo<any>, remult: Remult);
|
|
191
191
|
apiUpdateAllowed(item?: any): boolean;
|
|
192
192
|
displayValue(item: any): string;
|
|
193
|
-
|
|
193
|
+
includedInApi(item?: any): boolean;
|
|
194
194
|
toInput(value: any, inputType?: string): string;
|
|
195
195
|
fromInput(inputValue: string, inputType?: string): any;
|
|
196
196
|
getDbName(): Promise<string>;
|
|
@@ -1039,7 +1039,7 @@ class rowHelperBase {
|
|
|
1039
1039
|
for (const col of this.columnsInfo) {
|
|
1040
1040
|
if (!this.remult ||
|
|
1041
1041
|
col.includeInApi === undefined ||
|
|
1042
|
-
this.remult.
|
|
1042
|
+
this.remult.isAllowedForInstance(this.instance, col.includeInApi)) {
|
|
1043
1043
|
let val;
|
|
1044
1044
|
let lu = this.lookups.get(col.key);
|
|
1045
1045
|
let disable = false;
|
|
@@ -1073,7 +1073,7 @@ class rowHelperBase {
|
|
|
1073
1073
|
for (const col of this.columnsInfo) {
|
|
1074
1074
|
if (keys.includes(col.key))
|
|
1075
1075
|
if (col.includeInApi === undefined ||
|
|
1076
|
-
this.remult.
|
|
1076
|
+
this.remult.isAllowedForInstance(this.instance, col.includeInApi)) {
|
|
1077
1077
|
if (!this.remult ||
|
|
1078
1078
|
ignoreApiAllowed ||
|
|
1079
1079
|
col.allowApiUpdate === undefined ||
|
|
@@ -1363,8 +1363,10 @@ export class rowHelperImplementation extends rowHelperBase {
|
|
|
1363
1363
|
await col.__performValidation();
|
|
1364
1364
|
}
|
|
1365
1365
|
}
|
|
1366
|
-
if (this.info.entityInfo.validation)
|
|
1367
|
-
|
|
1366
|
+
if (this.info.entityInfo.validation) {
|
|
1367
|
+
let e = this.buildLifeCycleEvent(() => { });
|
|
1368
|
+
await this.info.entityInfo.validation(this.instance, e);
|
|
1369
|
+
}
|
|
1368
1370
|
if (this.repository.listeners)
|
|
1369
1371
|
for (const listener of this.repository.listeners.filter((x) => x.validating)) {
|
|
1370
1372
|
await listener.validating(this.instance);
|
|
@@ -1635,10 +1637,10 @@ export class columnDefsImpl {
|
|
|
1635
1637
|
.getEntityMetadataWithoutBreakingTheEntity(item)
|
|
1636
1638
|
.fields.find(this.key).displayValue;
|
|
1637
1639
|
}
|
|
1638
|
-
|
|
1640
|
+
includedInApi(item) {
|
|
1639
1641
|
if (this.options.includeInApi === undefined)
|
|
1640
1642
|
return true;
|
|
1641
|
-
return this.remult.
|
|
1643
|
+
return this.remult.isAllowedForInstance(item, this.options.includeInApi);
|
|
1642
1644
|
}
|
|
1643
1645
|
toInput(value, inputType) {
|
|
1644
1646
|
return this.valueConverter.toInput(value, inputType);
|
|
@@ -29,14 +29,48 @@ export interface EntityRef<entityType> extends Subscribable {
|
|
|
29
29
|
readonly apiInsertAllowed: boolean;
|
|
30
30
|
readonly isLoading: boolean;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Represents a lifecycle event associated with an entity instance. These events
|
|
34
|
+
* are triggered during various stages of the entity's lifecycle, such as validation,
|
|
35
|
+
* saving, saved, deleting, and deleted.
|
|
36
|
+
*
|
|
37
|
+
* @template entityType The type of the entity associated with the event.
|
|
38
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
39
|
+
*/
|
|
40
|
+
export interface LifecycleEvent<entityType> {
|
|
41
|
+
/**
|
|
42
|
+
* Indicates whether the entity is new or existing.
|
|
43
|
+
*/
|
|
33
44
|
isNew: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* A reference to the fields of the entity, providing access to its properties.
|
|
47
|
+
*/
|
|
34
48
|
fields: FieldsRef<entityType>;
|
|
49
|
+
/**
|
|
50
|
+
* The ID of the entity.
|
|
51
|
+
*/
|
|
35
52
|
id: idType<entityType>;
|
|
53
|
+
/**
|
|
54
|
+
* The original ID of the entity, useful for tracking changes.
|
|
55
|
+
*/
|
|
36
56
|
originalId: idType<entityType>;
|
|
57
|
+
/**
|
|
58
|
+
* The repository associated with the entity, providing access to repository methods.
|
|
59
|
+
*/
|
|
37
60
|
repository: Repository<entityType>;
|
|
61
|
+
/**
|
|
62
|
+
* Metadata describing the entity's structure and configuration.
|
|
63
|
+
*/
|
|
38
64
|
metadata: EntityMetadata<entityType>;
|
|
65
|
+
/**
|
|
66
|
+
* A function that can be used to prevent the default behavior associated with
|
|
67
|
+
* the lifecycle event.
|
|
68
|
+
*/
|
|
39
69
|
preventDefault: VoidFunction;
|
|
70
|
+
/**
|
|
71
|
+
* A reference to the repository relations associated with the entity, providing
|
|
72
|
+
* access to related entities and their data.
|
|
73
|
+
*/
|
|
40
74
|
relations: RepositoryRelations<entityType>;
|
|
41
75
|
}
|
|
42
76
|
export interface ControllerRef<entityType> extends Subscribable {
|
|
@@ -461,6 +495,12 @@ export interface RelationInfo {
|
|
|
461
495
|
* @template optionsType The type of find options to apply to the relation (default is FindOptionsBase<toEntity>).
|
|
462
496
|
*/
|
|
463
497
|
export type RelationOptions<fromEntity, toEntity, matchIdEntity, optionsType extends FindOptionsBase<toEntity> = FindOptionsBase<toEntity>> = {
|
|
498
|
+
/**
|
|
499
|
+
* An object specifying custom field names for the relation.
|
|
500
|
+
* Each key represents a field in the related entity, and its value is the corresponding field in the source entity.
|
|
501
|
+
* For example, `{ customerId: 'id' }` maps the 'customerId' field in the related entity to the 'id' field in the source entity.
|
|
502
|
+
* This is useful when you want to define custom field mappings for the relation.
|
|
503
|
+
*/
|
|
464
504
|
fields?: {
|
|
465
505
|
[K in keyof toEntity]?: keyof fromEntity;
|
|
466
506
|
};
|
|
@@ -1,3 +1,31 @@
|
|
|
1
1
|
export {};
|
|
2
2
|
//p1 - include relations in the api docs
|
|
3
3
|
//p1 - include Relation options in the api docs
|
|
4
|
+
//p1 - fix { allowApiRead: r => r.user.name === 'superman' } } in allowed for instace docs
|
|
5
|
+
//p1 - fix seeallowed in ref_entity
|
|
6
|
+
//p1 - write doc about controlling updates of rows...
|
|
7
|
+
//p1 - 'eventId' autocomplete in task app did not work
|
|
8
|
+
//p1 - need a way to extract the fields from the relation - for generating relation based sql
|
|
9
|
+
//p1 - remult object was used outside context
|
|
10
|
+
// ```
|
|
11
|
+
// sqlExpression: async (e) => {
|
|
12
|
+
// const v = await dbNamesOf(volunteerInTask)
|
|
13
|
+
// return `select true from ${v} where ${
|
|
14
|
+
// v.task
|
|
15
|
+
// }=${await e.getDbName()}.${await e.fields.id.getDbName()} and ${SqlDatabase.filterToRaw<volunteerInTask>(
|
|
16
|
+
// repo(volunteerInTask),
|
|
17
|
+
// {
|
|
18
|
+
// canceled: false,
|
|
19
|
+
// }
|
|
20
|
+
// )}`
|
|
21
|
+
// },
|
|
22
|
+
// })
|
|
23
|
+
// ```
|
|
24
|
+
//p2 - consider includeInApi as AllowedForInstance
|
|
25
|
+
//p1 - why didn't this._.relations.statusChanges.insert({})work?
|
|
26
|
+
//p1 - active record with include thinks that the row was change!
|
|
27
|
+
//p1 - add docs for apply changes
|
|
28
|
+
//p1 - update related field with null should respect it's allowed null - otherwise we get a null error for that field.
|
|
29
|
+
//p1 - when the include doesn't find the many to one - it deletes the id!!!
|
|
30
|
+
//y1 - discuss a default date formatter
|
|
31
|
+
//p1 - consider using this in saving etc...
|
package/graphql.js
CHANGED
|
@@ -908,7 +908,7 @@ function translateWhereToRestBody(fields, _a) {
|
|
|
908
908
|
var result = {};
|
|
909
909
|
var _loop_3 = function (field) {
|
|
910
910
|
var e_8, _c;
|
|
911
|
-
if (field.
|
|
911
|
+
if (field.options.includeInApi === false)
|
|
912
912
|
return "continue";
|
|
913
913
|
var condition = where[field.key];
|
|
914
914
|
if (condition) {
|
package/index.d.ts
CHANGED
|
@@ -30,4 +30,16 @@ export { ValueConverters } from './src/valueConverters';
|
|
|
30
30
|
export { remult } from './src/remult-proxy';
|
|
31
31
|
export { SubscriptionServer, LiveQueryStorage, StoredQuery, InMemoryLiveQueryStorage, } from './src/live-query/SubscriptionServer';
|
|
32
32
|
export { SubscriptionListener, SubscriptionClientConnection, SubscriptionClient, SubscriptionChannel, LiveQueryChange, Unsubscribe, } from './src/live-query/SubscriptionChannel';
|
|
33
|
+
/**
|
|
34
|
+
* A convenient shortcut function to quickly obtain a repository for a specific entity type in Remult.
|
|
35
|
+
*
|
|
36
|
+
* @param entity The entity class type for which you want to get a repository.
|
|
37
|
+
* @returns A repository instance for the specified entity type.
|
|
38
|
+
*
|
|
39
|
+
* Example usage:
|
|
40
|
+
* ```ts
|
|
41
|
+
* await repo(Task).find()
|
|
42
|
+
* await repo(Customer).insert()
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
33
45
|
export declare function repo<entityType>(entity: ClassType<entityType>): import("./src/remult3/remult3").Repository<entityType>;
|
package/index.js
CHANGED
|
@@ -67,6 +67,18 @@ var SubscriptionServer_1 = require("./src/live-query/SubscriptionServer");
|
|
|
67
67
|
Object.defineProperty(exports, "InMemoryLiveQueryStorage", { enumerable: true, get: function () { return SubscriptionServer_1.InMemoryLiveQueryStorage; } });
|
|
68
68
|
var SubscriptionChannel_1 = require("./src/live-query/SubscriptionChannel");
|
|
69
69
|
Object.defineProperty(exports, "SubscriptionChannel", { enumerable: true, get: function () { return SubscriptionChannel_1.SubscriptionChannel; } });
|
|
70
|
+
/**
|
|
71
|
+
* A convenient shortcut function to quickly obtain a repository for a specific entity type in Remult.
|
|
72
|
+
*
|
|
73
|
+
* @param entity The entity class type for which you want to get a repository.
|
|
74
|
+
* @returns A repository instance for the specified entity type.
|
|
75
|
+
*
|
|
76
|
+
* Example usage:
|
|
77
|
+
* ```ts
|
|
78
|
+
* await repo(Task).find()
|
|
79
|
+
* await repo(Customer).insert()
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
70
82
|
function repo(entity) {
|
|
71
83
|
return remult_proxy_2.remult.repo(entity);
|
|
72
84
|
}
|
package/package.json
CHANGED
package/src/CompoundIdField.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare class CompoundIdField implements FieldMetadata<string> {
|
|
|
6
6
|
constructor(...columns: FieldMetadata[]);
|
|
7
7
|
apiUpdateAllowed(item: any): boolean;
|
|
8
8
|
displayValue(item: any): string;
|
|
9
|
-
includedInApi: boolean;
|
|
9
|
+
includedInApi(item: any): boolean;
|
|
10
10
|
toInput(value: string, inputType?: string): string;
|
|
11
11
|
fromInput(inputValue: string, inputType?: string): string;
|
|
12
12
|
getDbName(): Promise<string>;
|
package/src/CompoundIdField.js
CHANGED
|
@@ -15,6 +15,9 @@ var CompoundIdField = /** @class */ (function () {
|
|
|
15
15
|
CompoundIdField.prototype.displayValue = function (item) {
|
|
16
16
|
throw new Error('Method not implemented.');
|
|
17
17
|
};
|
|
18
|
+
CompoundIdField.prototype.includedInApi = function (item) {
|
|
19
|
+
throw new Error('Method not implemented.');
|
|
20
|
+
};
|
|
18
21
|
CompoundIdField.prototype.toInput = function (value, inputType) {
|
|
19
22
|
throw new Error('Method not implemented.');
|
|
20
23
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassType } from '../classType';
|
|
2
|
-
import type {
|
|
3
|
-
import type { EntityMetadata, FieldRef,
|
|
2
|
+
import type { AllowedForInstance } from './context';
|
|
3
|
+
import type { EntityMetadata, FieldRef, LifecycleEvent, OmitEB } from './remult3/remult3';
|
|
4
4
|
export interface FieldOptions<entityType = any, valueType = any> {
|
|
5
5
|
/** A human readable name for the field. Can be used to achieve a consistent caption for a field throughout the app
|
|
6
6
|
* @example
|
|
@@ -11,7 +11,7 @@ export interface FieldOptions<entityType = any, valueType = any> {
|
|
|
11
11
|
allowNull?: boolean;
|
|
12
12
|
/** If this field data is included in the api.
|
|
13
13
|
* @see [allowed](http://remult.dev/docs/allowed.html)*/
|
|
14
|
-
includeInApi?:
|
|
14
|
+
includeInApi?: AllowedForInstance<entityType>;
|
|
15
15
|
/** If this field data can be updated in the api.
|
|
16
16
|
* @see [allowed](http://remult.dev/docs/allowed.html)*/
|
|
17
17
|
allowApiUpdate?: AllowedForInstance<entityType>;
|
|
@@ -37,7 +37,7 @@ export interface FieldOptions<entityType = any, valueType = any> {
|
|
|
37
37
|
*/
|
|
38
38
|
validate?: ((entity: entityType, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>) | ((entity: entityType, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>)[];
|
|
39
39
|
/** Will be fired before this field is saved to the server/database */
|
|
40
|
-
saving?: (entity: entityType, e:
|
|
40
|
+
saving?: (entity: entityType, e: LifecycleEvent<entityType>, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>;
|
|
41
41
|
/** An expression that will determine this fields value on the backend and be provided to the front end*/
|
|
42
42
|
serverExpression?: (entity: entityType) => valueType | Promise<valueType>;
|
|
43
43
|
/** The name of the column in the database that holds the data for this field. If no name is set, the key will be used instead.
|
|
@@ -134,7 +134,7 @@ export interface FieldMetadata<valueType = any, entityType = any> {
|
|
|
134
134
|
*/
|
|
135
135
|
displayValue(item: Partial<OmitEB<entityType>>): string;
|
|
136
136
|
apiUpdateAllowed(item?: Partial<OmitEB<entityType>>): boolean;
|
|
137
|
-
|
|
137
|
+
includedInApi(item?: Partial<OmitEB<entityType>>): boolean;
|
|
138
138
|
/** Adapts the value for usage with html input
|
|
139
139
|
* @example
|
|
140
140
|
* @Fields.dateOnly()
|
package/src/context.js
CHANGED
|
@@ -450,3 +450,6 @@ var transactionLiveQueryPublisher = /** @class */ (function () {
|
|
|
450
450
|
};
|
|
451
451
|
return transactionLiveQueryPublisher;
|
|
452
452
|
}());
|
|
453
|
+
//p1 - seems that after backend methods relations are loaded for some reason - see trempim - intake doRequest backend method
|
|
454
|
+
//p1 - reconsider the case in tremping where create user id was updated with some user and not the actual user
|
|
455
|
+
//[ ] - when value changes for field with error, clear error - so the user will feel comfortable
|
package/src/entity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Allowed, AllowedForInstance } from './context';
|
|
2
2
|
import type { FieldMetadata } from './column-interfaces';
|
|
3
|
-
import type { EntityFilter, EntityIdFields, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata,
|
|
3
|
+
import type { EntityFilter, EntityIdFields, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata, LifecycleEvent } from './remult3/remult3';
|
|
4
4
|
export interface EntityOptions<entityType = any> {
|
|
5
5
|
/**A human readable name for the entity */
|
|
6
6
|
caption?: string;
|
|
@@ -55,20 +55,51 @@ export interface EntityOptions<entityType = any> {
|
|
|
55
55
|
* this is the place to run logic that we want to run in any case before an entity is saved.
|
|
56
56
|
* @example
|
|
57
57
|
* @Entity<Task>("tasks", {
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*}
|
|
58
|
+
* saving: async (task, e) => {
|
|
59
|
+
* if (e.isNew) {
|
|
60
|
+
* task.createdAt = new Date(); // Set the creation date for new tasks.
|
|
61
|
+
* }
|
|
62
|
+
* task.lastUpdated = new Date(); // Update the last updated date.
|
|
63
|
+
* },
|
|
64
|
+
* })
|
|
65
|
+
* @param entity - The instance of the entity being saved.
|
|
66
|
+
* @param event - an @link LifeCycleEvent object
|
|
67
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
62
68
|
*/
|
|
63
|
-
saving?: (
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
saving?: (entity: entityType, event: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
70
|
+
/**
|
|
71
|
+
* A hook that runs after an entity has been successfully saved.
|
|
72
|
+
*
|
|
73
|
+
* @param entity The instance of the entity that was saved.
|
|
74
|
+
* @param event - an @link LifeCycleEvent object
|
|
75
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
76
|
+
*/
|
|
77
|
+
saved?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
78
|
+
/**
|
|
79
|
+
* A hook that runs before an entity is deleted.
|
|
80
|
+
*
|
|
81
|
+
* @param entity The instance of the entity being deleted.
|
|
82
|
+
* @param event - an @link LifeCycleEvent object
|
|
83
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
84
|
+
*/
|
|
85
|
+
deleting?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
86
|
+
/**
|
|
87
|
+
* A hook that runs after an entity has been successfully deleted.
|
|
88
|
+
*
|
|
89
|
+
* @param entity The instance of the entity that was deleted.
|
|
90
|
+
* @param event - an @link LifeCycleEvent object
|
|
91
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
92
|
+
*/
|
|
93
|
+
deleted?: (entity: entityType, e: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
94
|
+
/**
|
|
95
|
+
* A hook that runs to perform validation checks on an entity before saving.
|
|
96
|
+
* This hook is also executed on the frontend.
|
|
97
|
+
*
|
|
98
|
+
* @param entity The instance of the entity being validated.
|
|
99
|
+
* @param event - an @link LifeCycleEvent object
|
|
100
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
101
|
+
*/
|
|
102
|
+
validation?: (entity: entityType, ref: LifecycleEvent<entityType>) => Promise<any> | any;
|
|
72
103
|
/** The name of the table in the database that holds the data for this entity.
|
|
73
104
|
* If no name is set, the `key` will be used instead.
|
|
74
105
|
* @example
|
|
@@ -84,10 +115,10 @@ export interface EntityOptions<entityType = any> {
|
|
|
84
115
|
/** An arrow function that identifies the `id` column to use for this entity
|
|
85
116
|
* @example
|
|
86
117
|
* //Single column id
|
|
87
|
-
* @Entity<Products>("products", { id:
|
|
118
|
+
* @Entity<Products>("products", { id: {productCode: true} })
|
|
88
119
|
* @example
|
|
89
120
|
* //Multiple columns id
|
|
90
|
-
* @Entity<OrderDetails>("orderDetails", { id:
|
|
121
|
+
* @Entity<OrderDetails>("orderDetails", { id:{ orderId:true, productCode:true} })
|
|
91
122
|
*/
|
|
92
123
|
id?: EntityIdFields<entityType> | ((entity: FieldsMetadata<entityType>) => FieldMetadata | FieldMetadata[]);
|
|
93
124
|
entityRefInit?: (ref: EntityRef<entityType>, row: entityType) => void;
|
|
@@ -190,7 +190,7 @@ export declare class columnDefsImpl implements FieldMetadata {
|
|
|
190
190
|
constructor(settings: FieldOptions, entityDefs: EntityFullInfo<any>, remult: Remult);
|
|
191
191
|
apiUpdateAllowed(item?: any): boolean;
|
|
192
192
|
displayValue(item: any): string;
|
|
193
|
-
|
|
193
|
+
includedInApi(item?: any): boolean;
|
|
194
194
|
toInput(value: any, inputType?: string): string;
|
|
195
195
|
fromInput(inputValue: string, inputType?: string): any;
|
|
196
196
|
getDbName(): Promise<string>;
|
|
@@ -1635,7 +1635,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1635
1635
|
var col = _c.value;
|
|
1636
1636
|
if (!this.remult ||
|
|
1637
1637
|
col.includeInApi === undefined ||
|
|
1638
|
-
this.remult.
|
|
1638
|
+
this.remult.isAllowedForInstance(this.instance, col.includeInApi)) {
|
|
1639
1639
|
var val = void 0;
|
|
1640
1640
|
var lu = this.lookups.get(col.key);
|
|
1641
1641
|
var disable = false;
|
|
@@ -1686,7 +1686,7 @@ var rowHelperBase = /** @class */ (function () {
|
|
|
1686
1686
|
col = _b.value;
|
|
1687
1687
|
if (keys.includes(col.key))
|
|
1688
1688
|
if (col.includeInApi === undefined ||
|
|
1689
|
-
this.remult.
|
|
1689
|
+
this.remult.isAllowedForInstance(this.instance, col.includeInApi)) {
|
|
1690
1690
|
if (!this.remult ||
|
|
1691
1691
|
ignoreApiAllowed ||
|
|
1692
1692
|
col.allowApiUpdate === undefined ||
|
|
@@ -2264,7 +2264,7 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2264
2264
|
};
|
|
2265
2265
|
rowHelperImplementation.prototype.__performColumnAndEntityValidations = function () {
|
|
2266
2266
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
2267
|
-
var _a, _b, c, col, e_37_1, _c, _d, listener, e_38_1;
|
|
2267
|
+
var _a, _b, c, col, e_37_1, e, _c, _d, listener, e_38_1;
|
|
2268
2268
|
var e_37, _e, e_38, _f;
|
|
2269
2269
|
return tslib_1.__generator(this, function (_g) {
|
|
2270
2270
|
switch (_g.label) {
|
|
@@ -2297,7 +2297,8 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2297
2297
|
return [7 /*endfinally*/];
|
|
2298
2298
|
case 7:
|
|
2299
2299
|
if (!this.info.entityInfo.validation) return [3 /*break*/, 9];
|
|
2300
|
-
|
|
2300
|
+
e = this.buildLifeCycleEvent(function () { });
|
|
2301
|
+
return [4 /*yield*/, this.info.entityInfo.validation(this.instance, e)];
|
|
2301
2302
|
case 8:
|
|
2302
2303
|
_g.sent();
|
|
2303
2304
|
_g.label = 9;
|
|
@@ -2725,15 +2726,11 @@ var columnDefsImpl = /** @class */ (function () {
|
|
|
2725
2726
|
.getEntityMetadataWithoutBreakingTheEntity(item)
|
|
2726
2727
|
.fields.find(this.key).displayValue;
|
|
2727
2728
|
};
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
},
|
|
2734
|
-
enumerable: false,
|
|
2735
|
-
configurable: true
|
|
2736
|
-
});
|
|
2729
|
+
columnDefsImpl.prototype.includedInApi = function (item) {
|
|
2730
|
+
if (this.options.includeInApi === undefined)
|
|
2731
|
+
return true;
|
|
2732
|
+
return this.remult.isAllowedForInstance(item, this.options.includeInApi);
|
|
2733
|
+
};
|
|
2737
2734
|
columnDefsImpl.prototype.toInput = function (value, inputType) {
|
|
2738
2735
|
return this.valueConverter.toInput(value, inputType);
|
|
2739
2736
|
};
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -29,14 +29,48 @@ export interface EntityRef<entityType> extends Subscribable {
|
|
|
29
29
|
readonly apiInsertAllowed: boolean;
|
|
30
30
|
readonly isLoading: boolean;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Represents a lifecycle event associated with an entity instance. These events
|
|
34
|
+
* are triggered during various stages of the entity's lifecycle, such as validation,
|
|
35
|
+
* saving, saved, deleting, and deleted.
|
|
36
|
+
*
|
|
37
|
+
* @template entityType The type of the entity associated with the event.
|
|
38
|
+
* @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
|
|
39
|
+
*/
|
|
40
|
+
export interface LifecycleEvent<entityType> {
|
|
41
|
+
/**
|
|
42
|
+
* Indicates whether the entity is new or existing.
|
|
43
|
+
*/
|
|
33
44
|
isNew: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* A reference to the fields of the entity, providing access to its properties.
|
|
47
|
+
*/
|
|
34
48
|
fields: FieldsRef<entityType>;
|
|
49
|
+
/**
|
|
50
|
+
* The ID of the entity.
|
|
51
|
+
*/
|
|
35
52
|
id: idType<entityType>;
|
|
53
|
+
/**
|
|
54
|
+
* The original ID of the entity, useful for tracking changes.
|
|
55
|
+
*/
|
|
36
56
|
originalId: idType<entityType>;
|
|
57
|
+
/**
|
|
58
|
+
* The repository associated with the entity, providing access to repository methods.
|
|
59
|
+
*/
|
|
37
60
|
repository: Repository<entityType>;
|
|
61
|
+
/**
|
|
62
|
+
* Metadata describing the entity's structure and configuration.
|
|
63
|
+
*/
|
|
38
64
|
metadata: EntityMetadata<entityType>;
|
|
65
|
+
/**
|
|
66
|
+
* A function that can be used to prevent the default behavior associated with
|
|
67
|
+
* the lifecycle event.
|
|
68
|
+
*/
|
|
39
69
|
preventDefault: VoidFunction;
|
|
70
|
+
/**
|
|
71
|
+
* A reference to the repository relations associated with the entity, providing
|
|
72
|
+
* access to related entities and their data.
|
|
73
|
+
*/
|
|
40
74
|
relations: RepositoryRelations<entityType>;
|
|
41
75
|
}
|
|
42
76
|
export interface ControllerRef<entityType> extends Subscribable {
|
|
@@ -461,6 +495,12 @@ export interface RelationInfo {
|
|
|
461
495
|
* @template optionsType The type of find options to apply to the relation (default is FindOptionsBase<toEntity>).
|
|
462
496
|
*/
|
|
463
497
|
export type RelationOptions<fromEntity, toEntity, matchIdEntity, optionsType extends FindOptionsBase<toEntity> = FindOptionsBase<toEntity>> = {
|
|
498
|
+
/**
|
|
499
|
+
* An object specifying custom field names for the relation.
|
|
500
|
+
* Each key represents a field in the related entity, and its value is the corresponding field in the source entity.
|
|
501
|
+
* For example, `{ customerId: 'id' }` maps the 'customerId' field in the related entity to the 'id' field in the source entity.
|
|
502
|
+
* This is useful when you want to define custom field mappings for the relation.
|
|
503
|
+
*/
|
|
464
504
|
fields?: {
|
|
465
505
|
[K in keyof toEntity]?: keyof fromEntity;
|
|
466
506
|
};
|
package/src/remult3/remult3.js
CHANGED
|
@@ -2,3 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
//p1 - include relations in the api docs
|
|
4
4
|
//p1 - include Relation options in the api docs
|
|
5
|
+
//p1 - fix { allowApiRead: r => r.user.name === 'superman' } } in allowed for instace docs
|
|
6
|
+
//p1 - fix seeallowed in ref_entity
|
|
7
|
+
//p1 - write doc about controlling updates of rows...
|
|
8
|
+
//p1 - 'eventId' autocomplete in task app did not work
|
|
9
|
+
//p1 - need a way to extract the fields from the relation - for generating relation based sql
|
|
10
|
+
//p1 - remult object was used outside context
|
|
11
|
+
// ```
|
|
12
|
+
// sqlExpression: async (e) => {
|
|
13
|
+
// const v = await dbNamesOf(volunteerInTask)
|
|
14
|
+
// return `select true from ${v} where ${
|
|
15
|
+
// v.task
|
|
16
|
+
// }=${await e.getDbName()}.${await e.fields.id.getDbName()} and ${SqlDatabase.filterToRaw<volunteerInTask>(
|
|
17
|
+
// repo(volunteerInTask),
|
|
18
|
+
// {
|
|
19
|
+
// canceled: false,
|
|
20
|
+
// }
|
|
21
|
+
// )}`
|
|
22
|
+
// },
|
|
23
|
+
// })
|
|
24
|
+
// ```
|
|
25
|
+
//p2 - consider includeInApi as AllowedForInstance
|
|
26
|
+
//p1 - why didn't this._.relations.statusChanges.insert({})work?
|
|
27
|
+
//p1 - active record with include thinks that the row was change!
|
|
28
|
+
//p1 - add docs for apply changes
|
|
29
|
+
//p1 - update related field with null should respect it's allowed null - otherwise we get a null error for that field.
|
|
30
|
+
//p1 - when the include doesn't find the many to one - it deletes the id!!!
|
|
31
|
+
//y1 - discuss a default date formatter
|
|
32
|
+
//p1 - consider using this in saving etc...
|