@opra/sqb 1.26.3 → 1.27.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/README.md +24 -1
- package/adapter-utils/prepare-filter.d.ts +3 -4
- package/adapter-utils/prepare-filter.js +16 -31
- package/augmentation/datatype-factory.augmentation.js +1 -1
- package/package.json +3 -3
- package/sqb-adapter.d.ts +41 -1
- package/sqb-adapter.js +21 -6
- package/sqb-collection-service.d.ts +141 -159
- package/sqb-collection-service.js +52 -99
- package/sqb-entity-service.d.ts +133 -154
- package/sqb-entity-service.js +129 -132
- package/sqb-service-base.d.ts +17 -13
- package/sqb-service-base.js +15 -17
- package/sqb-singleton-service.d.ts +78 -88
- package/sqb-singleton-service.js +26 -26
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
1
|
# @opra/sqb
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[![NPM Version][npm-image]][npm-url]
|
|
4
|
+
[![NPM Downloads][downloads-image]][downloads-url]
|
|
5
|
+
[![CI Tests][ci-test-image]][ci-test-url]
|
|
6
|
+
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Support
|
|
10
|
+
You can report bugs and discuss features on the [GitHub issues](https://github.com/panates/opra/issues) page.
|
|
11
|
+
|
|
12
|
+
## Node Compatibility
|
|
13
|
+
- node >= 20.x
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## License
|
|
17
|
+
Available under [MIT](LICENSE) license.
|
|
18
|
+
|
|
19
|
+
[npm-image]: https://img.shields.io/npm/v/@opra/sqb
|
|
20
|
+
[npm-url]: https://npmjs.org/package/@opra/sqb
|
|
21
|
+
[downloads-image]: https://img.shields.io/npm/dm/@opra/sqb.svg
|
|
22
|
+
[downloads-url]: https://npmjs.org/package/@opra/sqb
|
|
23
|
+
[ci-test-image]: https://github.com/panates/opra/actions/workflows/test.yml/badge.svg
|
|
24
|
+
[ci-test-url]: https://github.com/panates/opra/actions/workflows/test.yml
|
|
25
|
+
[coveralls-image]: https://coveralls.io/repos/github/panates/opra/badge.svg?branch=main
|
|
26
|
+
[coveralls-url]: https://coveralls.io/github/panates/opra?branch=main
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import '@opra/core';
|
|
2
2
|
import type { SQBAdapter } from '../sqb-adapter.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Prepares the SQB filter based on the provided filters and options.
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
7
|
-
*
|
|
8
|
-
* @returns {Expression} - The prepared SQB Expression.
|
|
6
|
+
* @param filters - The filter(s) to be applied. Can be a single filter or an array of filters.
|
|
7
|
+
* @returns The prepared SQB Expression, or `undefined` if no filters are provided.
|
|
9
8
|
*/
|
|
10
9
|
export default function prepareFilter(filters: SQBAdapter.FilterInput | SQBAdapter.FilterInput[]): any;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import '@opra/core';
|
|
2
2
|
import { OpraFilter } from '@opra/common';
|
|
3
|
-
import
|
|
3
|
+
import { Operators, sql } from '@sqb/builder';
|
|
4
4
|
import { vg } from 'valgen';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Prepares the SQB filter based on the provided filters and options.
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
9
|
-
*
|
|
10
|
-
* @returns {Expression} - The prepared SQB Expression.
|
|
8
|
+
* @param filters - The filter(s) to be applied. Can be a single filter or an array of filters.
|
|
9
|
+
* @returns The prepared SQB Expression, or `undefined` if no filters are provided.
|
|
11
10
|
*/
|
|
12
11
|
export default function prepareFilter(filters) {
|
|
13
12
|
const filtersArray = Array.isArray(filters) ? filters : [filters];
|
|
@@ -27,7 +26,7 @@ export default function prepareFilter(filters) {
|
|
|
27
26
|
if (ast)
|
|
28
27
|
arr.push(ast);
|
|
29
28
|
}
|
|
30
|
-
return arr.length > 1 ?
|
|
29
|
+
return arr.length > 1 ? sql.And(...arr) : arr[0];
|
|
31
30
|
}
|
|
32
31
|
const _isDate = vg.isDate({ trim: 'day' });
|
|
33
32
|
const _isDateTime = vg.isDate();
|
|
@@ -44,12 +43,12 @@ function prepareFilterAst(ast) {
|
|
|
44
43
|
return ast.items.map(prepareFilterAst);
|
|
45
44
|
}
|
|
46
45
|
if (ast instanceof OpraFilter.NegativeExpression) {
|
|
47
|
-
return
|
|
46
|
+
return sql.Not(prepareFilterAst(ast.expression));
|
|
48
47
|
}
|
|
49
48
|
if (ast instanceof OpraFilter.LogicalExpression) {
|
|
50
49
|
if (ast.op === 'or')
|
|
51
|
-
return
|
|
52
|
-
return
|
|
50
|
+
return sql.Or(...ast.items.map(prepareFilterAst));
|
|
51
|
+
return sql.And(...ast.items.map(prepareFilterAst));
|
|
53
52
|
}
|
|
54
53
|
if (ast instanceof OpraFilter.ParenthesizedExpression) {
|
|
55
54
|
return prepareFilterAst(ast.expression);
|
|
@@ -68,33 +67,19 @@ function prepareFilterAst(ast) {
|
|
|
68
67
|
return x;
|
|
69
68
|
}
|
|
70
69
|
switch (ast.op) {
|
|
71
|
-
case '=':
|
|
72
|
-
return sqb.Eq(left, right);
|
|
73
|
-
case '!=':
|
|
74
|
-
return sqb.Ne(left, right);
|
|
75
|
-
case '>':
|
|
76
|
-
return sqb.Gt(left, right);
|
|
77
|
-
case '>=':
|
|
78
|
-
return sqb.Gte(left, right);
|
|
79
|
-
case '<':
|
|
80
|
-
return sqb.Lt(left, right);
|
|
81
|
-
case '<=':
|
|
82
|
-
return sqb.Lte(left, right);
|
|
83
|
-
case 'in':
|
|
84
|
-
return sqb.In(left, right);
|
|
85
|
-
case '!in':
|
|
86
|
-
return sqb.Nin(left, right);
|
|
87
70
|
case 'like':
|
|
88
|
-
return
|
|
71
|
+
return sql.Like(left, String(right).replace(/\*/g, '%'));
|
|
89
72
|
case 'ilike':
|
|
90
|
-
return
|
|
73
|
+
return sql.ILike(left, String(right).replace(/\*/g, '%'));
|
|
91
74
|
case '!like':
|
|
92
|
-
return
|
|
75
|
+
return sql.NotLike(left, String(right).replace(/\*/g, '%'));
|
|
93
76
|
case '!ilike':
|
|
94
|
-
return
|
|
95
|
-
default:
|
|
96
|
-
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
77
|
+
return sql.NotILike(left, String(right).replace(/\*/g, '%'));
|
|
97
78
|
}
|
|
79
|
+
const fn = Operators[ast.op];
|
|
80
|
+
if (fn)
|
|
81
|
+
return fn(left, right);
|
|
82
|
+
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
98
83
|
}
|
|
99
84
|
if (ast instanceof OpraFilter.QualifiedIdentifier ||
|
|
100
85
|
ast instanceof OpraFilter.Literal) {
|
|
@@ -13,7 +13,7 @@ DataTypeFactory._prepareComplexTypeArgs = async function (context, owner, initAr
|
|
|
13
13
|
const sqbField = sqbMeta && EntityMetadata.getField(sqbMeta, fieldName);
|
|
14
14
|
if (!sqbField)
|
|
15
15
|
continue;
|
|
16
|
-
|
|
16
|
+
/* Copy type information from sqb metadata to opra */
|
|
17
17
|
if (!fieldSchema.type || fieldSchema.type === Object) {
|
|
18
18
|
if (isAssociationField(sqbField)) {
|
|
19
19
|
if (!fieldSchema.type) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/sqb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"description": "Opra SQB adapter package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"valgen": "^6.0.3"
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
-
"@opra/core": "^1.
|
|
14
|
-
"@opra/http": "^1.
|
|
13
|
+
"@opra/core": "^1.27.0",
|
|
14
|
+
"@opra/http": "^1.27.0",
|
|
15
15
|
"@sqb/builder": ">4.0.0 <5",
|
|
16
16
|
"@sqb/connect": ">4.0.0 <5"
|
|
17
17
|
},
|
package/sqb-adapter.d.ts
CHANGED
|
@@ -2,20 +2,60 @@ import type { OpraFilter } from '@opra/common';
|
|
|
2
2
|
import type { ExecutionContext } from '@opra/core';
|
|
3
3
|
import { type Repository } from '@sqb/connect';
|
|
4
4
|
import _prepareFilter from './adapter-utils/prepare-filter.js';
|
|
5
|
+
/**
|
|
6
|
+
* SQBAdapter namespace provides types and utility functions for integrating SQB with Opra.
|
|
7
|
+
*/
|
|
5
8
|
export declare namespace SQBAdapter {
|
|
9
|
+
/**
|
|
10
|
+
* Represents a single identifier type.
|
|
11
|
+
*/
|
|
6
12
|
type Id = string | number | boolean | Date;
|
|
13
|
+
/**
|
|
14
|
+
* Represents a single identifier or a composite key.
|
|
15
|
+
*/
|
|
7
16
|
type IdOrIds = Id | Record<string, Id>;
|
|
17
|
+
/**
|
|
18
|
+
* Represents the input for a filter, which can be an Opra filter expression,
|
|
19
|
+
* a SQB filter object, a string, or undefined.
|
|
20
|
+
*/
|
|
8
21
|
type FilterInput = OpraFilter.Expression | Repository.FindManyOptions['filter'] | string | undefined;
|
|
9
22
|
/**
|
|
10
|
-
*
|
|
23
|
+
* Parses the given filter input into a SQB filter expression.
|
|
24
|
+
* @deprecated Use {@link prepareFilter} instead.
|
|
11
25
|
*/
|
|
12
26
|
const parseFilter: typeof _prepareFilter;
|
|
27
|
+
/**
|
|
28
|
+
* Prepares the given filter input into a SQB filter expression.
|
|
29
|
+
*/
|
|
13
30
|
const prepareFilter: typeof _prepareFilter;
|
|
31
|
+
/**
|
|
32
|
+
* Represents a request that has been transformed for SQB operations.
|
|
33
|
+
*/
|
|
14
34
|
interface TransformedRequest {
|
|
35
|
+
/**
|
|
36
|
+
* The operation method name.
|
|
37
|
+
*/
|
|
15
38
|
method: 'create' | 'delete' | 'deleteMany' | 'get' | 'replace' | 'findMany' | 'update' | 'updateMany';
|
|
39
|
+
/**
|
|
40
|
+
* The primary key for the operation, if applicable.
|
|
41
|
+
*/
|
|
16
42
|
key?: any;
|
|
43
|
+
/**
|
|
44
|
+
* The data object for create or update operations.
|
|
45
|
+
*/
|
|
17
46
|
data?: any;
|
|
47
|
+
/**
|
|
48
|
+
* Additional options for the SQB operation.
|
|
49
|
+
*/
|
|
18
50
|
options: any;
|
|
19
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses an execution context and transforms it into a SQB-compatible request.
|
|
54
|
+
*
|
|
55
|
+
* @param context - The execution context to parse.
|
|
56
|
+
* @returns A promise that resolves to the transformed request.
|
|
57
|
+
* @throws {TypeError} If the context transport is not 'http'.
|
|
58
|
+
* @throws {Error} If the operation is not compatible with SQB Adapter.
|
|
59
|
+
*/
|
|
20
60
|
function parseRequest(context: ExecutionContext): Promise<TransformedRequest>;
|
|
21
61
|
}
|
package/sqb-adapter.js
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import { EntityMetadata } from '@sqb/connect';
|
|
2
2
|
import _prepareFilter from './adapter-utils/prepare-filter.js';
|
|
3
|
+
/**
|
|
4
|
+
* SQBAdapter namespace provides types and utility functions for integrating SQB with Opra.
|
|
5
|
+
*/
|
|
3
6
|
export var SQBAdapter;
|
|
4
7
|
(function (SQBAdapter) {
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
9
|
+
* Parses the given filter input into a SQB filter expression.
|
|
10
|
+
* @deprecated Use {@link prepareFilter} instead.
|
|
7
11
|
*/
|
|
8
12
|
SQBAdapter.parseFilter = _prepareFilter;
|
|
13
|
+
/**
|
|
14
|
+
* Prepares the given filter input into a SQB filter expression.
|
|
15
|
+
*/
|
|
9
16
|
SQBAdapter.prepareFilter = _prepareFilter;
|
|
17
|
+
/**
|
|
18
|
+
* Parses an execution context and transforms it into a SQB-compatible request.
|
|
19
|
+
*
|
|
20
|
+
* @param context - The execution context to parse.
|
|
21
|
+
* @returns A promise that resolves to the transformed request.
|
|
22
|
+
* @throws {TypeError} If the context transport is not 'http'.
|
|
23
|
+
* @throws {Error} If the operation is not compatible with SQB Adapter.
|
|
24
|
+
*/
|
|
10
25
|
async function parseRequest(context) {
|
|
11
26
|
if (context.transport !== 'http') {
|
|
12
27
|
throw new TypeError('SQBAdapter can parse only HttpContext');
|
|
@@ -37,7 +52,7 @@ export var SQBAdapter;
|
|
|
37
52
|
controller.parameters.find(p => p.keyParam);
|
|
38
53
|
const key = keyParam && ctx.pathParams[String(keyParam.name)];
|
|
39
54
|
const options = {
|
|
40
|
-
filter: SQBAdapter.
|
|
55
|
+
filter: SQBAdapter.prepareFilter(ctx.queryParams.filter),
|
|
41
56
|
};
|
|
42
57
|
return {
|
|
43
58
|
method: 'delete',
|
|
@@ -47,14 +62,14 @@ export var SQBAdapter;
|
|
|
47
62
|
}
|
|
48
63
|
case 'Entity.DeleteMany': {
|
|
49
64
|
const options = {
|
|
50
|
-
filter: SQBAdapter.
|
|
65
|
+
filter: SQBAdapter.prepareFilter(ctx.queryParams.filter),
|
|
51
66
|
};
|
|
52
67
|
return { method: 'deleteMany', options };
|
|
53
68
|
}
|
|
54
69
|
case 'Entity.FindMany': {
|
|
55
70
|
const options = {
|
|
56
71
|
count: ctx.queryParams.count,
|
|
57
|
-
filter: SQBAdapter.
|
|
72
|
+
filter: SQBAdapter.prepareFilter(ctx.queryParams.filter),
|
|
58
73
|
projection: ctx.queryParams.projection ||
|
|
59
74
|
__oprDef.compositionOptions.defaultProjection,
|
|
60
75
|
limit: ctx.queryParams.limit || __oprDef.compositionOptions.defaultLimit,
|
|
@@ -96,7 +111,7 @@ export var SQBAdapter;
|
|
|
96
111
|
const key = keyParam && ctx.pathParams[String(keyParam.name)];
|
|
97
112
|
const options = {
|
|
98
113
|
projection: ctx.queryParams.projection,
|
|
99
|
-
filter: SQBAdapter.
|
|
114
|
+
filter: SQBAdapter.prepareFilter(ctx.queryParams.filter),
|
|
100
115
|
};
|
|
101
116
|
return {
|
|
102
117
|
method: 'update',
|
|
@@ -108,7 +123,7 @@ export var SQBAdapter;
|
|
|
108
123
|
case 'Entity.UpdateMany': {
|
|
109
124
|
const data = await ctx.getBody();
|
|
110
125
|
const options = {
|
|
111
|
-
filter: SQBAdapter.
|
|
126
|
+
filter: SQBAdapter.prepareFilter(ctx.queryParams.filter),
|
|
112
127
|
};
|
|
113
128
|
return {
|
|
114
129
|
method: 'updateMany',
|