@opra/core 0.0.12 → 0.1.0
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/cjs/enums/http-headers.enum.js +2 -1
- package/cjs/exception/http-errors/not-acceptable.error.js +26 -0
- package/cjs/exception/index.js +2 -0
- package/cjs/exception/resource-errors/resource-not-found.error.js +19 -0
- package/cjs/implementation/adapter-utils/entity-resource-execute.util.js +84 -0
- package/cjs/implementation/adapter-utils/resource-execute.util.js +11 -0
- package/cjs/implementation/adapter-utils/resource-prepare.util.js +11 -0
- package/cjs/implementation/{adapter/adapter.js → adapter.js} +40 -7
- package/cjs/implementation/{adapter/express-adapter.js → express-adapter.js} +0 -0
- package/cjs/implementation/http-adapter.js +267 -0
- package/cjs/implementation/query-context.js +5 -3
- package/cjs/index.js +5 -15
- package/cjs/{services/entity-resource-controller.js → interfaces/entity-service.interface.js} +0 -0
- package/cjs/interfaces/query.interface.js +26 -9
- package/cjs/services/json-data-service.js +241 -4
- package/cjs/utils/create-i18n.js +1 -1
- package/cjs/utils/get-caller-file.util.js +6 -1
- package/cjs/utils/{string-path-to-object-tree.js → path-to-tree.js} +3 -3
- package/esm/enums/http-headers.enum.d.ts +2 -1
- package/esm/enums/http-headers.enum.js +2 -1
- package/esm/exception/http-errors/not-acceptable.error.d.ts +10 -0
- package/esm/exception/http-errors/not-acceptable.error.js +22 -0
- package/esm/exception/index.d.ts +2 -0
- package/esm/exception/index.js +2 -0
- package/esm/exception/resource-errors/resource-not-found.error.d.ts +4 -0
- package/esm/exception/resource-errors/resource-not-found.error.js +15 -0
- package/esm/implementation/adapter-utils/entity-resource-execute.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/entity-resource-execute.util.js +80 -0
- package/esm/implementation/adapter-utils/resource-execute.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/resource-execute.util.js +7 -0
- package/esm/implementation/adapter-utils/resource-prepare.util.d.ts +3 -0
- package/esm/implementation/adapter-utils/resource-prepare.util.js +7 -0
- package/esm/implementation/{adapter/adapter.d.ts → adapter.d.ts} +5 -9
- package/esm/implementation/{adapter/adapter.js → adapter.js} +39 -6
- package/esm/implementation/{adapter/express-adapter.d.ts → express-adapter.d.ts} +2 -2
- package/esm/implementation/{adapter/express-adapter.js → express-adapter.js} +0 -0
- package/esm/implementation/{adapter/http-adapter.d.ts → http-adapter.d.ts} +6 -6
- package/esm/implementation/http-adapter.js +263 -0
- package/esm/implementation/query-context.d.ts +3 -4
- package/esm/implementation/query-context.js +5 -3
- package/esm/index.d.ts +5 -15
- package/esm/index.js +5 -15
- package/esm/{services/entity-resource-controller.d.ts → interfaces/entity-service.interface.d.ts} +0 -0
- package/esm/{services/entity-resource-controller.js → interfaces/entity-service.interface.js} +0 -0
- package/esm/interfaces/query.interface.d.ts +31 -25
- package/esm/interfaces/query.interface.js +26 -9
- package/esm/services/json-data-service.d.ts +66 -7
- package/esm/services/json-data-service.js +241 -4
- package/esm/types.d.ts +10 -8
- package/esm/utils/create-i18n.d.ts +1 -1
- package/esm/utils/create-i18n.js +1 -1
- package/esm/utils/get-caller-file.util.d.ts +1 -1
- package/esm/utils/get-caller-file.util.js +6 -1
- package/esm/utils/path-to-tree.d.ts +4 -0
- package/esm/utils/{string-path-to-object-tree.js → path-to-tree.js} +1 -1
- package/i18n/en/error.json +3 -0
- package/package.json +6 -7
- package/cjs/constants.js +0 -5
- package/cjs/decorators/entity-resource.decorator.js +0 -24
- package/cjs/implementation/adapter/http-adapter.js +0 -238
- package/cjs/implementation/data-type/complex-type.js +0 -39
- package/cjs/implementation/data-type/data-type.js +0 -35
- package/cjs/implementation/data-type/entity-type.js +0 -33
- package/cjs/implementation/data-type/simple-type.js +0 -30
- package/cjs/implementation/opra-document.js +0 -116
- package/cjs/implementation/opra-service.js +0 -59
- package/cjs/implementation/resource/container-resource-handler.js +0 -30
- package/cjs/implementation/resource/entity-resource-handler.js +0 -80
- package/cjs/implementation/resource/resource-handler.js +0 -31
- package/cjs/implementation/schema-generator.js +0 -163
- package/cjs/interfaces/opra-schema.metadata.js +0 -2
- package/cjs/interfaces/resource-container.interface.js +0 -2
- package/cjs/utils/class-utils.js +0 -37
- package/cjs/utils/headers.js +0 -58
- package/cjs/utils/internal-data-types.js +0 -81
- package/cjs/utils/responsive-object.js +0 -49
- package/cjs/utils/terminal-utils.js +0 -7
- package/esm/constants.d.ts +0 -2
- package/esm/constants.js +0 -2
- package/esm/decorators/entity-resource.decorator.d.ts +0 -5
- package/esm/decorators/entity-resource.decorator.js +0 -19
- package/esm/implementation/adapter/http-adapter.js +0 -234
- package/esm/implementation/data-type/complex-type.d.ts +0 -18
- package/esm/implementation/data-type/complex-type.js +0 -35
- package/esm/implementation/data-type/data-type.d.ts +0 -15
- package/esm/implementation/data-type/data-type.js +0 -31
- package/esm/implementation/data-type/entity-type.d.ts +0 -10
- package/esm/implementation/data-type/entity-type.js +0 -29
- package/esm/implementation/data-type/simple-type.d.ts +0 -15
- package/esm/implementation/data-type/simple-type.js +0 -26
- package/esm/implementation/opra-document.d.ts +0 -26
- package/esm/implementation/opra-document.js +0 -111
- package/esm/implementation/opra-service.d.ts +0 -19
- package/esm/implementation/opra-service.js +0 -55
- package/esm/implementation/resource/container-resource-handler.d.ts +0 -14
- package/esm/implementation/resource/container-resource-handler.js +0 -26
- package/esm/implementation/resource/entity-resource-handler.d.ts +0 -18
- package/esm/implementation/resource/entity-resource-handler.js +0 -75
- package/esm/implementation/resource/resource-handler.d.ts +0 -15
- package/esm/implementation/resource/resource-handler.js +0 -27
- package/esm/implementation/schema-generator.d.ts +0 -21
- package/esm/implementation/schema-generator.js +0 -159
- package/esm/interfaces/opra-schema.metadata.d.ts +0 -14
- package/esm/interfaces/opra-schema.metadata.js +0 -1
- package/esm/interfaces/resource-container.interface.d.ts +0 -6
- package/esm/interfaces/resource-container.interface.js +0 -1
- package/esm/utils/class-utils.d.ts +0 -6
- package/esm/utils/class-utils.js +0 -30
- package/esm/utils/headers.d.ts +0 -9
- package/esm/utils/headers.js +0 -55
- package/esm/utils/internal-data-types.d.ts +0 -5
- package/esm/utils/internal-data-types.js +0 -78
- package/esm/utils/responsive-object.d.ts +0 -3
- package/esm/utils/responsive-object.js +0 -45
- package/esm/utils/string-path-to-object-tree.d.ts +0 -4
- package/esm/utils/terminal-utils.d.ts +0 -4
- package/esm/utils/terminal-utils.js +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import { ComplexType } from '
|
|
3
|
-
import {
|
|
2
|
+
import { ComplexType } from '@opra/schema';
|
|
3
|
+
import { pathToTree } from '../utils/path-to-tree.js';
|
|
4
4
|
export var OpraQuery;
|
|
5
5
|
(function (OpraQuery) {
|
|
6
6
|
function forCreate(resource, values, options) {
|
|
@@ -21,7 +21,24 @@ export var OpraQuery;
|
|
|
21
21
|
return out;
|
|
22
22
|
}
|
|
23
23
|
OpraQuery.forCreate = forCreate;
|
|
24
|
-
function
|
|
24
|
+
function forGetSchema(resourcePath, options) {
|
|
25
|
+
// if (options?.pick)
|
|
26
|
+
// options.pick = normalizePick(resource, options.pick);
|
|
27
|
+
// if (options?.omit)
|
|
28
|
+
// options.omit = normalizePick(resource, options.omit);
|
|
29
|
+
// if (options?.include)
|
|
30
|
+
// options.include = normalizePick(resource, options.include);
|
|
31
|
+
const out = {
|
|
32
|
+
queryType: 'schema',
|
|
33
|
+
scope: 'instance',
|
|
34
|
+
resourcePath,
|
|
35
|
+
operation: 'read',
|
|
36
|
+
};
|
|
37
|
+
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
OpraQuery.forGetSchema = forGetSchema;
|
|
41
|
+
function forGetEntity(resource, key, options) {
|
|
25
42
|
if (options?.pick)
|
|
26
43
|
options.pick = normalizePick(resource, options.pick);
|
|
27
44
|
if (options?.omit)
|
|
@@ -39,7 +56,7 @@ export var OpraQuery;
|
|
|
39
56
|
Object.assign(out, _.omit(options, Object.keys(out)));
|
|
40
57
|
return out;
|
|
41
58
|
}
|
|
42
|
-
OpraQuery.
|
|
59
|
+
OpraQuery.forGetEntity = forGetEntity;
|
|
43
60
|
function forSearch(resource, options) {
|
|
44
61
|
if (options?.pick)
|
|
45
62
|
options.pick = normalizePick(resource, options.pick);
|
|
@@ -147,19 +164,19 @@ function checkKeyFields(resource, key) {
|
|
|
147
164
|
throw new Error(`"${resource.name}" has no primary key`);
|
|
148
165
|
}
|
|
149
166
|
function normalizePick(resource, fields) {
|
|
150
|
-
const fieldsTree =
|
|
167
|
+
const fieldsTree = pathToTree(fields) || {};
|
|
151
168
|
return _normalizeFieldsList([], resource.service, resource, resource.dataType, fieldsTree, '', {
|
|
152
|
-
|
|
169
|
+
additionalFields: true
|
|
153
170
|
});
|
|
154
171
|
}
|
|
155
172
|
function _normalizeFieldsList(target, service, resource, dataType, node, parentPath = '', options) {
|
|
156
173
|
let curPath = '';
|
|
157
174
|
for (const k of Object.keys(node)) {
|
|
158
175
|
const nodeVal = node[k];
|
|
159
|
-
const prop = dataType?.
|
|
176
|
+
const prop = dataType?.fields.get(k);
|
|
160
177
|
if (!prop) {
|
|
161
178
|
curPath = parentPath ? parentPath + '.' + k : k;
|
|
162
|
-
if (!options?.
|
|
179
|
+
if (!options?.additionalFields || (dataType && !dataType.additionalFields))
|
|
163
180
|
throw new TypeError(`Unknown field path "${resource.name + '.' + curPath}"`);
|
|
164
181
|
if (typeof nodeVal === 'object')
|
|
165
182
|
_normalizeFieldsList(target, service, resource, undefined, nodeVal, curPath, options);
|
|
@@ -170,7 +187,7 @@ function _normalizeFieldsList(target, service, resource, dataType, node, parentP
|
|
|
170
187
|
curPath = parentPath ? parentPath + '.' + prop.name : prop.name;
|
|
171
188
|
const propType = service.getDataType(prop.type || 'string');
|
|
172
189
|
if (typeof nodeVal === 'object') {
|
|
173
|
-
if (!(propType instanceof ComplexType))
|
|
190
|
+
if (!(propType && propType instanceof ComplexType))
|
|
174
191
|
throw new TypeError(`"${curPath}" is not a complex type and has no sub fields`);
|
|
175
192
|
if (target.findIndex(x => x === parentPath) >= 0)
|
|
176
193
|
continue;
|
|
@@ -1,9 +1,68 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { Maybe } from 'ts-gems';
|
|
2
|
+
import { Expression } from '@opra/url';
|
|
3
|
+
import { QueryContext } from '../implementation/query-context.js';
|
|
4
|
+
import { IEntityService } from '../interfaces/entity-service.interface.js';
|
|
5
|
+
import { OpraQuery } from '../interfaces/query.interface.js';
|
|
6
|
+
import { EntityInput, EntityOutput, QueryType } from '../types.js';
|
|
7
|
+
export interface JsonDataServiceAgs<T> {
|
|
8
|
+
resourceName: string;
|
|
9
|
+
data: T[];
|
|
10
|
+
primaryKey: string;
|
|
5
11
|
}
|
|
6
|
-
export declare
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
export declare namespace JsonDataService {
|
|
13
|
+
type GetOptions = {
|
|
14
|
+
pick?: string[];
|
|
15
|
+
omit?: string[];
|
|
16
|
+
include?: string[];
|
|
17
|
+
};
|
|
18
|
+
type SearchOptions = {
|
|
19
|
+
pick?: string[];
|
|
20
|
+
omit?: string[];
|
|
21
|
+
include?: string[];
|
|
22
|
+
limit?: number;
|
|
23
|
+
skip?: number;
|
|
24
|
+
distinct?: boolean;
|
|
25
|
+
total?: boolean;
|
|
26
|
+
filter?: string | Expression | {};
|
|
27
|
+
};
|
|
28
|
+
type CreateOptions = {
|
|
29
|
+
pick?: string[];
|
|
30
|
+
omit?: string[];
|
|
31
|
+
include?: string[];
|
|
32
|
+
};
|
|
33
|
+
type UpdateOptions = {
|
|
34
|
+
pick?: string[];
|
|
35
|
+
omit?: string[];
|
|
36
|
+
include?: string[];
|
|
37
|
+
};
|
|
38
|
+
type UpdateManyOptions = {
|
|
39
|
+
filter?: string | Expression | {};
|
|
40
|
+
};
|
|
41
|
+
type DeleteManyOptions = {
|
|
42
|
+
filter?: string | Expression | {};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare class JsonDataService<T, TOutput = EntityOutput<T>> implements IEntityService {
|
|
46
|
+
resourceName: string;
|
|
47
|
+
data: T[];
|
|
48
|
+
primaryKey: string;
|
|
49
|
+
constructor(args: JsonDataServiceAgs<T>);
|
|
50
|
+
processRequest(ctx: QueryContext): any;
|
|
51
|
+
get(keyValue: any, options?: JsonDataService.GetOptions): Maybe<TOutput>;
|
|
52
|
+
count(options?: JsonDataService.SearchOptions): Maybe<number>;
|
|
53
|
+
search(options?: JsonDataService.SearchOptions): Maybe<TOutput>[];
|
|
54
|
+
create(data: EntityInput<T>, options?: JsonDataService.CreateOptions): TOutput;
|
|
55
|
+
update(keyValue: any, data: EntityInput<T>, options?: JsonDataService.UpdateOptions): Maybe<TOutput>;
|
|
56
|
+
updateMany(data: EntityInput<T>, options?: JsonDataService.UpdateManyOptions): number;
|
|
57
|
+
delete(keyValue: any): boolean;
|
|
58
|
+
deleteMany(options?: JsonDataService.DeleteManyOptions): number;
|
|
59
|
+
static filterFields(obj: any, pick: string[] | undefined, omit: string[] | undefined, include: string[] | undefined): any;
|
|
60
|
+
static prepare(query: OpraQuery): {
|
|
61
|
+
method: QueryType;
|
|
62
|
+
options: any;
|
|
63
|
+
keyValue?: any;
|
|
64
|
+
values?: any;
|
|
65
|
+
args: any[];
|
|
66
|
+
};
|
|
67
|
+
static convertFilter(str: string | Expression | undefined | {}): any;
|
|
9
68
|
}
|
|
@@ -1,10 +1,247 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
1
2
|
import ruleJudgment from 'rule-judgment';
|
|
2
|
-
import {
|
|
3
|
+
import { $parse, ArrayExpression, BooleanLiteral, ComparisonExpression, DateLiteral, Expression, LogicalExpression, NullLiteral, NumberLiteral, ParenthesesExpression, QualifiedIdentifier, StringLiteral, TimeLiteral } from '@opra/url';
|
|
4
|
+
import { ResourceConflictError } from '../exception/index.js';
|
|
3
5
|
// Fix invalid importing (with ESM) of rule-judgment package
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
+
const createFilterFn = typeof ruleJudgment === 'function'
|
|
7
|
+
? ruleJudgment
|
|
8
|
+
: ruleJudgment.default;
|
|
9
|
+
export class JsonDataService {
|
|
10
|
+
resourceName;
|
|
6
11
|
data;
|
|
12
|
+
primaryKey;
|
|
7
13
|
constructor(args) {
|
|
8
|
-
|
|
14
|
+
this.resourceName = args.resourceName;
|
|
15
|
+
this.data = args.data;
|
|
16
|
+
this.primaryKey = args.primaryKey;
|
|
17
|
+
}
|
|
18
|
+
processRequest(ctx) {
|
|
19
|
+
const prepared = JsonDataService.prepare(ctx.query);
|
|
20
|
+
const fn = this[prepared.method];
|
|
21
|
+
if (!fn)
|
|
22
|
+
throw new TypeError(`Unimplemented method (${prepared.method})`);
|
|
23
|
+
return fn.apply(this, prepared.args);
|
|
24
|
+
}
|
|
25
|
+
get(keyValue, options) {
|
|
26
|
+
const primaryKey = this.primaryKey;
|
|
27
|
+
let v = this.data.find(x => '' + x[primaryKey] === '' + keyValue);
|
|
28
|
+
v = JsonDataService.filterFields(v, options?.pick, options?.omit, options?.include);
|
|
29
|
+
return v;
|
|
30
|
+
}
|
|
31
|
+
count(options) {
|
|
32
|
+
return this.search(options).length;
|
|
33
|
+
}
|
|
34
|
+
search(options) {
|
|
35
|
+
let out;
|
|
36
|
+
if (options?.filter) {
|
|
37
|
+
const filter = JsonDataService.convertFilter(options.filter);
|
|
38
|
+
const filterFn = createFilterFn(filter);
|
|
39
|
+
out = this.data.filter(filterFn);
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
out = this.data;
|
|
43
|
+
return out.map(v => JsonDataService.filterFields(v, options?.pick, options?.omit, options?.include));
|
|
44
|
+
}
|
|
45
|
+
create(data, options) {
|
|
46
|
+
if (this.get(data[this.primaryKey]))
|
|
47
|
+
throw new ResourceConflictError(this.resourceName, this.primaryKey);
|
|
48
|
+
this.data.push(data);
|
|
49
|
+
return JsonDataService.filterFields(data, options?.pick, options?.omit, options?.include);
|
|
50
|
+
}
|
|
51
|
+
update(keyValue, data, options) {
|
|
52
|
+
const primaryKey = this.primaryKey;
|
|
53
|
+
const i = this.data.findIndex(x => '' + x[primaryKey] === '' + keyValue);
|
|
54
|
+
if (i >= 0) {
|
|
55
|
+
data = Object.assign(this.data[i], data);
|
|
56
|
+
return JsonDataService.filterFields(data, options?.pick, options?.omit, options?.include);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
updateMany(data, options) {
|
|
60
|
+
const items = this.search({ filter: options?.filter });
|
|
61
|
+
for (let i = 0; i < items.length; i++) {
|
|
62
|
+
Object.assign(items[i], data);
|
|
63
|
+
}
|
|
64
|
+
return items.length;
|
|
65
|
+
}
|
|
66
|
+
delete(keyValue) {
|
|
67
|
+
const primaryKey = this.primaryKey;
|
|
68
|
+
const i = this.data.findIndex(x => '' + x[primaryKey] === '' + keyValue);
|
|
69
|
+
if (i >= 0) {
|
|
70
|
+
this.data = this.data.slice(i, 1);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
deleteMany(options) {
|
|
76
|
+
const items = this.search({ filter: options?.filter });
|
|
77
|
+
this.data = this.data.filter(x => !items.includes(x));
|
|
78
|
+
return items.length;
|
|
79
|
+
}
|
|
80
|
+
static filterFields(obj,
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
82
|
+
pick,
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
84
|
+
omit,
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
+
include) {
|
|
87
|
+
if (!obj)
|
|
88
|
+
return;
|
|
89
|
+
return obj;
|
|
90
|
+
}
|
|
91
|
+
static prepare(query) {
|
|
92
|
+
switch (query.queryType) {
|
|
93
|
+
case 'create': {
|
|
94
|
+
const options = _.omitBy({
|
|
95
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
96
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
97
|
+
include: query.include?.length ? query.include : undefined,
|
|
98
|
+
}, _.isNil);
|
|
99
|
+
const { data } = query;
|
|
100
|
+
return {
|
|
101
|
+
method: query.queryType,
|
|
102
|
+
values: data,
|
|
103
|
+
options,
|
|
104
|
+
args: [data, options]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
case 'get': {
|
|
108
|
+
const options = _.omitBy({
|
|
109
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
110
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
111
|
+
include: query.include?.length ? query.include : undefined,
|
|
112
|
+
}, _.isNil);
|
|
113
|
+
const keyValue = query.keyValue;
|
|
114
|
+
return {
|
|
115
|
+
method: query.queryType,
|
|
116
|
+
keyValue,
|
|
117
|
+
options,
|
|
118
|
+
args: [keyValue, options]
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
case 'search': {
|
|
122
|
+
const options = _.omitBy({
|
|
123
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
124
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
125
|
+
include: query.include?.length ? query.include : undefined,
|
|
126
|
+
sort: query.sort?.length ? query.sort : undefined,
|
|
127
|
+
limit: query.limit,
|
|
128
|
+
offset: query.skip,
|
|
129
|
+
distinct: query.distinct,
|
|
130
|
+
total: query.count,
|
|
131
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
132
|
+
}, _.isNil);
|
|
133
|
+
return {
|
|
134
|
+
method: query.queryType,
|
|
135
|
+
options,
|
|
136
|
+
args: [options]
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
case 'update': {
|
|
140
|
+
const options = _.omitBy({
|
|
141
|
+
pick: query.pick?.length ? query.pick : undefined,
|
|
142
|
+
omit: query.omit?.length ? query.omit : undefined,
|
|
143
|
+
include: query.include?.length ? query.include : undefined,
|
|
144
|
+
}, _.isNil);
|
|
145
|
+
const { data } = query;
|
|
146
|
+
const keyValue = query.keyValue;
|
|
147
|
+
return {
|
|
148
|
+
method: query.queryType,
|
|
149
|
+
keyValue: query.keyValue,
|
|
150
|
+
values: data,
|
|
151
|
+
options,
|
|
152
|
+
args: [keyValue, data, options]
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
case 'updateMany': {
|
|
156
|
+
const options = _.omitBy({
|
|
157
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
158
|
+
}, _.isNil);
|
|
159
|
+
const { data } = query;
|
|
160
|
+
return {
|
|
161
|
+
method: query.queryType,
|
|
162
|
+
options,
|
|
163
|
+
args: [data, options]
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
case 'delete': {
|
|
167
|
+
const options = {};
|
|
168
|
+
const keyValue = query.keyValue;
|
|
169
|
+
return {
|
|
170
|
+
method: query.queryType,
|
|
171
|
+
keyValue,
|
|
172
|
+
options,
|
|
173
|
+
args: [keyValue, options]
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
case 'deleteMany': {
|
|
177
|
+
const options = _.omitBy({
|
|
178
|
+
filter: JsonDataService.convertFilter(query.filter)
|
|
179
|
+
}, _.isNil);
|
|
180
|
+
return {
|
|
181
|
+
method: query.queryType,
|
|
182
|
+
options,
|
|
183
|
+
args: [options]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
default:
|
|
187
|
+
throw new Error(`Unimplemented query type "${query.queryType}"`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
static convertFilter(str) {
|
|
191
|
+
const ast = typeof str === 'string'
|
|
192
|
+
? $parse(str)
|
|
193
|
+
: str;
|
|
194
|
+
if (!ast || !(ast instanceof Expression))
|
|
195
|
+
return ast;
|
|
196
|
+
if (ast instanceof ComparisonExpression) {
|
|
197
|
+
const left = JsonDataService.convertFilter(ast.left);
|
|
198
|
+
const right = JsonDataService.convertFilter(ast.right);
|
|
199
|
+
switch (ast.op) {
|
|
200
|
+
case '=':
|
|
201
|
+
return { $eq: { [left]: right } };
|
|
202
|
+
case '!=':
|
|
203
|
+
return { $ne: { [left]: right } };
|
|
204
|
+
case '>':
|
|
205
|
+
return { $gt: { [left]: right } };
|
|
206
|
+
case '>=':
|
|
207
|
+
return { $gte: { [left]: right } };
|
|
208
|
+
case '<':
|
|
209
|
+
return { $lt: { [left]: right } };
|
|
210
|
+
case '<=':
|
|
211
|
+
return { $lte: { [left]: right } };
|
|
212
|
+
case 'in':
|
|
213
|
+
return { $in: { [left]: right } };
|
|
214
|
+
case '!in':
|
|
215
|
+
return { $nin: { [left]: right } };
|
|
216
|
+
default:
|
|
217
|
+
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (ast instanceof QualifiedIdentifier) {
|
|
221
|
+
return ast.value;
|
|
222
|
+
}
|
|
223
|
+
if (ast instanceof NumberLiteral ||
|
|
224
|
+
ast instanceof StringLiteral ||
|
|
225
|
+
ast instanceof BooleanLiteral ||
|
|
226
|
+
ast instanceof NullLiteral ||
|
|
227
|
+
ast instanceof DateLiteral ||
|
|
228
|
+
ast instanceof TimeLiteral) {
|
|
229
|
+
return ast.value;
|
|
230
|
+
}
|
|
231
|
+
if (ast instanceof ArrayExpression) {
|
|
232
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
233
|
+
}
|
|
234
|
+
if (ast instanceof LogicalExpression) {
|
|
235
|
+
if (ast.op === 'or')
|
|
236
|
+
return { $or: ast.items.map(JsonDataService.convertFilter) };
|
|
237
|
+
return { $and: ast.items.map(JsonDataService.convertFilter) };
|
|
238
|
+
}
|
|
239
|
+
if (ast instanceof ArrayExpression) {
|
|
240
|
+
return ast.items.map(JsonDataService.convertFilter);
|
|
241
|
+
}
|
|
242
|
+
if (ast instanceof ParenthesesExpression) {
|
|
243
|
+
return JsonDataService.convertFilter(ast.expression);
|
|
244
|
+
}
|
|
245
|
+
throw new Error(`${ast.type} is not implemented yet`);
|
|
9
246
|
}
|
|
10
247
|
}
|
package/esm/types.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export declare type
|
|
4
|
-
export declare type TypeThunk<T = any> = Thunk<Type<T>>;
|
|
5
|
-
export declare type TypeThunkAsync<T = any> = ThunkAsync<Type<T>>;
|
|
6
|
-
export declare type QueryScope = 'collection' | 'instance' | 'property';
|
|
7
|
-
export declare type QueryType = 'create' | 'get' | 'update' | 'patch' | 'delete' | 'execute' | 'search' | 'updateMany' | 'patchMany' | 'deleteMany';
|
|
8
|
-
export declare type OperationType = 'create' | 'read' | 'update' | 'patch' | 'delete' | 'execute';
|
|
1
|
+
import { Builtin, DeepPickWritable } from 'ts-gems';
|
|
2
|
+
import { OpraSchema } from '@opra/schema';
|
|
3
|
+
export declare type QueryType = OpraSchema.EntityMethodType | 'schema' | 'execute';
|
|
9
4
|
export declare type KeyValue = string | number | boolean | object;
|
|
5
|
+
export declare type EntityInput<T> = DeepNullableIfPartial<DeepPickWritable<T>>;
|
|
6
|
+
export declare type EntityOutput<T> = DeepNullableIfPartial<T>;
|
|
7
|
+
export declare type DeepNullableIfPartial<T> = _DeepNullableIfPartial<T>;
|
|
8
|
+
declare type _DeepNullableIfPartial<T> = T extends Builtin ? T : T extends Promise<infer U> ? Promise<DeepNullableIfPartial<U>> : T extends (infer U)[] ? DeepNullableIfPartial<U>[] : {
|
|
9
|
+
[P in keyof T]?: DeepNullableIfPartial<Exclude<T[P], undefined>> | null;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
package/esm/utils/create-i18n.js
CHANGED
|
@@ -4,8 +4,8 @@ import { getCallerFile } from './get-caller-file.util.js';
|
|
|
4
4
|
export async function createI18n(options) {
|
|
5
5
|
const opts = {
|
|
6
6
|
...options,
|
|
7
|
-
resourceDirs: undefined
|
|
8
7
|
};
|
|
8
|
+
delete opts.resourceDirs;
|
|
9
9
|
const instance = I18n.createInstance(opts);
|
|
10
10
|
await instance.init();
|
|
11
11
|
await instance.loadResourceDir(path.resolve(getCallerFile(), '../../../i18n'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function getCallerFile(position?: number):
|
|
1
|
+
export declare function getCallerFile(position?: number): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const PATH_PATTERN = /^(?:file:\/\/)?(.+)$/;
|
|
1
2
|
export function getCallerFile(position = 1) {
|
|
2
3
|
if (position >= Error.stackTraceLimit) {
|
|
3
4
|
throw new TypeError('getCallerFile(position) requires position be less then Error.stackTraceLimit but position was: `' +
|
|
@@ -10,6 +11,10 @@ export function getCallerFile(position = 1) {
|
|
|
10
11
|
if (stack !== null && typeof stack === 'object') {
|
|
11
12
|
// stack[0] holds this file
|
|
12
13
|
// stack[1] holds where this function was called
|
|
13
|
-
|
|
14
|
+
const s = stack[position] ?
|
|
15
|
+
stack[position].getFileName() : undefined;
|
|
16
|
+
const m = s ? PATH_PATTERN.exec(s) : undefined;
|
|
17
|
+
return m ? m[1] : '';
|
|
14
18
|
}
|
|
19
|
+
return '';
|
|
15
20
|
}
|
package/i18n/en/error.json
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
"FORBIDDEN": "You are not authorized to perform this action",
|
|
5
5
|
"INTERNAL_SERVER_ERROR": "Internal server error",
|
|
6
6
|
"METHOD_NOT_ALLOWED": "Method Not Allowed",
|
|
7
|
+
"NOT_ACCEPTABLE": "Not Acceptable",
|
|
7
8
|
"NOT_FOUND": "Not found",
|
|
8
9
|
"UNAUTHORIZED": "You have not been authenticated to perform this action",
|
|
9
10
|
"UNPROCESSABLE_ENTITY": "Unprocessable entity",
|
|
10
11
|
|
|
12
|
+
"RESOLVER_FORBIDDEN": "The resource endpoint does not accept '{{queryType}}' operations",
|
|
13
|
+
"RESOURCE_NOT_FOUND": "The resource '{{resource}}' could not be found",
|
|
11
14
|
"RESOURCE_CONFLICT": "There is already an other {{resource}} resource with same field values ({{fields}})"
|
|
12
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/core",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Opra schema package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,13 +27,14 @@
|
|
|
27
27
|
"clean:cover": "rimraf ../../coverage/core"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@opra/i18n": "^0.0
|
|
31
|
-
"@opra/optionals": "^0.0
|
|
32
|
-
"@opra/schema": "^0.0
|
|
33
|
-
"@opra/url": "^0.0
|
|
30
|
+
"@opra/i18n": "^0.1.0",
|
|
31
|
+
"@opra/optionals": "^0.1.0",
|
|
32
|
+
"@opra/schema": "^0.1.0",
|
|
33
|
+
"@opra/url": "^0.1.0",
|
|
34
34
|
"lodash": "^4.17.21",
|
|
35
35
|
"putil-isplainobject": "^1.1.4",
|
|
36
36
|
"putil-varhelpers": "^1.6.4",
|
|
37
|
+
"putil-merge": "^3.9.0",
|
|
37
38
|
"rule-judgment": "^1.1.5",
|
|
38
39
|
"strict-typed-events": "^2.2.0",
|
|
39
40
|
"ts-gems": "^2.2.0"
|
|
@@ -43,8 +44,6 @@
|
|
|
43
44
|
"express": "^4.18.1"
|
|
44
45
|
},
|
|
45
46
|
"type": "module",
|
|
46
|
-
"main": "cjs/index.js",
|
|
47
|
-
"module": "esm/index.js",
|
|
48
47
|
"types": "esm/index.d.ts",
|
|
49
48
|
"exports": {
|
|
50
49
|
".": {
|
package/cjs/constants.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApiEntityResource = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
require("reflect-metadata");
|
|
6
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
|
-
const constants_js_1 = require("../constants.js");
|
|
8
|
-
const NESTJS_INJECTABLE_WATERMARK = '__injectable__';
|
|
9
|
-
const NAME_PATTERN = /^(.*)Resource$/;
|
|
10
|
-
function ApiEntityResource(entityFunc, options) {
|
|
11
|
-
return function (target) {
|
|
12
|
-
const name = options?.name || target.name.match(NAME_PATTERN)?.[1] || target.name;
|
|
13
|
-
const meta = {
|
|
14
|
-
kind: 'EntityResource',
|
|
15
|
-
type: entityFunc,
|
|
16
|
-
name
|
|
17
|
-
};
|
|
18
|
-
Object.assign(meta, lodash_1.default.omit(options, Object.keys(meta)));
|
|
19
|
-
Reflect.defineMetadata(constants_js_1.RESOURCE_METADATA, meta, target);
|
|
20
|
-
/* Define Injectable metadata for NestJS support*/
|
|
21
|
-
Reflect.defineMetadata(NESTJS_INJECTABLE_WATERMARK, true, target);
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
exports.ApiEntityResource = ApiEntityResource;
|