proto.io 0.0.171 → 0.0.173
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/dist/adapters/file/database.d.ts +2 -2
- package/dist/adapters/file/filesystem.d.ts +2 -2
- package/dist/adapters/file/google-cloud-storage.d.ts +2 -2
- package/dist/adapters/storage/progres.d.ts +8 -1
- package/dist/adapters/storage/progres.js +66 -9
- package/dist/adapters/storage/progres.js.map +1 -1
- package/dist/adapters/storage/progres.mjs +66 -9
- package/dist/adapters/storage/progres.mjs.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +1 -1
- package/dist/client.mjs +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +137 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -26
- package/dist/index.mjs.map +1 -1
- package/dist/internals/{index-B5u7VXjz.d.ts → index-BJnQhKf3.d.ts} +2 -2
- package/dist/internals/index-BJnQhKf3.d.ts.map +1 -0
- package/dist/internals/{index-D0hHgn2P.mjs → index-BZNPlw1L.mjs} +20 -1
- package/dist/internals/index-BZNPlw1L.mjs.map +1 -0
- package/dist/internals/{index-BJP46VGq.js → index-CIecB6mS.js} +20 -1
- package/dist/internals/index-CIecB6mS.js.map +1 -0
- package/dist/internals/{index-D_GYwO8X.d.ts → index-Cpv1DoEI.d.ts} +2 -2
- package/dist/internals/index-Cpv1DoEI.d.ts.map +1 -0
- package/dist/internals/{index-BB2vDnq0.d.ts → index-lX-M76Tn.d.ts} +16 -3
- package/dist/internals/index-lX-M76Tn.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/internals/index-B5u7VXjz.d.ts.map +0 -1
- package/dist/internals/index-BB2vDnq0.d.ts.map +0 -1
- package/dist/internals/index-BJP46VGq.js.map +0 -1
- package/dist/internals/index-D0hHgn2P.mjs.map +0 -1
- package/dist/internals/index-D_GYwO8X.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import { Server } from '@o2ter/server-js';
|
|
|
3
3
|
import { Q as QueryValidator, r as resolveColumn, a as resolveDataType, g as generateId } from './internals/random-BCpwYpyw.mjs';
|
|
4
4
|
import { P as PVK } from './internals/private-BUpLAMZi.mjs';
|
|
5
5
|
import { prototypes, asyncStream, asyncIterableToArray, isBinaryData, base64ToBuffer } from '@o2ter/utils-js';
|
|
6
|
-
import { T as TQuery, M as MASTER_USER_HEADER_NAME, a as MASTER_PASS_HEADER_NAME, A as AUTH_COOKIE_KEY, b as TUser, P as ProtoType, s as serialize, d as deserialize, U as UPLOAD_TOKEN_HEADER_NAME } from './internals/index-
|
|
7
|
-
export { c as ProtoClient, e as classExtends, j as isFile, f as isObject, i as isQuery, h as isRole, g as isUser } from './internals/index-
|
|
6
|
+
import { T as TQuery, M as MASTER_USER_HEADER_NAME, a as MASTER_PASS_HEADER_NAME, A as AUTH_COOKIE_KEY, b as TUser, P as ProtoType, s as serialize, d as deserialize, U as UPLOAD_TOKEN_HEADER_NAME } from './internals/index-BZNPlw1L.mjs';
|
|
7
|
+
export { c as ProtoClient, e as classExtends, j as isFile, f as isObject, i as isQuery, h as isRole, g as isUser } from './internals/index-BZNPlw1L.mjs';
|
|
8
8
|
import { i as isPointer, a as isRelation, d as decodeUpdateOp, T as TObject, b as isShape, c as defaultObjectKeyTypes, e as isPrimitive } from './internals/index-BYbMU-Ao.mjs';
|
|
9
9
|
import jwt from 'jsonwebtoken';
|
|
10
10
|
import { Blob } from 'node:buffer';
|
|
@@ -183,6 +183,13 @@ const dispatcher = (proto, options, disableSecurity) => {
|
|
|
183
183
|
throw Error('No permission');
|
|
184
184
|
return proto.storage.atomic((storage) => storage.updateOne(_validator.decodeQuery(normalize(query), 'update'), normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path))));
|
|
185
185
|
},
|
|
186
|
+
async updateMany(query, update) {
|
|
187
|
+
QueryValidator.recursiveCheck(query, update);
|
|
188
|
+
const _validator = await validator();
|
|
189
|
+
if (!_validator.validateCLPs(query.className, 'update'))
|
|
190
|
+
throw Error('No permission');
|
|
191
|
+
return proto.storage.atomic((storage) => storage.updateMany(_validator.decodeQuery(normalize(query), 'update'), normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path))));
|
|
192
|
+
},
|
|
186
193
|
async upsertOne(query, update, setOnInsert) {
|
|
187
194
|
QueryValidator.recursiveCheck(query, update, setOnInsert);
|
|
188
195
|
const _validator = await validator();
|
|
@@ -202,6 +209,25 @@ const dispatcher = (proto, options, disableSecurity) => {
|
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
},
|
|
212
|
+
async upsertMany(query, update, setOnInsert) {
|
|
213
|
+
QueryValidator.recursiveCheck(query, update, setOnInsert);
|
|
214
|
+
const _validator = await validator();
|
|
215
|
+
if (!_validator.validateCLPs(query.className, 'create', 'update'))
|
|
216
|
+
throw Error('No permission');
|
|
217
|
+
const _query = _validator.decodeQuery(normalize(query), 'update');
|
|
218
|
+
const _update = normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path));
|
|
219
|
+
const _setOnInsert = normalize(_validator.validateFields(query.className, setOnInsert, 'create', QueryValidator.patterns.name));
|
|
220
|
+
while (true) {
|
|
221
|
+
try {
|
|
222
|
+
return await proto.storage.atomic((storage) => storage.upsertMany(_query, _update, _setOnInsert), { lockTable: query.className, retry: true });
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
if (proto.storage.isDuplicateIdError(e))
|
|
226
|
+
continue;
|
|
227
|
+
throw e;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
205
231
|
async deleteOne(query) {
|
|
206
232
|
QueryValidator.recursiveCheck(query);
|
|
207
233
|
const _validator = await validator();
|
|
@@ -440,6 +466,33 @@ class _ProtoQuery extends TQuery {
|
|
|
440
466
|
}
|
|
441
467
|
return result;
|
|
442
468
|
}
|
|
469
|
+
async updateMany(update, options) {
|
|
470
|
+
const context = options?.context ?? {};
|
|
471
|
+
const silent = _.castArray(options?.silent ?? []);
|
|
472
|
+
const beforeSave = _.includes(silent, 'beforeSave') ? null : this._proto[PVK].triggers?.beforeSave?.[this.className];
|
|
473
|
+
const afterSave = _.includes(silent, 'afterSave') ? null : this._proto[PVK].triggers?.afterSave?.[this.className];
|
|
474
|
+
if (_.isFunction(beforeSave) || _.isFunction(afterSave)) {
|
|
475
|
+
const objects = this._objectMethods(await asyncIterableToArray(this._dispatcher(options).find(this._queryOptions)));
|
|
476
|
+
if (_.isEmpty(objects))
|
|
477
|
+
return 0;
|
|
478
|
+
if (_.isFunction(beforeSave)) {
|
|
479
|
+
await Promise.all(_.map(objects, object => beforeSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
|
|
480
|
+
}
|
|
481
|
+
if (!_.isFunction(afterSave)) {
|
|
482
|
+
return this._dispatcher(options).updateMany({
|
|
483
|
+
...this._queryOptions,
|
|
484
|
+
filter: { _id: { $in: _.map(objects, x => x.objectId) } },
|
|
485
|
+
}, update);
|
|
486
|
+
}
|
|
487
|
+
const updated = await Promise.all(_.map(objects, x => this._dispatcher(options).updateOne({
|
|
488
|
+
...this._queryOptions,
|
|
489
|
+
filter: { _id: { $eq: x.objectId } },
|
|
490
|
+
}, update)));
|
|
491
|
+
await Promise.all(_.map(updated, object => afterSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
|
|
492
|
+
return updated.length;
|
|
493
|
+
}
|
|
494
|
+
return this._dispatcher(options).updateMany(this._queryOptions, update);
|
|
495
|
+
}
|
|
443
496
|
async upsertOne(update, setOnInsert, options) {
|
|
444
497
|
const context = options?.context ?? {};
|
|
445
498
|
const silent = _.castArray(options?.silent ?? []);
|
|
@@ -478,6 +531,47 @@ class _ProtoQuery extends TQuery {
|
|
|
478
531
|
}
|
|
479
532
|
return result;
|
|
480
533
|
}
|
|
534
|
+
async upsertMany(update, setOnInsert, options) {
|
|
535
|
+
const context = options?.context ?? {};
|
|
536
|
+
const silent = _.castArray(options?.silent ?? []);
|
|
537
|
+
const beforeSave = _.includes(silent, 'beforeSave') ? null : this._proto[PVK].triggers?.beforeSave?.[this.className];
|
|
538
|
+
const afterSave = _.includes(silent, 'afterSave') ? null : this._proto[PVK].triggers?.afterSave?.[this.className];
|
|
539
|
+
if (_.isFunction(beforeSave) || _.isFunction(afterSave)) {
|
|
540
|
+
const objects = this._objectMethods(await asyncIterableToArray(this._dispatcher(options).find(this._queryOptions)));
|
|
541
|
+
if (!_.isEmpty(objects) && _.isFunction(beforeSave)) {
|
|
542
|
+
await Promise.all(_.map(objects, object => beforeSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
|
|
543
|
+
}
|
|
544
|
+
if (_.isEmpty(objects)) {
|
|
545
|
+
const result = await this._dispatcher(options).insert({
|
|
546
|
+
className: this.className,
|
|
547
|
+
includes: this[PVK].options.includes,
|
|
548
|
+
matches: this[PVK].options.matches,
|
|
549
|
+
}, setOnInsert);
|
|
550
|
+
if (!result)
|
|
551
|
+
throw Error('Unable to insert document');
|
|
552
|
+
if (_.isFunction(afterSave)) {
|
|
553
|
+
await afterSave(proxy(Object.setPrototypeOf({ object: result, context }, options?.session ?? this._proto)));
|
|
554
|
+
}
|
|
555
|
+
return { updated: 0, inserted: 1 };
|
|
556
|
+
}
|
|
557
|
+
if (!_.isFunction(afterSave)) {
|
|
558
|
+
return {
|
|
559
|
+
inserted: 0,
|
|
560
|
+
updated: await this._dispatcher(options).updateMany({
|
|
561
|
+
...this._queryOptions,
|
|
562
|
+
filter: { _id: { $in: _.map(objects, x => x.objectId) } },
|
|
563
|
+
}, update),
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const updated = await Promise.all(_.map(objects, x => this._dispatcher(options).updateOne({
|
|
567
|
+
...this._queryOptions,
|
|
568
|
+
filter: { _id: { $eq: x.objectId } },
|
|
569
|
+
}, update)));
|
|
570
|
+
await Promise.all(_.map(updated, object => afterSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
|
|
571
|
+
return { updated: updated.length, inserted: 0 };
|
|
572
|
+
}
|
|
573
|
+
return this._dispatcher(options).upsertMany(this._queryOptions, update, setOnInsert);
|
|
574
|
+
}
|
|
481
575
|
async deleteOne(options) {
|
|
482
576
|
const context = options?.context ?? {};
|
|
483
577
|
const silent = _.castArray(options?.silent ?? []);
|
|
@@ -848,7 +942,7 @@ class ProtoInternal {
|
|
|
848
942
|
validateSchemaName(options.schema);
|
|
849
943
|
const schema = mergeSchema(defaultSchema, options.fileStorage.schema, options.schema);
|
|
850
944
|
validateSchema(schema);
|
|
851
|
-
if (!_.every(options.
|
|
945
|
+
if (!_.every(options.roleResolver?.inheritKeys, k => {
|
|
852
946
|
const type = resolveDataType(schema, 'Role', k);
|
|
853
947
|
return type && isRelation(type) && _.includes(['User', 'Role'], type.target);
|
|
854
948
|
})) {
|
|
@@ -1354,7 +1448,7 @@ class ProtoService extends ProtoType {
|
|
|
1354
1448
|
constructor(options) {
|
|
1355
1449
|
super();
|
|
1356
1450
|
this[PVK] = new ProtoInternal({
|
|
1357
|
-
|
|
1451
|
+
roleResolver: {},
|
|
1358
1452
|
objectIdSize: 10,
|
|
1359
1453
|
maxFetchLimit: 1000,
|
|
1360
1454
|
maxUploadSize: 20 * 1024 * 1024,
|
|
@@ -1441,30 +1535,36 @@ class ProtoService extends ProtoType {
|
|
|
1441
1535
|
return _.assign(payload, _.isFunction(attrs) ? attrs(payload) : attrs);
|
|
1442
1536
|
}
|
|
1443
1537
|
async userRoles(user) {
|
|
1444
|
-
const
|
|
1445
|
-
const
|
|
1446
|
-
const
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
.
|
|
1457
|
-
|
|
1458
|
-
let roles = queue;
|
|
1459
|
-
while (!_.isEmpty(queue)) {
|
|
1460
|
-
queue = await this.Query('Role')
|
|
1461
|
-
.or(_.map(_.uniq(['roles', ...roleKeys]), k => q => q.isIntersect(k, queue)))
|
|
1462
|
-
.notContainsIn('_id', _.compact(_.map(roles, x => x.objectId)))
|
|
1538
|
+
const self = this;
|
|
1539
|
+
const { inheritKeys, resolver } = self[PVK].options.roleResolver;
|
|
1540
|
+
const defaultResolver = async () => {
|
|
1541
|
+
const schema = self.schema;
|
|
1542
|
+
const userKeys = _.filter(inheritKeys, k => {
|
|
1543
|
+
const type = resolveDataType(schema, 'Role', k);
|
|
1544
|
+
return !!type && isRelation(type) && type.target === 'User';
|
|
1545
|
+
});
|
|
1546
|
+
const roleKeys = _.filter(inheritKeys, k => {
|
|
1547
|
+
const type = resolveDataType(schema, 'Role', k);
|
|
1548
|
+
return !!type && isRelation(type) && type.target === 'Role';
|
|
1549
|
+
});
|
|
1550
|
+
let queue = await self.Query('Role')
|
|
1551
|
+
.or(_.map(_.uniq(['users', ...userKeys]), k => q => q.isIntersect(k, [user])))
|
|
1463
1552
|
.includes('name')
|
|
1464
1553
|
.find({ master: true });
|
|
1465
|
-
roles =
|
|
1466
|
-
|
|
1467
|
-
|
|
1554
|
+
let roles = queue;
|
|
1555
|
+
while (!_.isEmpty(queue)) {
|
|
1556
|
+
queue = await self.Query('Role')
|
|
1557
|
+
.or(_.map(_.uniq(['roles', ...roleKeys]), k => q => q.isIntersect(k, queue)))
|
|
1558
|
+
.notContainsIn('_id', _.compact(_.map(roles, x => x.objectId)))
|
|
1559
|
+
.includes('name')
|
|
1560
|
+
.find({ master: true });
|
|
1561
|
+
roles = _.uniqBy([...roles, ...queue], x => x.objectId);
|
|
1562
|
+
}
|
|
1563
|
+
return roles;
|
|
1564
|
+
};
|
|
1565
|
+
if (resolver)
|
|
1566
|
+
return resolver(user, defaultResolver);
|
|
1567
|
+
return defaultResolver();
|
|
1468
1568
|
}
|
|
1469
1569
|
async becomeUser(req, user, options) {
|
|
1470
1570
|
if (!user.objectId)
|
|
@@ -1769,7 +1869,9 @@ var classesRoute = (router, proto) => {
|
|
|
1769
1869
|
case 'insert': return query.insert(attributes, opts);
|
|
1770
1870
|
case 'insertMany': return query.insertMany(attributes, opts);
|
|
1771
1871
|
case 'updateOne': return query.updateOne(update, opts);
|
|
1872
|
+
case 'updateMany': return query.updateMany(update, opts);
|
|
1772
1873
|
case 'upsertOne': return query.upsertOne(update, setOnInsert, opts);
|
|
1874
|
+
case 'upsertMany': return query.upsertMany(update, setOnInsert, opts);
|
|
1773
1875
|
case 'deleteOne': return query.deleteOne(opts);
|
|
1774
1876
|
case 'deleteMany': return query.deleteMany(opts);
|
|
1775
1877
|
default: throw Error('Invalid operation');
|
|
@@ -1873,6 +1975,16 @@ var classesRoute = (router, proto) => {
|
|
|
1873
1975
|
const payload = proto.connect(req);
|
|
1874
1976
|
await response(res, async () => payload.refs(payload.Object(name, id), { master: payload.isMaster }));
|
|
1875
1977
|
});
|
|
1978
|
+
router.patch('/classes/:name', Server.text({ type: '*/*' }), async (req, res) => {
|
|
1979
|
+
res.setHeader('Cache-Control', ['no-cache', 'no-store']);
|
|
1980
|
+
const { name } = req.params;
|
|
1981
|
+
const classes = proto.classes();
|
|
1982
|
+
if (!_.includes(classes, name))
|
|
1983
|
+
return void res.sendStatus(404);
|
|
1984
|
+
const payload = proto.connect(req);
|
|
1985
|
+
const update = _.mapValues(deserialize(req.body), v => ({ $set: v }));
|
|
1986
|
+
await response(res, () => createQuery(payload, req, false).updateMany(update, { master: payload.isMaster }));
|
|
1987
|
+
});
|
|
1876
1988
|
router.patch('/classes/:name/:id', Server.text({ type: '*/*' }), async (req, res) => {
|
|
1877
1989
|
res.setHeader('Cache-Control', ['no-cache', 'no-store']);
|
|
1878
1990
|
const { name, id } = req.params;
|