remult 0.27.5 → 0.27.7
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/server/get-remult-admin-html.js +1 -1
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +3 -2
- package/esm/src/live-query/SubscriptionServer.js +2 -2
- package/esm/src/remult3/RepositoryImplementation.js +4 -2
- package/esm/src/remult3/remult3.js +19 -40
- package/esm/src/server-action.js +28 -4
- package/package.json +1 -1
- package/server/get-remult-admin-html.js +1 -1
- package/src/filter/filter-consumer-bridge-to-sql-request.js +3 -2
- package/src/live-query/SubscriptionServer.js +2 -2
- package/src/remult3/Fields.d.ts +1 -1
- package/src/remult3/RepositoryImplementation.js +18 -18
- package/src/remult3/remult3.js +19 -40
- package/src/server-action.d.ts +25 -1
- package/src/server-action.js +39 -4
- package/src/validators.d.ts +1 -1
|
@@ -285,13 +285,14 @@ export async function fieldDbName(f, meta, wrapIdentifier = (x) => x, forceSqlEx
|
|
|
285
285
|
let result;
|
|
286
286
|
if (typeof f.options.sqlExpression === 'function') {
|
|
287
287
|
if (f[sqlExpressionInProgressKey] && !forceSqlExpression) {
|
|
288
|
-
return "recursive sqlExpression call for field '" + f.key + "'. ";
|
|
288
|
+
return "recursive sqlExpression call for field '" + f.key + "'. \0";
|
|
289
289
|
}
|
|
290
290
|
try {
|
|
291
291
|
;
|
|
292
292
|
f[sqlExpressionInProgressKey] = true;
|
|
293
293
|
result = await f.options.sqlExpression(meta);
|
|
294
|
-
|
|
294
|
+
if (!result.includes('\0'))
|
|
295
|
+
f.options.sqlExpression = () => result;
|
|
295
296
|
}
|
|
296
297
|
finally {
|
|
297
298
|
delete f[sqlExpressionInProgressKey];
|
|
@@ -12,7 +12,7 @@ export class LiveQueryPublisher {
|
|
|
12
12
|
runPromise(p) { }
|
|
13
13
|
debugFileSaver = (x) => { };
|
|
14
14
|
async itemChanged(entityKey, changes) {
|
|
15
|
-
await this.liveQueryStorage().forEach(entityKey, async ({ query: q, setData }) => {
|
|
15
|
+
await this.runPromise(this.liveQueryStorage().forEach(entityKey, async ({ query: q, setData }) => {
|
|
16
16
|
let query = { ...q.data };
|
|
17
17
|
await this.performWithContext(query.requestJson, entityKey, async (repo) => {
|
|
18
18
|
const messages = [];
|
|
@@ -61,7 +61,7 @@ export class LiveQueryPublisher {
|
|
|
61
61
|
if (messages.length > 0)
|
|
62
62
|
this.subscriptionServer().publishMessage(q.id, messages);
|
|
63
63
|
});
|
|
64
|
-
});
|
|
64
|
+
}));
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
export class InMemoryLiveQueryStorage {
|
|
@@ -1348,7 +1348,7 @@ export class rowHelperImplementation extends rowHelperBase {
|
|
|
1348
1348
|
await listener.saved?.(this.instance, isNew);
|
|
1349
1349
|
}
|
|
1350
1350
|
}
|
|
1351
|
-
|
|
1351
|
+
this.repo._remult.liveQueryPublisher.itemChanged(this.repo.metadata.key, [{ id: this.getId(), oldId: this.getOriginalId(), deleted: false }]);
|
|
1352
1352
|
this.saveOriginalData();
|
|
1353
1353
|
this._isNew = false;
|
|
1354
1354
|
return this.instance;
|
|
@@ -1420,7 +1420,9 @@ export class rowHelperImplementation extends rowHelperBase {
|
|
|
1420
1420
|
for (const listener of this.repo.listeners) {
|
|
1421
1421
|
await listener.deleted?.(this.instance);
|
|
1422
1422
|
}
|
|
1423
|
-
|
|
1423
|
+
this.repo._remult.liveQueryPublisher.itemChanged(this.repo.metadata.key, [
|
|
1424
|
+
{ id: this.getId(), oldId: this.getOriginalId(), deleted: true },
|
|
1425
|
+
]);
|
|
1424
1426
|
this._wasDeleted = true;
|
|
1425
1427
|
}
|
|
1426
1428
|
catch (err) {
|
|
@@ -1,51 +1,37 @@
|
|
|
1
1
|
export const flags = {
|
|
2
2
|
error500RetryCount: 4,
|
|
3
3
|
};
|
|
4
|
-
//
|
|
4
|
+
//p1 - add transactional option to backend method
|
|
5
|
+
//p1 - add parameter all to deleteMany, and updateMany
|
|
6
|
+
//p1 filter.apply ApiPreFilter
|
|
7
|
+
//p1 - min, max, avg, sum, countDistinct - noam come up with an api
|
|
8
|
+
/*p1 - add id and use uuid by default, but allow changes with Fields.id.defaultIdProvider NO but defaultProvider yes???
|
|
9
|
+
//p1 - replace uuid with crypto.randomUUID and allow custom fallback NO
|
|
10
|
+
//p1 - Add example for luid
|
|
11
|
+
//p1 - add example for nanoid
|
|
12
|
+
//p1 - explain the benefits of changing the default provider for testing in docs.
|
|
13
|
+
*/
|
|
14
|
+
//p1 - consider upsert (where,set)
|
|
15
|
+
//p1 TODO - consider id to also support keyof (id:['company','index']) - had problem with | (keyof Partial<entityType>)[] & `entity`
|
|
16
|
+
//p2 - add some kind of options handler that will help with translation etc... like in hagai - something that runs at the stage where options are being built
|
|
5
17
|
/*y1 - https://github.com/remult/remult/discussions/438
|
|
6
18
|
- https://github.com/remult/remult/blob/query-argumets/projects/tests/dbs/test-sql-database.spec.ts#L100-L128
|
|
7
|
-
//p2 - allow preprocess to replace filter values - for example replace $contains on a specific field, with specific other sql - useful for full text search and other scenarios
|
|
8
19
|
//y1 - consider sql expression gets a dbnames of it's own (that already has the "tableName" defined correctly) maybe also the filter translator
|
|
20
|
+
//p2 - allow preprocess to replace filter values - for example replace $contains on a specific field, with specific other sql - useful for full text search and other scenarios
|
|
9
21
|
//y2 - soft-delete-discussion https://discord.com/channels/975754286384418847/1230386433093533698/1230386433093533698
|
|
10
22
|
*/
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//p1 - when like doesn't have a string - don't send it to the db
|
|
14
|
-
//y1 - 'test expression columns without aliases'
|
|
15
|
-
//y1 - live query update waits for last
|
|
16
|
-
//p1 - add luid - it's cool for order by. - NO
|
|
17
|
-
//p1 - replace uuid with crypto.randomUUID and allow custom fallback NO
|
|
18
|
-
//p1 - add nanoid - NO
|
|
19
|
-
//p1 - add id and use luid by default, but allow changes with Fields.id.defaultIdProvider NO but defaultProvider yes
|
|
20
|
-
/*p1
|
|
21
|
-
* field, fieldType ,ValueListFieldType, - return optional parameter for decorators
|
|
22
|
-
* options to remultExpress tc... should be mandatory
|
|
23
|
-
* return value converter to previous typing
|
|
24
|
-
* add breaking change notification about findOne and findFirst and findId
|
|
25
|
-
*/
|
|
26
|
-
//p1 - fix query docs to also explain how it can be used for infinite scroll and pagination.
|
|
27
|
-
//y1 - 'test expression columns without aliases'
|
|
28
|
-
//y1 - ts issue with fields - when a field is optional, it's $ is also optional and thats a problem
|
|
23
|
+
//p2 - fix query docs to also explain how it can be used for infinite scroll and pagination.
|
|
24
|
+
//p2 - when like doesn't have a string - don't send it to the db
|
|
29
25
|
//p1 - vite 5.3 supports ts5 decorators - check and adapt.
|
|
30
|
-
//p1 -
|
|
31
|
-
//p1 -
|
|
32
|
-
//p1 -
|
|
33
|
-
//p1 - add nanoid
|
|
34
|
-
//p1 - add id and use luid by default, but allow changes with Fields.id.defaultIdProvider
|
|
35
|
-
//p1 - explain the benefits of changing the default provider for testing in docs.
|
|
26
|
+
//p1 - tutorial about controller - and mutable controller
|
|
27
|
+
//p1 - docs abount subscription channel
|
|
28
|
+
//p1 - Consider enforcing serial operations on JSON database to prevent data loss
|
|
36
29
|
//p1 - fix sqlite to support alter table when adding a column with ensure schema = on
|
|
37
|
-
//p1 - fix app custom filters example for multiple filters.
|
|
38
|
-
//p1 - add not!!!!
|
|
39
30
|
//p1 - add LifecycleEvent to documentation
|
|
40
|
-
//p1 - Fix hagai and starter project to latest ts
|
|
41
31
|
//p1 - fix chaining of saving and saved in multiple entity options args
|
|
42
32
|
//p1 - review starter and examples and separate remult * auth from the routes
|
|
43
|
-
//p1 - min, max, avg, sum
|
|
44
|
-
//p1 - consider upsert (where,set)
|
|
45
33
|
//y1 - live query with count #436
|
|
46
34
|
//y1 TODO - In the esm version of our tutorial - the imports are automatically .ts and not .js in react and not in vue
|
|
47
|
-
//y1 TODO - consider id to also support keyof (id:['company','index']) - had problem with | (keyof Partial<entityType>)[] & `entity`
|
|
48
|
-
//y1 TODO - readonly key: keyof MembersOnly<entityType> & string
|
|
49
35
|
//y1 TODO - fix remult admin not to load the html into memory until used
|
|
50
36
|
//y2 - talk about insert / update / delete with relations
|
|
51
37
|
/*
|
|
@@ -63,15 +49,10 @@ const result = await repo.batch(x=>({
|
|
|
63
49
|
}))
|
|
64
50
|
*/
|
|
65
51
|
//y1 - wait a second to close stream -see pr
|
|
66
|
-
//p1 - Consider enforcing serial operations on JSON database to prevent data loss
|
|
67
52
|
//p1 - prepare the createEntity discussion
|
|
68
|
-
//p1 - return error on connection error
|
|
69
53
|
//p1 - article on displayValue including it's definition for entities that is used in relations
|
|
70
54
|
//p1 - article auth.js with express - played with it, requires type="module" and a few more configurations - https://github.com/noam-honig/express-auth
|
|
71
|
-
//y2 - currently for string fields we default for 255 in knex (which is their default) why not just use text (varchar max) - and only use exact length when one is provided?
|
|
72
55
|
//p2 - create foreign key constraints in user code - https://codesandbox.io/p/devbox/fk-validator-tdshcs
|
|
73
|
-
//p2 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string} also checkout the admin* as it should probably be something else and didn't work in hono
|
|
74
|
-
//y2 - fix validators cache
|
|
75
56
|
//y2 - should we validate relations
|
|
76
57
|
//y1 - dependency of live query tables live query refresh of view on table update
|
|
77
58
|
//p1 - see why mongo tests do not run anymore
|
|
@@ -91,7 +72,6 @@ const result = await repo.batch(x=>({
|
|
|
91
72
|
- delete restrict (implicit, or user selected - and if so, how) (delete & update of id)
|
|
92
73
|
|
|
93
74
|
*/
|
|
94
|
-
//y1 - tried to upgrade vitest, nuxt tests are failing with loading uuid - sounds familiar?
|
|
95
75
|
//y1 - talk about the parameter issue with backend methods
|
|
96
76
|
//y2 - livequery for findfirst (@JY)
|
|
97
77
|
/*y2 -
|
|
@@ -108,7 +88,6 @@ const result = await repo.batch(x=>({
|
|
|
108
88
|
//y2 - Fix problem with promise all in sql expression recurssion - when using PromiseAll in row relation loading, some sql expressions appear is recursion call even if they are not
|
|
109
89
|
//p2 - when subscribe is forbidden - the query still runs after the renew process
|
|
110
90
|
//p2 - 'update tasks set where id = $1
|
|
111
|
-
//p2 - type metadata.key - to keyof entity - based on cwis input
|
|
112
91
|
//y2 - remove __dirname from tutorials
|
|
113
92
|
//p2 - when value changes for field with error, clear error - so the user will feel comfortable
|
|
114
93
|
//p2 - allowApiUpdate should be false for include in api false
|
package/esm/src/server-action.js
CHANGED
|
@@ -89,7 +89,7 @@ export class myServerAction extends Action {
|
|
|
89
89
|
async execute(info, remult, res) {
|
|
90
90
|
let result = { data: {} };
|
|
91
91
|
let ds = remult.dataProvider;
|
|
92
|
-
await
|
|
92
|
+
await decideTransaction(remult, this.options, async () => {
|
|
93
93
|
if (!remult.isAllowedForInstance(undefined, this.options.allowed))
|
|
94
94
|
throw new ForbiddenError();
|
|
95
95
|
info.args = await prepareReceivedArgs(this.types(), info.args, remult, ds, res);
|
|
@@ -112,7 +112,24 @@ export function Controller(key) {
|
|
|
112
112
|
return target;
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Decorator indicating that the decorated method runs on the backend.
|
|
117
|
+
* It allows the method to be invoked from the frontend while ensuring that the execution happens on the server side.
|
|
118
|
+
* By default, the method runs within a database transaction, meaning it will either complete entirely or fail without making any partial changes.
|
|
119
|
+
* This behavior can be controlled using the `transactional` option in the `BackendMethodOptions`.
|
|
120
|
+
*
|
|
121
|
+
* For more details, see: [Backend Methods](https://remult.dev/docs/backendMethods.html).
|
|
122
|
+
*
|
|
123
|
+
* @param options - Configuration options for the backend method, including permissions, routing, and transactional behavior.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* @BackendMethod({ allowed: true })
|
|
128
|
+
* async someBackendMethod() {
|
|
129
|
+
* // method logic here
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
116
133
|
export function BackendMethod(options) {
|
|
117
134
|
return (target, context, descriptor) => {
|
|
118
135
|
const key = typeof context === 'string' ? context : context.name.toString();
|
|
@@ -147,7 +164,7 @@ export function BackendMethod(options) {
|
|
|
147
164
|
}
|
|
148
165
|
else
|
|
149
166
|
return await originalMethod.apply(
|
|
150
|
-
//@ts-
|
|
167
|
+
//@ts-ignore
|
|
151
168
|
this, args);
|
|
152
169
|
};
|
|
153
170
|
registerAction(target, result);
|
|
@@ -181,7 +198,7 @@ export function BackendMethod(options) {
|
|
|
181
198
|
try {
|
|
182
199
|
let remult = req;
|
|
183
200
|
let r;
|
|
184
|
-
await
|
|
201
|
+
await decideTransaction(remult, options, async () => {
|
|
185
202
|
d.args = await prepareReceivedArgs(getTypes(), d.args, remult, remult.dataProvider, res);
|
|
186
203
|
if (remultStatic.allEntities.includes(constructor)) {
|
|
187
204
|
let repo = remult.repo(constructor);
|
|
@@ -406,3 +423,10 @@ export async function prepareReceivedArgs(types, args, remult, ds, res) {
|
|
|
406
423
|
return args;
|
|
407
424
|
}
|
|
408
425
|
export const classBackendMethodsArray = Symbol.for('classBackendMethodsArray');
|
|
426
|
+
//
|
|
427
|
+
async function decideTransaction(remult, options, what) {
|
|
428
|
+
if (options.transactional === undefined || options.transactional === true)
|
|
429
|
+
return await doTransaction(remult, what);
|
|
430
|
+
else
|
|
431
|
+
await what(remult.dataProvider);
|
|
432
|
+
}
|