remult 0.23.0-exp.2 → 0.23.0-exp.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -27
- package/esm/index.d.ts +4 -3
- package/esm/index.js +5 -2
- package/esm/src/column-interfaces.d.ts +2 -2
- package/esm/src/column.d.ts +3 -16
- package/esm/src/column.js +7 -42
- package/esm/src/entity.d.ts +6 -6
- package/esm/src/entity.js +1 -0
- package/esm/src/filter/filter-interfaces.d.ts +0 -14
- package/esm/src/filter/filter-interfaces.js +83 -3
- package/esm/src/remult-proxy.js +7 -1
- package/esm/src/remult3/Fields.d.ts +5 -4
- package/esm/src/remult3/Fields.js +26 -29
- package/esm/src/remult3/RepositoryImplementation.d.ts +2 -0
- package/esm/src/remult3/RepositoryImplementation.js +66 -18
- package/esm/src/remult3/relation-loader.js +4 -1
- package/esm/src/remult3/remult3.d.ts +17 -3
- package/esm/src/sort.js +23 -1
- package/index.d.ts +4 -3
- package/index.js +7 -3
- package/package.json +1 -1
- package/src/column-interfaces.d.ts +2 -2
- package/src/column.d.ts +3 -16
- package/src/column.js +7 -54
- package/src/entity.d.ts +6 -6
- package/src/entity.js +1 -0
- package/src/filter/filter-interfaces.d.ts +0 -14
- package/src/filter/filter-interfaces.js +97 -6
- package/src/remult-proxy.js +9 -1
- package/src/remult3/Fields.d.ts +5 -4
- package/src/remult3/Fields.js +33 -32
- package/src/remult3/RepositoryImplementation.d.ts +2 -0
- package/src/remult3/RepositoryImplementation.js +77 -24
- package/src/remult3/relation-loader.js +4 -1
- package/src/remult3/remult3.d.ts +17 -3
- package/src/sort.js +31 -6
package/README.md
CHANGED
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
<a href="https://discord.gg/GXHk7ZfuG5" rel="nofollow">
|
|
23
23
|
<img alt="Join Discord" src="https://badgen.net/discord/online-members/GXHk7ZfuG5?icon=discord&label=Discord"/>
|
|
24
24
|
</a>
|
|
25
|
-
</a>
|
|
26
25
|
</div>
|
|
27
26
|
|
|
28
27
|
<br/>
|
|
@@ -101,14 +100,14 @@ npm i remult
|
|
|
101
100
|
```ts
|
|
102
101
|
// shared/product.ts
|
|
103
102
|
|
|
104
|
-
import { Entity, Fields } from
|
|
103
|
+
import { Entity, Fields } from 'remult'
|
|
105
104
|
|
|
106
|
-
@Entity(
|
|
107
|
-
allowApiCrud: true
|
|
105
|
+
@Entity('products', {
|
|
106
|
+
allowApiCrud: true,
|
|
108
107
|
})
|
|
109
108
|
export class Product {
|
|
110
109
|
@Fields.string()
|
|
111
|
-
name =
|
|
110
|
+
name = ''
|
|
112
111
|
|
|
113
112
|
@Fields.number()
|
|
114
113
|
unitPrice = 0
|
|
@@ -120,17 +119,17 @@ export class Product {
|
|
|
120
119
|
```ts
|
|
121
120
|
// backend/index.ts
|
|
122
121
|
|
|
123
|
-
import express from
|
|
124
|
-
import { remultExpress } from
|
|
125
|
-
import { Product } from
|
|
122
|
+
import express from 'express'
|
|
123
|
+
import { remultExpress } from 'remult/remult-express'
|
|
124
|
+
import { Product } from '../shared/product'
|
|
126
125
|
|
|
127
126
|
const port = 3001
|
|
128
127
|
const app = express()
|
|
129
128
|
|
|
130
129
|
app.use(
|
|
131
130
|
remultExpress({
|
|
132
|
-
entities: [Product]
|
|
133
|
-
})
|
|
131
|
+
entities: [Product],
|
|
132
|
+
}),
|
|
134
133
|
)
|
|
135
134
|
|
|
136
135
|
app.listen(port, () => {
|
|
@@ -151,13 +150,13 @@ app.listen(port, () => {
|
|
|
151
150
|
```ts
|
|
152
151
|
// frontend/code.ts
|
|
153
152
|
|
|
154
|
-
import { remult } from
|
|
155
|
-
import { Product } from
|
|
153
|
+
import { remult } from 'remult'
|
|
154
|
+
import { Product } from '../shared/product'
|
|
156
155
|
|
|
157
156
|
async function increasePriceOfTofu(priceIncrease: number) {
|
|
158
157
|
const productsRepo = remult.repo(Product)
|
|
159
158
|
|
|
160
|
-
const product = await productsRepo.findFirst({ name:
|
|
159
|
+
const product = await productsRepo.findFirst({ name: 'Tofu' }) // filter is passed through API request all the way to the db
|
|
161
160
|
product.unitPrice += priceIncrease
|
|
162
161
|
productsRepo.save(product) // mutation request updates the db with no boilerplate code
|
|
163
162
|
}
|
|
@@ -179,32 +178,32 @@ static async increasePriceOfTofu(priceIncrease: number) {
|
|
|
179
178
|
### :ballot_box_with_check: Data validation and constraints - defined once
|
|
180
179
|
|
|
181
180
|
```ts
|
|
182
|
-
import { Entity, Fields, Validators } from
|
|
181
|
+
import { Entity, Fields, Validators } from 'remult'
|
|
183
182
|
|
|
184
|
-
@Entity(
|
|
185
|
-
allowApiCrud: true
|
|
183
|
+
@Entity('products', {
|
|
184
|
+
allowApiCrud: true,
|
|
186
185
|
})
|
|
187
186
|
export class Product {
|
|
188
187
|
@Fields.string({
|
|
189
|
-
validate: Validators.required
|
|
188
|
+
validate: Validators.required,
|
|
190
189
|
})
|
|
191
|
-
name =
|
|
190
|
+
name = ''
|
|
192
191
|
|
|
193
192
|
@Fields.string<Product>({
|
|
194
193
|
validate: (product) => {
|
|
195
194
|
if (product.description.trim().length < 50) {
|
|
196
|
-
throw
|
|
195
|
+
throw 'too short'
|
|
197
196
|
}
|
|
198
|
-
}
|
|
197
|
+
},
|
|
199
198
|
})
|
|
200
|
-
description =
|
|
199
|
+
description = ''
|
|
201
200
|
|
|
202
201
|
@Fields.number({
|
|
203
202
|
validate: (_, field) => {
|
|
204
203
|
if (field.value < 0) {
|
|
205
|
-
field.error =
|
|
204
|
+
field.error = 'must not be less than 0' // or: throw "must not be less than 0";
|
|
206
205
|
}
|
|
207
|
-
}
|
|
206
|
+
},
|
|
208
207
|
})
|
|
209
208
|
unitPrice = 0
|
|
210
209
|
}
|
|
@@ -233,20 +232,20 @@ try {
|
|
|
233
232
|
### :lock: Secure the API with fine-grained authorization
|
|
234
233
|
|
|
235
234
|
```ts
|
|
236
|
-
@Entity<Article>(
|
|
235
|
+
@Entity<Article>('Articles', {
|
|
237
236
|
allowApiRead: true,
|
|
238
237
|
allowApiInsert: (_, remult) => remult.authenticated(),
|
|
239
|
-
allowApiUpdate: (article, remult) => article.author.id == remult.user.id
|
|
238
|
+
allowApiUpdate: (article, remult) => article.author.id == remult.user.id,
|
|
240
239
|
})
|
|
241
240
|
export class Article {
|
|
242
241
|
@Fields.string({ allowApiUpdate: false })
|
|
243
|
-
slug =
|
|
242
|
+
slug = ''
|
|
244
243
|
|
|
245
244
|
@Field(() => Profile, { allowApiUpdate: false })
|
|
246
245
|
author!: Profile
|
|
247
246
|
|
|
248
247
|
@Fields.string()
|
|
249
|
-
content =
|
|
248
|
+
content = ''
|
|
250
249
|
}
|
|
251
250
|
```
|
|
252
251
|
|
package/esm/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ClassType } from './classType';
|
|
2
|
+
export { OmitEB, 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, RelationOptionsBase, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, } from './src/remult3/remult3';
|
|
2
3
|
export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation';
|
|
3
4
|
export { Entity } from './src/remult3/entity';
|
|
4
5
|
export { getEntityRef } from './src/remult3/getEntityRef';
|
|
5
|
-
export { Field, Fields, StringFieldOptions } from './src/remult3/Fields';
|
|
6
|
+
export { Field, Fields, StringFieldOptions, Relations, } from './src/remult3/Fields';
|
|
6
7
|
export { IdEntity } from './src/remult3/IdEntity';
|
|
7
8
|
export { describeClass } from './src/remult3/DecoratorReplacer';
|
|
8
9
|
export { EntityOptions } from './src/entity';
|
|
@@ -21,7 +22,6 @@ export { Controller, BackendMethodOptions, BackendMethod, ProgressListener, } fr
|
|
|
21
22
|
export { Allowed, Allow, Remult, RemultContext, ApiClient, isBackend, AllowedForInstance, EventDispatcher, EventSource, UserInfo, } from './src/context';
|
|
22
23
|
export { ExternalHttpProvider } from './src/buildRestDataProvider';
|
|
23
24
|
export { SortSegment, Sort } from './src/sort';
|
|
24
|
-
export { OneToMany } from './src/column';
|
|
25
25
|
export { CompoundIdField } from './src/CompoundIdField';
|
|
26
26
|
export { Filter } from './src/filter/filter-interfaces';
|
|
27
27
|
export { UrlBuilder } from './urlBuilder';
|
|
@@ -30,3 +30,4 @@ 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
|
+
export declare function repo<entityType>(entity: ClassType<entityType>): import("./src/remult3/remult3").Repository<entityType>;
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation';
|
|
2
2
|
export { Entity } from './src/remult3/entity';
|
|
3
3
|
export { getEntityRef } from './src/remult3/getEntityRef';
|
|
4
|
-
export { Field, Fields } from './src/remult3/Fields';
|
|
4
|
+
export { Field, Fields, Relations, } from './src/remult3/Fields';
|
|
5
5
|
export { IdEntity } from './src/remult3/IdEntity';
|
|
6
6
|
export { describeClass } from './src/remult3/DecoratorReplacer';
|
|
7
7
|
export { RestDataProvider } from './src/data-providers/rest-data-provider'; //V
|
|
@@ -15,13 +15,16 @@ export { JsonDataProvider, } from './src/data-providers/json-data-provider'; //V
|
|
|
15
15
|
export { Controller, BackendMethod, ProgressListener, } from './src/server-action';
|
|
16
16
|
export { Allow, Remult, isBackend, EventSource, } from './src/context';
|
|
17
17
|
export { Sort } from './src/sort';
|
|
18
|
-
export { OneToMany } from './src/column';
|
|
19
18
|
export { CompoundIdField } from './src/CompoundIdField';
|
|
20
19
|
export { Filter } from './src/filter/filter-interfaces';
|
|
21
20
|
export { UrlBuilder } from './urlBuilder';
|
|
22
21
|
export { Validators } from './src/validators';
|
|
23
22
|
export { ValueConverters } from './src/valueConverters';
|
|
24
23
|
export { remult } from './src/remult-proxy';
|
|
24
|
+
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
|
+
export function repo(entity) {
|
|
29
|
+
return remult.repo(entity);
|
|
30
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassType } from '../classType';
|
|
2
2
|
import type { Allowed, AllowedForInstance } from './context';
|
|
3
|
-
import type { EntityMetadata, FieldRef, OmitEB } from './remult3/remult3';
|
|
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
|
|
@@ -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, fieldRef: FieldRef<entityType, valueType>) => any | Promise<any>;
|
|
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.
|
package/esm/src/column.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { idType } from './remult3/remult3';
|
|
2
2
|
import type { RepositoryImplementation } from './remult3/RepositoryImplementation';
|
|
3
3
|
export declare function makeTitle(name: string): string;
|
|
4
4
|
export declare class LookupColumn<T> {
|
|
5
5
|
private repository;
|
|
6
|
-
private
|
|
6
|
+
private isReferenceRelation;
|
|
7
7
|
toJson(): any;
|
|
8
8
|
setId(val: any): void;
|
|
9
9
|
waitLoadOf(id: any): Promise<T>;
|
|
@@ -13,20 +13,7 @@ export declare class LookupColumn<T> {
|
|
|
13
13
|
};
|
|
14
14
|
set(item: T): void;
|
|
15
15
|
id: idType<T>;
|
|
16
|
-
constructor(repository: RepositoryImplementation<T>,
|
|
16
|
+
constructor(repository: RepositoryImplementation<T>, isReferenceRelation: any);
|
|
17
17
|
get item(): T;
|
|
18
18
|
waitLoad(): Promise<T>;
|
|
19
19
|
}
|
|
20
|
-
export declare class OneToMany<T> {
|
|
21
|
-
private provider;
|
|
22
|
-
private settings?;
|
|
23
|
-
constructor(provider: Repository<T>, settings?: {
|
|
24
|
-
create?: (newItem: T) => void;
|
|
25
|
-
} & FindOptions<T>);
|
|
26
|
-
private _items;
|
|
27
|
-
private _currentPromise;
|
|
28
|
-
get lazyItems(): T[];
|
|
29
|
-
load(): Promise<T[]>;
|
|
30
|
-
private find;
|
|
31
|
-
create(item?: Partial<T>): T;
|
|
32
|
-
}
|
package/esm/src/column.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { assign } from '../assign';
|
|
2
|
-
import { __updateEntityBasedOnWhere } from './remult3/__updateEntityBasedOnWhere';
|
|
3
1
|
import { getEntityRef } from './remult3/getEntityRef';
|
|
4
2
|
export function makeTitle(name) {
|
|
5
3
|
// insert a space before all caps
|
|
@@ -12,7 +10,7 @@ export function makeTitle(name) {
|
|
|
12
10
|
}
|
|
13
11
|
export class LookupColumn {
|
|
14
12
|
repository;
|
|
15
|
-
|
|
13
|
+
isReferenceRelation;
|
|
16
14
|
toJson() {
|
|
17
15
|
if (!this.storedItem)
|
|
18
16
|
return undefined;
|
|
@@ -33,7 +31,9 @@ export class LookupColumn {
|
|
|
33
31
|
get(id) {
|
|
34
32
|
if (id === undefined || id === null)
|
|
35
33
|
return null;
|
|
36
|
-
|
|
34
|
+
if (this.isReferenceRelation && !this.storedItem)
|
|
35
|
+
return undefined;
|
|
36
|
+
return this.repository.getCachedById(id, this.isReferenceRelation);
|
|
37
37
|
}
|
|
38
38
|
storedItem;
|
|
39
39
|
set(item) {
|
|
@@ -43,7 +43,7 @@ export class LookupColumn {
|
|
|
43
43
|
this.id = item;
|
|
44
44
|
else {
|
|
45
45
|
let eo = getEntityRef(item, false);
|
|
46
|
-
if (eo) {
|
|
46
|
+
if (eo && !this.isReferenceRelation) {
|
|
47
47
|
this.repository.addToCache(item);
|
|
48
48
|
this.id = eo.getId();
|
|
49
49
|
}
|
|
@@ -61,9 +61,9 @@ export class LookupColumn {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
id;
|
|
64
|
-
constructor(repository,
|
|
64
|
+
constructor(repository, isReferenceRelation) {
|
|
65
65
|
this.repository = repository;
|
|
66
|
-
this.
|
|
66
|
+
this.isReferenceRelation = isReferenceRelation;
|
|
67
67
|
}
|
|
68
68
|
get item() {
|
|
69
69
|
if (this.storedItem)
|
|
@@ -74,38 +74,3 @@ export class LookupColumn {
|
|
|
74
74
|
return this.waitLoadOf(this.id);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
9000;
|
|
78
|
-
export class OneToMany {
|
|
79
|
-
provider;
|
|
80
|
-
settings;
|
|
81
|
-
constructor(provider, settings) {
|
|
82
|
-
this.provider = provider;
|
|
83
|
-
this.settings = settings;
|
|
84
|
-
}
|
|
85
|
-
_items;
|
|
86
|
-
_currentPromise;
|
|
87
|
-
get lazyItems() {
|
|
88
|
-
this.load();
|
|
89
|
-
return this._items;
|
|
90
|
-
}
|
|
91
|
-
async load() {
|
|
92
|
-
if (this._currentPromise != null)
|
|
93
|
-
return this._currentPromise;
|
|
94
|
-
if (this._items === undefined)
|
|
95
|
-
this._items = [];
|
|
96
|
-
return (this._currentPromise = this.find().then((x) => {
|
|
97
|
-
this._items.splice(0);
|
|
98
|
-
this._items.push(...x);
|
|
99
|
-
return this._items;
|
|
100
|
-
}));
|
|
101
|
-
}
|
|
102
|
-
async find() {
|
|
103
|
-
return this.provider.find(this.settings);
|
|
104
|
-
}
|
|
105
|
-
create(item) {
|
|
106
|
-
let r = this.provider.create();
|
|
107
|
-
__updateEntityBasedOnWhere(this.provider.metadata, this.settings.where, r);
|
|
108
|
-
assign(r, item);
|
|
109
|
-
return r;
|
|
110
|
-
}
|
|
111
|
-
}
|
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, EntityMetadata, EntityOrderBy, EntityRef, FieldsMetadata } from './remult3/remult3';
|
|
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;
|
|
@@ -60,13 +60,13 @@ export interface EntityOptions<entityType = any> {
|
|
|
60
60
|
* }
|
|
61
61
|
*})
|
|
62
62
|
*/
|
|
63
|
-
saving?: (row: entityType,
|
|
63
|
+
saving?: (row: entityType, e: LifeCycleEvent<entityType>) => Promise<any> | any;
|
|
64
64
|
/** will be called after the Entity was saved to the data source. */
|
|
65
|
-
saved?: (row: entityType) => Promise<any> | any;
|
|
65
|
+
saved?: (row: entityType, e: LifeCycleEvent<entityType>) => Promise<any> | any;
|
|
66
66
|
/** Will be called before an Entity is deleted. */
|
|
67
|
-
deleting?: (row: entityType) => Promise<any> | any;
|
|
67
|
+
deleting?: (row: entityType, e: LifeCycleEvent<entityType>) => Promise<any> | any;
|
|
68
68
|
/** Will be called after an Entity is deleted */
|
|
69
|
-
deleted?: (row: entityType) => Promise<any> | any;
|
|
69
|
+
deleted?: (row: entityType, e: LifeCycleEvent<entityType>) => Promise<any> | any;
|
|
70
70
|
/** Will be called when the entity is being validated, usually prior to the `saving` event */
|
|
71
71
|
validation?: (row: entityType, ref: EntityRef<entityType>) => Promise<any> | any;
|
|
72
72
|
/** The name of the table in the database that holds the data for this entity.
|
|
@@ -89,7 +89,7 @@ export interface EntityOptions<entityType = any> {
|
|
|
89
89
|
* //Multiple columns id
|
|
90
90
|
* @Entity<OrderDetails>("orderDetails", { id:od=> [od.orderId, od.productCode] })
|
|
91
91
|
*/
|
|
92
|
-
id?: (entity: FieldsMetadata<entityType>) => FieldMetadata | FieldMetadata[];
|
|
92
|
+
id?: EntityIdFields<entityType> | ((entity: FieldsMetadata<entityType>) => FieldMetadata | FieldMetadata[]);
|
|
93
93
|
entityRefInit?: (ref: EntityRef<entityType>, row: entityType) => void;
|
|
94
94
|
apiRequireId?: Allowed;
|
|
95
95
|
}
|
package/esm/src/entity.js
CHANGED
|
@@ -14,20 +14,6 @@ export declare class Filter {
|
|
|
14
14
|
static entityFilterFromJson<T>(entityDefs: EntityMetadata<T>, packed: any): EntityFilter<T>;
|
|
15
15
|
static translateCustomWhere<T>(r: Filter, entity: EntityMetadata<T>, remult: Remult): Promise<Filter>;
|
|
16
16
|
}
|
|
17
|
-
export declare class filterHelper {
|
|
18
|
-
metadata: FieldMetadata;
|
|
19
|
-
constructor(metadata: FieldMetadata);
|
|
20
|
-
processVal(val: any): any;
|
|
21
|
-
contains(val: string): Filter;
|
|
22
|
-
isLessThan(val: any): Filter;
|
|
23
|
-
isGreaterOrEqualTo(val: any): Filter;
|
|
24
|
-
isNotIn(values: any[]): Filter;
|
|
25
|
-
isDifferentFrom(val: any): Filter;
|
|
26
|
-
isLessOrEqualTo(val: any): Filter;
|
|
27
|
-
isGreaterThan(val: any): Filter;
|
|
28
|
-
isEqualTo(val: any): Filter;
|
|
29
|
-
isIn(val: any[]): Filter;
|
|
30
|
-
}
|
|
31
17
|
export interface FilterConsumer {
|
|
32
18
|
or(orElements: Filter[]): any;
|
|
33
19
|
isEqualTo(col: FieldMetadata, val: any): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getEntityRef, getEntitySettings } from '../remult3/getEntityRef';
|
|
2
|
+
import { getRelationInfo } from '../remult3/relationInfoMember';
|
|
2
3
|
export class Filter {
|
|
3
4
|
apply;
|
|
4
5
|
constructor(apply) {
|
|
@@ -49,7 +50,14 @@ export class Filter {
|
|
|
49
50
|
result.push(new Filter((x) => x.databaseCustom(fieldToFilter)));
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
52
|
-
|
|
53
|
+
const field = entity.fields[key];
|
|
54
|
+
const rel = getRelationInfo(field.options);
|
|
55
|
+
const op = field.options;
|
|
56
|
+
let fh = rel?.type === 'toOne'
|
|
57
|
+
? op.fields
|
|
58
|
+
? new manyToOneFilterHelper(field, entity.fields, op)
|
|
59
|
+
: new toOneFilterHelper(entity.fields[op.field])
|
|
60
|
+
: new filterHelper(field);
|
|
53
61
|
let found = false;
|
|
54
62
|
if (fieldToFilter !== undefined && fieldToFilter != null) {
|
|
55
63
|
if (fieldToFilter.$id)
|
|
@@ -147,7 +155,7 @@ export class Filter {
|
|
|
147
155
|
return r;
|
|
148
156
|
}
|
|
149
157
|
}
|
|
150
|
-
|
|
158
|
+
class filterHelper {
|
|
151
159
|
metadata;
|
|
152
160
|
constructor(metadata) {
|
|
153
161
|
this.metadata = metadata;
|
|
@@ -206,6 +214,79 @@ export class filterHelper {
|
|
|
206
214
|
return new Filter((add) => add.isIn(this.metadata, val));
|
|
207
215
|
}
|
|
208
216
|
}
|
|
217
|
+
class toOneFilterHelper extends filterHelper {
|
|
218
|
+
processVal(val) {
|
|
219
|
+
if (!val)
|
|
220
|
+
return null;
|
|
221
|
+
if (typeof val === 'string' || typeof val === 'number')
|
|
222
|
+
return val;
|
|
223
|
+
return getEntityRef(val).getId();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
class manyToOneFilterHelper {
|
|
227
|
+
metadata;
|
|
228
|
+
fields;
|
|
229
|
+
relationOptions;
|
|
230
|
+
constructor(metadata, fields, relationOptions) {
|
|
231
|
+
this.metadata = metadata;
|
|
232
|
+
this.fields = fields;
|
|
233
|
+
this.relationOptions = relationOptions;
|
|
234
|
+
}
|
|
235
|
+
processVal(val) {
|
|
236
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
237
|
+
}
|
|
238
|
+
contains(val) {
|
|
239
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
240
|
+
}
|
|
241
|
+
isLessThan(val) {
|
|
242
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
243
|
+
}
|
|
244
|
+
isGreaterOrEqualTo(val) {
|
|
245
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
246
|
+
}
|
|
247
|
+
isNotIn(values) {
|
|
248
|
+
return new Filter((add) => {
|
|
249
|
+
values.forEach((v) => this.isDifferentFrom(v).__applyToConsumer(add));
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
isDifferentFrom(val) {
|
|
253
|
+
return new Filter((add) => {
|
|
254
|
+
const or = [];
|
|
255
|
+
for (const key in this.relationOptions.fields) {
|
|
256
|
+
if (Object.prototype.hasOwnProperty.call(this.relationOptions.fields, key)) {
|
|
257
|
+
const keyInMyEntity = this.relationOptions.fields[key];
|
|
258
|
+
or.push(new Filter((add) => new filterHelper(this.fields.find(keyInMyEntity))
|
|
259
|
+
.isDifferentFrom(val[key])
|
|
260
|
+
.__applyToConsumer(add)));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
add.or(or);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
isLessOrEqualTo(val) {
|
|
267
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
268
|
+
}
|
|
269
|
+
isGreaterThan(val) {
|
|
270
|
+
throw new Error('Invalid for Many To One Relation Field');
|
|
271
|
+
}
|
|
272
|
+
isEqualTo(val) {
|
|
273
|
+
return new Filter((add) => {
|
|
274
|
+
for (const key in this.relationOptions.fields) {
|
|
275
|
+
if (Object.prototype.hasOwnProperty.call(this.relationOptions.fields, key)) {
|
|
276
|
+
const keyInMyEntity = this.relationOptions.fields[key];
|
|
277
|
+
new filterHelper(this.fields.find(keyInMyEntity))
|
|
278
|
+
.isEqualTo(val[key])
|
|
279
|
+
.__applyToConsumer(add);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
isIn(val) {
|
|
285
|
+
return new Filter((add) => {
|
|
286
|
+
add.or(val.map((v) => this.isEqualTo(v)));
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
209
290
|
export class AndFilter extends Filter {
|
|
210
291
|
filters;
|
|
211
292
|
constructor(...filters) {
|
|
@@ -350,7 +431,6 @@ export function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
350
431
|
}
|
|
351
432
|
}
|
|
352
433
|
}
|
|
353
|
-
let c = new filterHelper(col);
|
|
354
434
|
addFilter('', (val) => val);
|
|
355
435
|
addFilter('.gt', (val) => ({ $gt: val }));
|
|
356
436
|
addFilter('.gte', (val) => ({ $gte: val }));
|
package/esm/src/remult-proxy.js
CHANGED
|
@@ -81,6 +81,10 @@ export class RemultProxy {
|
|
|
81
81
|
get fields() {
|
|
82
82
|
return self.remultFactory().repo(...args).metadata.fields;
|
|
83
83
|
},
|
|
84
|
+
relations: (args2) => self
|
|
85
|
+
.remultFactory()
|
|
86
|
+
.repo(...args)
|
|
87
|
+
.relations(args2),
|
|
84
88
|
validate: (a, b) => self
|
|
85
89
|
.remultFactory()
|
|
86
90
|
.repo(...args)
|
|
@@ -135,7 +139,9 @@ export class RemultProxy {
|
|
|
135
139
|
.repo(...args)
|
|
136
140
|
.liveQuery(...args2),
|
|
137
141
|
//@ts-ignore
|
|
138
|
-
addToCache: (a) => self
|
|
142
|
+
addToCache: (a) => self
|
|
143
|
+
.remultFactory()
|
|
144
|
+
.repo(...args).addToCache(a),
|
|
139
145
|
get metadata() {
|
|
140
146
|
return self.remultFactory().repo(...args).metadata;
|
|
141
147
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ClassType } from '../../classType';
|
|
2
2
|
import type { FieldOptions } from '../column-interfaces';
|
|
3
3
|
import type { Remult } from '../context';
|
|
4
|
-
import type { FindOptions, RelationOptions
|
|
4
|
+
import type { FindOptions, RelationOptions } from './remult3';
|
|
5
5
|
import { type ClassFieldDecoratorContextStub } from './RepositoryImplementation';
|
|
6
6
|
export declare class Fields {
|
|
7
7
|
/**
|
|
@@ -20,11 +20,12 @@ export declare class Fields {
|
|
|
20
20
|
static cuid<entityType = any>(...options: (FieldOptions<entityType, string> | ((options: FieldOptions<entityType, string>, remult: Remult) => void))[]): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, string | undefined>, c?: any) => void;
|
|
21
21
|
static string<entityType = any>(...options: (StringFieldOptions<entityType> | ((options: StringFieldOptions<entityType>, remult: Remult) => void))[]): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, string | undefined>, c?: any) => void;
|
|
22
22
|
static boolean<entityType = any>(...options: (FieldOptions<entityType, boolean> | ((options: FieldOptions<entityType, boolean>, remult: Remult) => void))[]): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, boolean | undefined>, c?: any) => void;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
}
|
|
24
|
+
export declare class Relations {
|
|
25
|
+
static toOne<entityType, toEntityType>(toEntityType: () => ClassType<toEntityType>, options?: RelationOptions<entityType, toEntityType, entityType> | keyof entityType): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, toEntityType>, c?: any) => void;
|
|
26
|
+
static toMany<entityType, toEntityType>(toEntityType: () => ClassType<toEntityType>, options: (RelationOptions<entityType, toEntityType, toEntityType, FindOptions<toEntityType>> & {
|
|
25
27
|
fromEntityType?: ClassType<entityType>;
|
|
26
28
|
}) | keyof toEntityType): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, any>, c?: any) => void;
|
|
27
|
-
static one<entityType, toEntityType>(entity: ClassType<entityType>, toEntityType: () => ClassType<toEntityType>, options?: RelationOptions<entityType, toEntityType, entityType> | keyof entityType): (target: any, context: string | ClassFieldDecoratorContextStub<entityType, any>, c?: any) => void;
|
|
28
29
|
}
|
|
29
30
|
/**Decorates fields that should be used as fields.
|
|
30
31
|
* for more info see: [Field Types](https://remult.dev/docs/field-types.html)
|