remult 0.13.19 → 0.13.20
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/graphql.js +3 -3
- package/package.json +1 -1
- package/server/expressBridge.js +2 -0
- package/src/column-interfaces.d.ts +51 -10
- package/src/column.d.ts +0 -1
- package/src/column.js +0 -12
- package/src/context.d.ts +57 -14
- package/src/context.js +103 -75
- package/src/data-providers/rest-data-provider.d.ts +3 -2
- package/src/data-providers/rest-data-provider.js +56 -51
- package/src/data-providers/sql-database.js +2 -6
- package/src/entity.d.ts +31 -28
- package/src/remult3/RepositoryImplementation.d.ts +36 -0
- package/src/remult3/RepositoryImplementation.js +187 -125
- package/src/remult3/remult3.d.ts +83 -22
- package/src/server-action.d.ts +5 -1
- package/src/server-action.js +1 -0
- package/src/shared-tests/db-tests.db-tests.js +52 -1
- package/src/tests/testHelper.spec.js +2 -2
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -103,43 +103,80 @@ export interface EntityMetadata<entityType = any> {
|
|
|
103
103
|
getDbName(): Promise<string>;
|
|
104
104
|
}
|
|
105
105
|
export declare type OmitEB<T> = Omit<T, keyof import('./RepositoryImplementation').EntityBase>;
|
|
106
|
+
/**used to perform CRUD operations on an `entityType` */
|
|
106
107
|
export interface Repository<entityType> {
|
|
107
|
-
/**creates a json representation of the object */
|
|
108
|
-
fromJson(x: any, isNew?: boolean): Promise<entityType>;
|
|
109
|
-
metadata: EntityMetadata<entityType>;
|
|
110
108
|
/** returns a result array based on the provided options */
|
|
111
109
|
find(options?: FindOptions<entityType>): Promise<entityType[]>;
|
|
112
|
-
|
|
110
|
+
/** returns the first item that matchers the `where` condition */
|
|
113
111
|
findFirst(where?: EntityFilter<entityType>, options?: FindFirstOptions<entityType>): Promise<entityType>;
|
|
112
|
+
/** returns the items that matches the idm the result is cached unless specified differently in the `options` parameter */
|
|
114
113
|
findId(id: entityType extends {
|
|
115
114
|
id: number;
|
|
116
115
|
} ? number : entityType extends {
|
|
117
116
|
id: string;
|
|
118
117
|
} ? string : (string | number), options?: FindFirstOptionsBase<entityType>): Promise<entityType>;
|
|
118
|
+
/** An alternative form of fetching data from the API server, which is intended for operating on large numbers of entity objects.
|
|
119
|
+
*
|
|
120
|
+
* It also has it's own paging mechanism that can be used n paging scenarios.
|
|
121
|
+
*
|
|
122
|
+
* The `query` method doesn't return an array (as the `find` method) and instead returns an `iteratable` `QueryResult` object
|
|
123
|
+
* which supports iterations using the JavaScript `for await` statement.
|
|
124
|
+
* @example
|
|
125
|
+
* for await (const task of taskRepo.query()) {
|
|
126
|
+
* // do something.
|
|
127
|
+
* }
|
|
128
|
+
* */
|
|
129
|
+
query(options?: QueryOptions<entityType>): QueryResult<entityType>;
|
|
130
|
+
/** Returns a count of the items matching the criteria.
|
|
131
|
+
* @see [EntityFilter](http://remult.dev/docs/entityFilter.html)
|
|
132
|
+
* @example
|
|
133
|
+
* await taskRepo.count({ completed:false })
|
|
134
|
+
*/
|
|
119
135
|
count(where?: EntityFilter<entityType>): Promise<number>;
|
|
120
|
-
|
|
121
|
-
|
|
136
|
+
/** saves an item or item[] to the data source. It assumes that if an `id` value exists, it's an existing row - otherwise it's a new row
|
|
137
|
+
* @example
|
|
138
|
+
* await taskRepo.save({...task, completed:true })
|
|
139
|
+
*/
|
|
122
140
|
save(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
|
|
123
141
|
save(item: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
142
|
+
/**Insert an item or item[] to the data source
|
|
143
|
+
* @example
|
|
144
|
+
* await taskRepo.insert({title:"task a"})
|
|
145
|
+
* @example
|
|
146
|
+
* await taskRepo.insert([{title:"task a"}, {title:"task b", completed:true }])
|
|
147
|
+
*/
|
|
124
148
|
insert(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
|
|
125
149
|
insert(item: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
150
|
+
/** Updates an item, based on it's `id`
|
|
151
|
+
* @example
|
|
152
|
+
* taskRepo.update(task.id,{...task,completed:true})
|
|
153
|
+
*/
|
|
126
154
|
update(id: (entityType extends {
|
|
127
155
|
id: number;
|
|
128
156
|
} ? number : entityType extends {
|
|
129
157
|
id: string;
|
|
130
158
|
} ? string : (string | number)), item: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
159
|
+
/** Deletes an Item*/
|
|
131
160
|
delete(id: (entityType extends {
|
|
132
161
|
id: number;
|
|
133
162
|
} ? number : entityType extends {
|
|
134
163
|
id: string;
|
|
135
164
|
} ? string : (string | number))): Promise<void>;
|
|
136
165
|
delete(item: entityType): Promise<void>;
|
|
166
|
+
/** Creates an instance of an item. It'll not be saved to the data source unless `save` or `insert` will be called for that item */
|
|
167
|
+
create(item?: Partial<OmitEB<entityType>>): entityType;
|
|
168
|
+
/** Translates a json object to an item instance */
|
|
169
|
+
fromJson(x: any, isNew?: boolean): Promise<entityType>;
|
|
170
|
+
/** returns an `entityRef` for an item returned by `create`, `find` etc... */
|
|
171
|
+
getEntityRef(item: entityType): EntityRef<entityType>;
|
|
172
|
+
/**The metadata for the `entity` */
|
|
173
|
+
metadata: EntityMetadata<entityType>;
|
|
137
174
|
addEventListener(listener: entityEventListener<entityType>): Unobserve;
|
|
138
175
|
}
|
|
139
176
|
export interface FindOptions<entityType> extends FindOptionsBase<entityType> {
|
|
140
177
|
/** Determines the number of rows returned by the request, on the browser the default is 100 rows
|
|
141
178
|
* @example
|
|
142
|
-
*
|
|
179
|
+
* await this.remult.repo(Products).find({
|
|
143
180
|
* limit:10,
|
|
144
181
|
* page:2
|
|
145
182
|
* })
|
|
@@ -147,24 +184,25 @@ export interface FindOptions<entityType> extends FindOptionsBase<entityType> {
|
|
|
147
184
|
limit?: number;
|
|
148
185
|
/** Determines the page number that will be used to extract the data
|
|
149
186
|
* @example
|
|
150
|
-
*
|
|
187
|
+
* await this.remult.repo(Products).find({
|
|
151
188
|
* limit:10,
|
|
152
189
|
* page:2
|
|
153
190
|
* })
|
|
154
191
|
*/
|
|
155
192
|
page?: number;
|
|
156
193
|
}
|
|
157
|
-
/** Determines the order of
|
|
194
|
+
/** Determines the order of items returned .
|
|
158
195
|
* @example
|
|
159
196
|
* await this.remult.repo(Products).find({ orderBy: { name: "asc" }})
|
|
160
197
|
* @example
|
|
161
|
-
* await this.remult.repo(Products).find({ orderBy: { price: "asc", name: "asc" }})
|
|
162
|
-
* @example
|
|
163
198
|
* await this.remult.repo(Products).find({ orderBy: { price: "desc", name: "asc" }})
|
|
164
199
|
*/
|
|
165
200
|
export declare type EntityOrderBy<entityType> = {
|
|
166
201
|
[Properties in keyof Partial<OmitEB<entityType>>]?: "asc" | "desc";
|
|
167
202
|
};
|
|
203
|
+
/**Used to filter the desired result set
|
|
204
|
+
* @see [EntityFilter](http://remult.dev/docs/entityFilter.html)
|
|
205
|
+
*/
|
|
168
206
|
export declare type EntityFilter<entityType> = {
|
|
169
207
|
[Properties in keyof Partial<OmitEB<entityType>>]?: (Partial<OmitEB<entityType>>[Properties] extends (number | Date | undefined) ? ComparisonValueFilter<Partial<OmitEB<entityType>>[Properties]> : Partial<OmitEB<entityType>>[Properties] extends (string | undefined) ? ContainsStringValueFilter & ComparisonValueFilter<string> : Partial<OmitEB<entityType>>[Properties] extends (boolean | undefined) ? ValueFilter<boolean> : Partial<OmitEB<entityType>>[Properties] extends ({
|
|
170
208
|
id: (string | number);
|
|
@@ -201,41 +239,64 @@ export interface LoadOptions<entityType> {
|
|
|
201
239
|
export interface FindOptionsBase<entityType> extends LoadOptions<entityType> {
|
|
202
240
|
/** filters the data
|
|
203
241
|
* @example
|
|
204
|
-
* where
|
|
205
|
-
* @see For more usage examples see [
|
|
242
|
+
* await taskRepo.find({where: { completed:false }})
|
|
243
|
+
* @see For more usage examples see [EntityFilter](https://remult.github.io/guide/entityFilter.html)
|
|
206
244
|
*/
|
|
207
245
|
where?: EntityFilter<entityType>;
|
|
208
|
-
/** Determines the order
|
|
209
|
-
|
|
210
|
-
|
|
246
|
+
/** Determines the order of items returned .
|
|
247
|
+
* @example
|
|
248
|
+
* await this.remult.repo(Products).find({ orderBy: { name: "asc" }})
|
|
249
|
+
* @example
|
|
250
|
+
* await this.remult.repo(Products).find({ orderBy: { price: "desc", name: "asc" }})
|
|
251
|
+
*/
|
|
211
252
|
orderBy?: EntityOrderBy<entityType>;
|
|
212
253
|
}
|
|
213
254
|
export interface FindFirstOptions<entityType> extends FindOptionsBase<entityType>, FindFirstOptionsBase<entityType> {
|
|
214
255
|
}
|
|
215
256
|
export interface FindFirstOptionsBase<entityType> extends LoadOptions<entityType> {
|
|
216
|
-
/**
|
|
257
|
+
/** determines if to cache the result, and return the results from cache.
|
|
217
258
|
*/
|
|
218
259
|
useCache?: boolean;
|
|
260
|
+
/** If set to true and an item is not found, it's created and returned*/
|
|
219
261
|
createIfNotFound?: boolean;
|
|
220
262
|
}
|
|
221
263
|
export interface QueryOptions<entityType> extends FindOptionsBase<entityType> {
|
|
264
|
+
/** The number of items to return in each step */
|
|
222
265
|
pageSize?: number;
|
|
266
|
+
/** A callback method to indicate the progress of the iteration */
|
|
223
267
|
progress?: {
|
|
224
268
|
progress: (progress: number) => void;
|
|
225
269
|
};
|
|
226
270
|
}
|
|
271
|
+
/** The result of a call to the `query` method in the `Repository` object.
|
|
272
|
+
*/
|
|
227
273
|
export interface QueryResult<entityType> {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
274
|
+
/** returns an iterator that iterates the rows in the result using a paging mechanism
|
|
275
|
+
* @example
|
|
276
|
+
* for await (const task of taskRepo.query()) {
|
|
277
|
+
* await taskRepo.save({ ...task, completed });
|
|
278
|
+
* }
|
|
279
|
+
*/
|
|
232
280
|
[Symbol.asyncIterator](): {
|
|
233
281
|
next: () => Promise<IteratorResult<entityType, entityType>>;
|
|
234
282
|
};
|
|
283
|
+
/** returns the number of rows that match the query critiria */
|
|
284
|
+
count(): Promise<number>;
|
|
285
|
+
/** Returns a `Paginator` object that is used for efficient paging */
|
|
286
|
+
paginator(): Promise<Paginator<entityType>>;
|
|
287
|
+
/** gets the items in a specific page */
|
|
288
|
+
getPage(pageNumber?: number): Promise<entityType[]>;
|
|
289
|
+
/** Performs an operation on all the items matching the query criteria */
|
|
290
|
+
forEach(what: (item: entityType) => Promise<any>): Promise<number>;
|
|
235
291
|
}
|
|
292
|
+
/** An interface used to paginating using the `query` method in the `Repository` object */
|
|
236
293
|
export interface Paginator<entityType> {
|
|
294
|
+
/** the items in the current page */
|
|
237
295
|
items: entityType[];
|
|
238
|
-
|
|
296
|
+
/** True if next page exists */
|
|
239
297
|
hasNextPage: boolean;
|
|
298
|
+
/** Get's the next page in the query's result set */
|
|
240
299
|
nextPage(): Promise<Paginator<entityType>>;
|
|
300
|
+
/** the count of the total items in the `query`'s result */
|
|
301
|
+
count(): Promise<number>;
|
|
241
302
|
}
|
package/src/server-action.d.ts
CHANGED
|
@@ -27,9 +27,12 @@ export declare class myServerAction extends Action<inArgs, result> {
|
|
|
27
27
|
protected execute(info: inArgs, remult: Remult, res: DataApiResponse): Promise<result>;
|
|
28
28
|
}
|
|
29
29
|
export interface BackendMethodOptions<type> {
|
|
30
|
+
/**Determines when this `BackendMethod` can execute, see: [Allowed](https://remult.dev/docs/allowed.html) */
|
|
30
31
|
allowed: AllowedForInstance<type>;
|
|
31
|
-
|
|
32
|
+
/** EXPERIMENTAL: Determines if this method should be queued for later execution */
|
|
32
33
|
queue?: boolean;
|
|
34
|
+
/** EXPERIMENTAL: Determines if the user should be blocked while this `BackendMethod` is running*/
|
|
35
|
+
blockUser?: boolean;
|
|
33
36
|
}
|
|
34
37
|
export declare const actionInfo: {
|
|
35
38
|
allActions: any[];
|
|
@@ -42,6 +45,7 @@ export declare const actionInfo: {
|
|
|
42
45
|
};
|
|
43
46
|
export declare const serverActionField: unique symbol;
|
|
44
47
|
export declare function Controller(key: string): (target: any) => any;
|
|
48
|
+
/** Indicates that the decorated methods runs on the backend. See: [Backend Methods](https://remult.dev/docs/backendMethods.html) */
|
|
45
49
|
export declare function BackendMethod<type = any>(options: BackendMethodOptions<type>): (target: any, key: string, descriptor: any) => any;
|
|
46
50
|
export interface registrableAction {
|
|
47
51
|
__register: (reg: (url: string, queue: boolean, allowed: AllowedForInstance<any>, what: ((data: any, req: DataApiRequest, res: DataApiResponse) => void)) => void) => void;
|
package/src/server-action.js
CHANGED
|
@@ -178,6 +178,7 @@ function Controller(key) {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
exports.Controller = Controller;
|
|
181
|
+
/** Indicates that the decorated methods runs on the backend. See: [Backend Methods](https://remult.dev/docs/backendMethods.html) */
|
|
181
182
|
function BackendMethod(options) {
|
|
182
183
|
return function (target, key, descriptor) {
|
|
183
184
|
if (target.prototype !== undefined) {
|
|
@@ -218,7 +218,58 @@ db_tests_setup_1.testAll("empty find works", function (_a) {
|
|
|
218
218
|
}
|
|
219
219
|
});
|
|
220
220
|
});
|
|
221
|
-
});
|
|
221
|
+
}, false);
|
|
222
|
+
db_tests_setup_1.testAll("test descending", function (_a) {
|
|
223
|
+
var createEntity = _a.createEntity;
|
|
224
|
+
return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
225
|
+
var repo, rows;
|
|
226
|
+
return tslib_1.__generator(this, function (_b) {
|
|
227
|
+
switch (_b.label) {
|
|
228
|
+
case 0: return [4 /*yield*/, createEntity(remult_3_entities_1.Categories)];
|
|
229
|
+
case 1:
|
|
230
|
+
repo = _b.sent();
|
|
231
|
+
return [4 /*yield*/, repo.create({ id: 1, categoryName: 'a' }).save()];
|
|
232
|
+
case 2:
|
|
233
|
+
_b.sent();
|
|
234
|
+
return [4 /*yield*/, repo.create({ id: 2, categoryName: 'b' }).save()];
|
|
235
|
+
case 3:
|
|
236
|
+
_b.sent();
|
|
237
|
+
return [4 /*yield*/, repo.find({
|
|
238
|
+
orderBy: { categoryName: 'desc' },
|
|
239
|
+
page: -1
|
|
240
|
+
})];
|
|
241
|
+
case 4:
|
|
242
|
+
rows = _b.sent();
|
|
243
|
+
expect(rows[0].id).toBe(2);
|
|
244
|
+
return [2 /*return*/];
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}, false);
|
|
249
|
+
db_tests_setup_1.testAll("test descending 2", function (_a) {
|
|
250
|
+
var createEntity = _a.createEntity;
|
|
251
|
+
return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
252
|
+
var repo, rows;
|
|
253
|
+
return tslib_1.__generator(this, function (_b) {
|
|
254
|
+
switch (_b.label) {
|
|
255
|
+
case 0: return [4 /*yield*/, createEntity(remult_3_entities_1.Categories)];
|
|
256
|
+
case 1:
|
|
257
|
+
repo = _b.sent();
|
|
258
|
+
return [4 /*yield*/, repo.insert([{ id: 1, categoryName: 'a' }, { id: 2, categoryName: 'b' }])];
|
|
259
|
+
case 2:
|
|
260
|
+
_b.sent();
|
|
261
|
+
return [4 /*yield*/, repo.find({
|
|
262
|
+
orderBy: { categoryName: 'desc' },
|
|
263
|
+
page: -1
|
|
264
|
+
})];
|
|
265
|
+
case 3:
|
|
266
|
+
rows = _b.sent();
|
|
267
|
+
expect(rows[0].id).toBe(2);
|
|
268
|
+
return [2 /*return*/];
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}, false);
|
|
222
273
|
db_tests_setup_1.testAll("partial updates", function (_a) {
|
|
223
274
|
var remult = _a.remult, createEntity = _a.createEntity;
|
|
224
275
|
return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
@@ -267,7 +267,7 @@ var MockRestDataProvider = /** @class */ (function () {
|
|
|
267
267
|
MockRestDataProvider.prototype.getEntityDataProvider = function (metadata) {
|
|
268
268
|
var _this = this;
|
|
269
269
|
var dataApi = new data_api_1.DataApi(this.remult.repo(metadata.entityType), this.remult);
|
|
270
|
-
return new rest_data_provider_1.RestEntityDataProvider("", {
|
|
270
|
+
return new rest_data_provider_1.RestEntityDataProvider("", new context_1.HttpProviderBridgeToRestDataProviderHttpProvider({
|
|
271
271
|
delete: function (url) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
272
272
|
var urlSplit, r, result;
|
|
273
273
|
return tslib_1.__generator(this, function (_a) {
|
|
@@ -359,7 +359,7 @@ var MockRestDataProvider = /** @class */ (function () {
|
|
|
359
359
|
}
|
|
360
360
|
});
|
|
361
361
|
}); }
|
|
362
|
-
}, metadata);
|
|
362
|
+
}), metadata);
|
|
363
363
|
};
|
|
364
364
|
MockRestDataProvider.prototype.transaction = function (action) {
|
|
365
365
|
throw new Error('Method not implemented.');
|