nesoi 3.0.0 → 3.0.6
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 +10 -0
- package/lib/adapters/postgres/src/migrator/bucket.d.ts +20 -0
- package/lib/adapters/postgres/src/migrator/bucket.js +184 -0
- package/lib/adapters/postgres/src/migrator/csv.d.ts +7 -0
- package/lib/adapters/postgres/src/migrator/csv.js +72 -0
- package/lib/adapters/postgres/src/migrator/migration.d.ts +2 -18
- package/lib/adapters/postgres/src/migrator/migration.js +10 -158
- package/lib/adapters/postgres/src/migrator/migrator.js +8 -5
- package/lib/adapters/postgres/src/migrator/runner.d.ts +16 -6
- package/lib/adapters/postgres/src/migrator/runner.js +103 -34
- package/lib/adapters/postgres/src/postgres.bucket_adapter.d.ts +19 -22
- package/lib/adapters/postgres/src/postgres.bucket_adapter.js +116 -100
- package/lib/adapters/postgres/src/postgres.cli.d.ts +23 -3
- package/lib/adapters/postgres/src/postgres.cli.js +70 -10
- package/lib/adapters/postgres/src/postgres.config.d.ts +5 -0
- package/lib/adapters/postgres/src/postgres.config.js +2 -0
- package/lib/adapters/postgres/src/postgres.nql.d.ts +7 -3
- package/lib/adapters/postgres/src/postgres.nql.js +86 -32
- package/lib/adapters/postgres/src/postgres.provider.d.ts +18 -0
- package/lib/adapters/postgres/src/postgres.provider.js +77 -0
- package/lib/adapters/postgres/test/postgres.bucket_adapter.test.js +76 -39
- package/lib/compiler/apps/monolyth/monolyth_compiler.d.ts +3 -0
- package/lib/compiler/apps/monolyth/monolyth_compiler.js +24 -0
- package/lib/compiler/apps/monolyth/stages/2_build_typescript_stage.js +2 -1
- package/lib/compiler/apps/monolyth/stages/5_dump_cli_stage.js +1 -1
- package/lib/compiler/apps/monolyth/stages/6_dump_package_json_stage.js +1 -1
- package/lib/compiler/elements/bucket.element.js +26 -11
- package/lib/compiler/elements/constants.element.js +1 -1
- package/lib/compiler/elements/element.d.ts +2 -0
- package/lib/compiler/elements/message.element.js +4 -4
- package/lib/compiler/helpers/dump_helpers.js +5 -2
- package/lib/compiler/stages/7_dump_stage.js +2 -0
- package/lib/compiler/treeshake.js +9 -37
- package/lib/compiler/typescript/bridge/extract.js +12 -0
- package/lib/compiler/typescript/bridge/inject.js +3 -0
- package/lib/compiler/typescript/bridge/organize.js +3 -3
- package/lib/elements/blocks/block.builder.js +4 -2
- package/lib/elements/blocks/job/internal/resource_job.builder.d.ts +22 -20
- package/lib/elements/blocks/job/internal/resource_job.d.ts +2 -1
- package/lib/elements/blocks/job/internal/resource_job.js +17 -4
- package/lib/elements/blocks/job/job.js +3 -0
- package/lib/elements/blocks/job/job.types.d.ts +7 -0
- package/lib/elements/blocks/job/job.types.js +2 -0
- package/lib/elements/blocks/machine/machine.js +3 -2
- package/lib/elements/blocks/resource/resource.builder.js +2 -4
- package/lib/elements/blocks/resource/resource.d.ts +5 -3
- package/lib/elements/blocks/resource/resource.js +26 -17
- package/lib/elements/edge/controller/adapters/controller_adapter.d.ts +2 -1
- package/lib/elements/edge/controller/adapters/controller_adapter.js +11 -2
- package/lib/elements/edge/controller/controller.builder.d.ts +4 -5
- package/lib/elements/edge/controller/controller.builder.js +7 -7
- package/lib/elements/edge/controller/controller.d.ts +2 -1
- package/lib/elements/edge/controller/controller.js +8 -6
- package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +61 -23
- package/lib/elements/entities/bucket/adapters/bucket_adapter.js +22 -13
- package/lib/elements/entities/bucket/adapters/memory.bucket_adapter.d.ts +21 -22
- package/lib/elements/entities/bucket/adapters/memory.bucket_adapter.js +68 -2
- package/lib/elements/entities/bucket/adapters/memory.nql.d.ts +10 -6
- package/lib/elements/entities/bucket/adapters/memory.nql.js +38 -3
- package/lib/elements/entities/bucket/adapters/slow_memory.bucket_adapter.d.ts +0 -20
- package/lib/elements/entities/bucket/adapters/slow_memory.bucket_adapter.js +46 -30
- package/lib/elements/entities/bucket/bucket.builder.d.ts +8 -2
- package/lib/elements/entities/bucket/bucket.builder.js +13 -19
- package/lib/elements/entities/bucket/bucket.config.d.ts +5 -1
- package/lib/elements/entities/bucket/bucket.d.ts +180 -19
- package/lib/elements/entities/bucket/bucket.js +662 -48
- package/lib/elements/entities/bucket/bucket.schema.d.ts +7 -1
- package/lib/elements/entities/bucket/bucket.schema.js +2 -1
- package/lib/elements/entities/bucket/bucket.types.d.ts +2 -7
- package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +6 -2
- package/lib/elements/entities/bucket/cache/bucket_cache.js +12 -12
- package/lib/elements/entities/bucket/graph/bucket_graph.d.ts +32 -5
- package/lib/elements/entities/bucket/graph/bucket_graph.js +80 -111
- package/lib/elements/entities/bucket/graph/bucket_graph.schema.d.ts +3 -6
- package/lib/elements/entities/bucket/graph/bucket_graph.schema.js +1 -4
- package/lib/elements/entities/bucket/graph/bucket_graph_link.builder.d.ts +3 -7
- package/lib/elements/entities/bucket/graph/bucket_graph_link.builder.js +6 -2
- package/lib/elements/entities/bucket/model/bucket_model.builder.js +1 -1
- package/lib/elements/entities/bucket/model/bucket_model.convert.js +3 -3
- package/lib/elements/entities/bucket/model/bucket_model.schema.d.ts +37 -8
- package/lib/elements/entities/bucket/model/bucket_model.schema.js +25 -4
- package/lib/elements/entities/bucket/model/bucket_model_field.builder.d.ts +33 -14
- package/lib/elements/entities/bucket/model/bucket_model_field.builder.js +56 -13
- package/lib/elements/entities/bucket/query/nql.schema.d.ts +1 -0
- package/lib/elements/entities/bucket/query/nql_compiler.js +13 -2
- package/lib/elements/entities/bucket/query/nql_engine.d.ts +11 -4
- package/lib/elements/entities/bucket/query/nql_engine.js +20 -11
- package/lib/elements/entities/bucket/view/bucket_view.js +63 -35
- package/lib/elements/entities/bucket/view/bucket_view.schema.d.ts +5 -2
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.d.ts +6 -2
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.js +22 -16
- package/lib/elements/entities/constants/constants.schema.d.ts +1 -1
- package/lib/elements/entities/drive/drive_adapter.d.ts +44 -0
- package/lib/elements/entities/drive/drive_adapter.js +10 -0
- package/lib/elements/entities/drive/local.drive_adapter.d.ts +10 -0
- package/lib/elements/entities/drive/local.drive_adapter.js +34 -0
- package/lib/elements/entities/message/message.schema.d.ts +1 -0
- package/lib/elements/entities/message/message.schema.js +33 -0
- package/lib/elements/entities/message/message_parser.d.ts +5 -1
- package/lib/elements/entities/message/message_parser.js +56 -35
- package/lib/elements/entities/message/template/message_template.schema.d.ts +10 -8
- package/lib/elements/entities/message/template/message_template_field.builder.d.ts +16 -6
- package/lib/elements/entities/message/template/message_template_field.builder.js +25 -0
- package/lib/elements/entities/message/template/message_template_parser.js +2 -1
- package/lib/engine/apps/app.config.d.ts +32 -11
- package/lib/engine/apps/app.config.js +12 -0
- package/lib/engine/apps/app.d.ts +2 -0
- package/lib/engine/apps/app.js +3 -0
- package/lib/engine/apps/inline.app.d.ts +5 -3
- package/lib/engine/apps/inline.app.js +27 -12
- package/lib/engine/apps/monolyth/monolyth.app.d.ts +4 -2
- package/lib/engine/apps/monolyth/monolyth.app.js +22 -10
- package/lib/engine/auth/authn.d.ts +5 -1
- package/lib/engine/auth/zero.authn_provider.d.ts +4 -2
- package/lib/engine/auth/zero.authn_provider.js +2 -2
- package/lib/engine/cli/cli.d.ts +3 -1
- package/lib/engine/cli/cli.js +22 -3
- package/lib/engine/cli/cli_adapter.d.ts +2 -1
- package/lib/engine/cli/cli_adapter.js +2 -1
- package/lib/engine/cli/cli_input.d.ts +19 -0
- package/lib/engine/cli/cli_input.js +207 -0
- package/lib/engine/cli/ui.d.ts +1 -1
- package/lib/engine/cli/ui.js +2 -2
- package/lib/engine/daemon.d.ts +3 -2
- package/lib/engine/daemon.js +14 -2
- package/lib/engine/data/date.js +2 -2
- package/lib/engine/data/datetime.d.ts +40 -4
- package/lib/engine/data/datetime.js +70 -11
- package/lib/engine/data/decimal.d.ts +1 -1
- package/lib/engine/data/decimal.js +3 -3
- package/lib/engine/data/error.d.ts +21 -4
- package/lib/engine/data/error.js +23 -7
- package/lib/engine/data/file.d.ts +38 -0
- package/lib/engine/data/file.js +54 -0
- package/lib/engine/data/json.d.ts +6 -0
- package/lib/engine/data/json.js +26 -0
- package/lib/engine/data/obj.d.ts +1 -1
- package/lib/engine/data/trash.d.ts +14 -0
- package/lib/engine/data/trash.js +2 -0
- package/lib/engine/data/tree.d.ts +7 -12
- package/lib/engine/data/tree.js +101 -49
- package/lib/engine/module.d.ts +2 -1
- package/lib/engine/module.js +2 -5
- package/lib/engine/space.d.ts +1 -0
- package/lib/engine/space.js +6 -0
- package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +184 -24
- package/lib/engine/transaction/nodes/bucket.trx_node.js +346 -451
- package/lib/engine/transaction/nodes/bucket_query.trx_node.d.ts +4 -2
- package/lib/engine/transaction/nodes/bucket_query.trx_node.js +27 -15
- package/lib/engine/transaction/nodes/job.trx_node.d.ts +2 -1
- package/lib/engine/transaction/nodes/job.trx_node.js +6 -0
- package/lib/engine/transaction/trx.d.ts +5 -2
- package/lib/engine/transaction/trx.js +2 -2
- package/lib/engine/transaction/trx_engine.config.d.ts +1 -3
- package/lib/engine/transaction/trx_engine.d.ts +2 -2
- package/lib/engine/transaction/trx_engine.js +14 -11
- package/lib/engine/transaction/trx_node.d.ts +14 -4
- package/lib/engine/transaction/trx_node.js +50 -8
- package/lib/engine/tree.d.ts +1 -1
- package/lib/engine/util/crypto.d.ts +50 -0
- package/lib/engine/util/crypto.js +89 -0
- package/lib/engine/util/deep.d.ts +5 -0
- package/lib/engine/util/deep.js +46 -0
- package/lib/engine/util/dotenv.d.ts +2 -8
- package/lib/engine/util/dotenv.js +14 -36
- package/lib/engine/util/hash.d.ts +3 -0
- package/lib/engine/util/hash.js +23 -0
- package/lib/engine/util/log.js +1 -1
- package/lib/engine/util/mime.d.ts +10 -0
- package/lib/engine/util/mime.js +389 -0
- package/lib/engine/util/parse.d.ts +6 -5
- package/lib/engine/util/parse.js +16 -15
- package/lib/engine/util/path.d.ts +3 -0
- package/lib/engine/util/path.js +92 -0
- package/lib/engine/util/rules.d.ts +4 -0
- package/lib/engine/util/rules.js +12 -0
- package/package.json +2 -2
- package/tools/compile.js +2 -2
- package/tools/dotenv.d.ts +1 -0
- package/tools/dotenv.js +4 -0
- package/tools/joaquin/job.d.ts +5 -5
- package/tools/joaquin/mock.d.ts +23 -2
- package/tools/joaquin/mock.js +127 -21
- package/tsconfig.build.tsbuildinfo +1 -1
- package/lib/adapters/postgres/test/postgres.bucket_query.test.d.ts +0 -0
- package/lib/adapters/postgres/test/postgres.bucket_query.test.js +0 -136
|
@@ -3,6 +3,11 @@ import { $BucketViews } from './view/bucket_view.schema';
|
|
|
3
3
|
import { $BucketModel } from './model/bucket_model.schema';
|
|
4
4
|
import { NesoiObj } from "../../../engine/data/obj";
|
|
5
5
|
import { $Dependency } from "../../../engine/dependency";
|
|
6
|
+
import { $Module } from "../..";
|
|
7
|
+
import { NQL_Query } from './query/nql.schema';
|
|
8
|
+
export type $BucketTenancy<M extends $Module, B extends $Bucket> = {
|
|
9
|
+
[K in keyof M['#authn']]?: (user: M['#authn'][K]) => NQL_Query<M, B>;
|
|
10
|
+
};
|
|
6
11
|
export declare class $Bucket {
|
|
7
12
|
module: string;
|
|
8
13
|
name: string;
|
|
@@ -10,6 +15,7 @@ export declare class $Bucket {
|
|
|
10
15
|
model: $BucketModel;
|
|
11
16
|
graph: $BucketGraph;
|
|
12
17
|
views: $BucketViews;
|
|
18
|
+
tenancy?: $BucketTenancy<any, any> | undefined;
|
|
13
19
|
extended?: $Dependency | undefined;
|
|
14
20
|
$t: "bucket";
|
|
15
21
|
'#data': NesoiObj;
|
|
@@ -20,5 +26,5 @@ export declare class $Bucket {
|
|
|
20
26
|
}>;
|
|
21
27
|
'#fieldpath': {};
|
|
22
28
|
'#defaults': Record<string, any>;
|
|
23
|
-
constructor(module: string, name: string, alias: string, model: $BucketModel, graph: $BucketGraph, views: $BucketViews, extended?: $Dependency | undefined);
|
|
29
|
+
constructor(module: string, name: string, alias: string, model: $BucketModel, graph: $BucketGraph, views: $BucketViews, tenancy?: $BucketTenancy<any, any> | undefined, extended?: $Dependency | undefined);
|
|
24
30
|
}
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.$Bucket = void 0;
|
|
4
4
|
class $Bucket {
|
|
5
|
-
constructor(module, name, alias, model, graph, views, extended) {
|
|
5
|
+
constructor(module, name, alias, model, graph, views, tenancy, extended) {
|
|
6
6
|
this.module = module;
|
|
7
7
|
this.name = name;
|
|
8
8
|
this.alias = alias;
|
|
9
9
|
this.model = model;
|
|
10
10
|
this.graph = graph;
|
|
11
11
|
this.views = views;
|
|
12
|
+
this.tenancy = tenancy;
|
|
12
13
|
this.extended = extended;
|
|
13
14
|
this.$t = 'bucket';
|
|
14
15
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ObjWithOptionalId } from "../../../engine/data/obj";
|
|
2
2
|
import { $Bucket } from './bucket.schema';
|
|
3
3
|
import { DeepPartialNullable } from "../../../engine/util/deep";
|
|
4
|
-
export type PutObj<$ extends $Bucket> =
|
|
4
|
+
export type PutObj<$ extends $Bucket> = ObjWithOptionalId<$['#data']> & (keyof $['#composition'] extends never ? {} : {
|
|
5
5
|
'#composition': {
|
|
6
6
|
[K in keyof $['#composition']]: $['#composition'][K]['many'] extends true ? (PutObj<$['#composition'][K]['bucket']> | ($['#composition'][K]['optional'] extends true ? undefined : never))[] : PutObj<$['#composition'][K]['bucket']> | ($['#composition'][K]['optional'] extends true ? undefined : never);
|
|
7
7
|
};
|
|
@@ -13,11 +13,6 @@ export type CreateObj<$ extends $Bucket> = Omit<$['#data'], 'id' | keyof $['#def
|
|
|
13
13
|
[K in keyof $['#composition']]: $['#composition'][K]['many'] extends true ? (PutObj<$['#composition'][K]['bucket']> | ($['#composition'][K]['optional'] extends true ? undefined : never))[] : PutObj<$['#composition'][K]['bucket']> | ($['#composition'][K]['optional'] extends true ? undefined : never);
|
|
14
14
|
};
|
|
15
15
|
});
|
|
16
|
-
export type ReplaceObj<$ extends $Bucket> = $['#data'] & (string extends keyof $['#composition'] ? {} : keyof $['#composition'] extends never ? {} : {
|
|
17
|
-
'#composition': {
|
|
18
|
-
[K in keyof $['#composition']]: $['#composition'][K]['many'] extends true ? ReplaceObj<$['#composition'][K]['bucket']>[] : ReplaceObj<$['#composition'][K]['bucket']>;
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
16
|
export type PatchObj<$ extends $Bucket> = DeepPartialNullable<$['#data']> & {
|
|
22
17
|
id: $['#data']['id'];
|
|
23
18
|
} & (string extends keyof $['#composition'] ? {} : keyof $['#composition'] extends never ? {} : {
|
|
@@ -4,6 +4,7 @@ import { NesoiObj } from "../../../../engine/data/obj";
|
|
|
4
4
|
import { AnyBucketAdapter } from '../adapters/bucket_adapter';
|
|
5
5
|
import { $BucketView } from '../view/bucket_view.schema';
|
|
6
6
|
import { NQL_AnyQuery, NQL_Pagination } from '../query/nql.schema';
|
|
7
|
+
import { NQL_Result } from '../query/nql_engine';
|
|
7
8
|
export type BucketCacheSync<T> = {
|
|
8
9
|
obj: T;
|
|
9
10
|
updateEpoch: number;
|
|
@@ -23,10 +24,13 @@ export declare class BucketCache<Obj extends NesoiObj> {
|
|
|
23
24
|
private lastSyncEpoch?;
|
|
24
25
|
private lastHash?;
|
|
25
26
|
private innerAdapter;
|
|
26
|
-
constructor(bucketName: string, outerAdapter: AnyBucketAdapter, config: NonNullable<BucketConfig<any, any>['cache']>);
|
|
27
|
+
constructor(bucketName: string, outerAdapter: AnyBucketAdapter, config: NonNullable<BucketConfig<any, any, any>['cache']>);
|
|
27
28
|
get(trx: AnyTrxNode, id: NesoiObj['id']): Promise<any>;
|
|
28
29
|
index(trx: AnyTrxNode): Promise<any[]>;
|
|
29
|
-
query(trx: AnyTrxNode, view: $BucketView, query: NQL_AnyQuery, pagination?: NQL_Pagination): Promise<any[]
|
|
30
|
+
query(trx: AnyTrxNode, view: $BucketView, query: NQL_AnyQuery, pagination?: NQL_Pagination): Promise<NQL_Result<any[] | {
|
|
31
|
+
[x: string]: any;
|
|
32
|
+
id: any;
|
|
33
|
+
}[]> | Obj[]>;
|
|
30
34
|
private syncOne;
|
|
31
35
|
private syncOneAndPast;
|
|
32
36
|
private syncAll;
|
|
@@ -69,7 +69,7 @@ class BucketCache {
|
|
|
69
69
|
const obj = await this.outerAdapter.get(trx, id);
|
|
70
70
|
if (obj) {
|
|
71
71
|
const entry = new BucketCacheEntry(obj.id, obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch);
|
|
72
|
-
await this.innerAdapter.
|
|
72
|
+
await this.innerAdapter.create(trx, entry);
|
|
73
73
|
return { action: 'update', sync: entry };
|
|
74
74
|
}
|
|
75
75
|
return { action: 'keep' };
|
|
@@ -93,7 +93,7 @@ class BucketCache {
|
|
|
93
93
|
if (!localObj) {
|
|
94
94
|
const obj = await this.outerAdapter.get(trx, id);
|
|
95
95
|
if (obj) {
|
|
96
|
-
await this.innerAdapter.
|
|
96
|
+
await this.innerAdapter.create(trx, obj);
|
|
97
97
|
return { action: 'update', sync: {
|
|
98
98
|
obj,
|
|
99
99
|
updateEpoch: this.outerAdapter.getUpdateEpoch(obj)
|
|
@@ -132,26 +132,26 @@ class BucketCache {
|
|
|
132
132
|
}
|
|
133
133
|
async syncQuery(trx, view, query, pagination) {
|
|
134
134
|
// 1. Query id and epoch from outer adapter
|
|
135
|
-
const outerMetadata = await this.outerAdapter.query(trx, query, pagination, {
|
|
135
|
+
const outerMetadata = await this.outerAdapter.query(trx, query, pagination, undefined, {
|
|
136
136
|
metadataOnly: true
|
|
137
137
|
});
|
|
138
|
-
if (!outerMetadata.length) {
|
|
138
|
+
if (!outerMetadata.data.length) {
|
|
139
139
|
return { action: 'keep', sync: [] };
|
|
140
140
|
}
|
|
141
141
|
// 2. Read ids from the inner adapter
|
|
142
142
|
const innerData = await this.innerAdapter.query(trx, {
|
|
143
|
-
'id in': outerMetadata.map(obj => obj.id)
|
|
143
|
+
'id in': outerMetadata.data.map(obj => obj.id)
|
|
144
144
|
});
|
|
145
145
|
// 3. Filter modified query results
|
|
146
146
|
const outerEpoch = {};
|
|
147
|
-
for (const i in outerMetadata) {
|
|
148
|
-
const obj = outerMetadata[i];
|
|
147
|
+
for (const i in outerMetadata.data) {
|
|
148
|
+
const obj = outerMetadata.data[i];
|
|
149
149
|
outerEpoch[obj.id] = this.outerAdapter.getUpdateEpoch(obj);
|
|
150
150
|
}
|
|
151
151
|
const queryResults = {};
|
|
152
152
|
const modifiedIds = [];
|
|
153
|
-
for (const i in innerData) {
|
|
154
|
-
const obj = innerData[i];
|
|
153
|
+
for (const i in innerData.data) {
|
|
154
|
+
const obj = innerData.data[i];
|
|
155
155
|
const epoch = outerEpoch[obj.id];
|
|
156
156
|
if (!epoch || epoch > obj.updateEpoch) {
|
|
157
157
|
modifiedIds.push(obj.id);
|
|
@@ -162,14 +162,14 @@ class BucketCache {
|
|
|
162
162
|
}
|
|
163
163
|
// 4. Nothing changed, return current data
|
|
164
164
|
if (!modifiedIds.length) {
|
|
165
|
-
return { action: 'keep', sync: innerData };
|
|
165
|
+
return { action: 'keep', sync: innerData.data };
|
|
166
166
|
}
|
|
167
167
|
// 5. Query modified objects to outer adapter and merge them on results
|
|
168
168
|
const outerData = await this.outerAdapter.query(trx, {
|
|
169
169
|
'id in': modifiedIds
|
|
170
170
|
});
|
|
171
|
-
for (const i in outerData) {
|
|
172
|
-
const obj = outerData[i];
|
|
171
|
+
for (const i in outerData.data) {
|
|
172
|
+
const obj = outerData.data[i];
|
|
173
173
|
const updateEpoch = this.outerAdapter.getUpdateEpoch(obj);
|
|
174
174
|
queryResults[obj.id] = {
|
|
175
175
|
obj,
|
|
@@ -7,10 +7,37 @@ export declare class BucketGraph<M extends $Module, $ extends $Bucket> {
|
|
|
7
7
|
private bucketName;
|
|
8
8
|
private schema;
|
|
9
9
|
constructor(bucket: Bucket<M, $>);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Read the data from a link
|
|
12
|
+
*
|
|
13
|
+
* - Options
|
|
14
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
15
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
16
|
+
*/
|
|
17
|
+
readLink<LinkName extends keyof $['graph']['links'], LinkBucketName extends $['graph']['links'][LinkName]['bucket']['refName'], LinkBucket extends M['buckets'][LinkBucketName], Obj = LinkBucket['#data']>(trx: AnyTrxNode, obj: $['#data'], link: LinkName, options?: {
|
|
18
|
+
silent?: boolean;
|
|
19
|
+
no_tenancy?: boolean;
|
|
20
|
+
}): Promise<Obj | Obj[] | undefined>;
|
|
21
|
+
/**
|
|
22
|
+
* Read the data from a link and build it with a given view
|
|
23
|
+
*
|
|
24
|
+
* - Options
|
|
25
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
26
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
27
|
+
*/
|
|
28
|
+
viewLink<LinkName extends keyof $['graph']['links'], LinkBucketName extends $['graph']['links'][LinkName]['bucket']['refName'], LinkBucket extends M['buckets'][LinkBucketName], V extends ViewName<LinkBucket>, Obj extends ViewObj<LinkBucket, V>>(trx: AnyTrxNode, obj: $['#data'], link: LinkName, view: V, options?: {
|
|
29
|
+
silent?: boolean;
|
|
30
|
+
no_tenancy?: boolean;
|
|
31
|
+
}): Promise<Obj | Obj[] | undefined>;
|
|
32
|
+
/**
|
|
33
|
+
* Return true if the link resolves to at least one object
|
|
34
|
+
*
|
|
35
|
+
* - Options
|
|
36
|
+
* - `silent`: If not found, returns undefined instead of raising an exception
|
|
37
|
+
* - `no_tenancy`: Don't apply tenancy rules
|
|
38
|
+
*/
|
|
39
|
+
hasLink<LinkName extends keyof $['graph']['links']>(trx: AnyTrxNode, link: LinkName, obj: $['#data'], options?: {
|
|
40
|
+
no_tenancy?: boolean;
|
|
41
|
+
}): Promise<boolean>;
|
|
15
42
|
}
|
|
16
43
|
export type AnyBucket = Bucket<any, any>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BucketGraph = void 0;
|
|
4
|
+
const trx_node_1 = require("../../../../engine/transaction/trx_node");
|
|
4
5
|
const log_1 = require("../../../../engine/util/log");
|
|
5
|
-
const tree_1 = require("../../../../engine/data/tree");
|
|
6
6
|
const error_1 = require("../../../../engine/data/error");
|
|
7
7
|
class BucketGraph {
|
|
8
8
|
constructor(bucket) {
|
|
@@ -10,127 +10,96 @@ class BucketGraph {
|
|
|
10
10
|
this.bucketName = bucket.schema.name;
|
|
11
11
|
this.schema = bucket.schema.graph;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
async readLink(trx, link, obj, view = 'default', index = []) {
|
|
13
|
+
/**
|
|
14
|
+
* Read the data from a link
|
|
15
|
+
*
|
|
16
|
+
* - Options
|
|
17
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
18
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
19
|
+
*/
|
|
20
|
+
async readLink(trx, obj, link, options) {
|
|
21
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
24
22
|
const schema = this.schema.links[link];
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
// Make tenancy query
|
|
24
|
+
const tenancy = (options?.no_tenancy)
|
|
25
|
+
? undefined
|
|
26
|
+
: this.bucket.getTenancyQuery(trx);
|
|
27
|
+
// Query
|
|
28
|
+
const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
|
|
29
|
+
const links = await otherBucket.adapter.query(trx, {
|
|
30
|
+
...schema.query,
|
|
31
|
+
'#and': tenancy
|
|
32
|
+
}, {
|
|
33
|
+
perPage: schema.many ? undefined : 1,
|
|
34
|
+
}, obj);
|
|
35
|
+
// Empty response
|
|
36
|
+
if (!schema.many && !schema.optional && !links.data.length) {
|
|
37
|
+
// silent = undefined
|
|
38
|
+
if (options?.silent)
|
|
39
|
+
return;
|
|
40
|
+
// non-silent = exception
|
|
37
41
|
else {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
else {
|
|
44
|
-
if (Array.isArray(selfValue)) {
|
|
45
|
-
throw error_1.NesoiError.Bucket.Graph.LinkOneWithArrayValue(schema.name);
|
|
42
|
+
throw error_1.NesoiError.Bucket.Graph.RequiredLinkNotFound({
|
|
43
|
+
bucket: this.bucketName,
|
|
44
|
+
link: link,
|
|
45
|
+
id: obj.id
|
|
46
|
+
});
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
? await this.readManyLink(trx, schema, selfValue, view)
|
|
51
|
-
: await this.readOneLink(trx, schema, selfValue, view);
|
|
52
|
-
if (!schema.many && !schema.optional && !links) {
|
|
53
|
-
throw error_1.NesoiError.Bucket.Graph.RequiredLinkNotFound(schema.name, selfValue);
|
|
54
|
-
}
|
|
55
|
-
return links;
|
|
56
|
-
}
|
|
57
|
-
async readOneLink(trx, link, selfValue, view) {
|
|
58
|
-
const linkBucket = trx.bucket(link.bucket.refName);
|
|
59
|
-
if (link.keyOwner === 'self' || link.keyOwner === 'other') {
|
|
60
|
-
const q = linkBucket.query({
|
|
61
|
-
[link.otherKey]: selfValue
|
|
62
|
-
}, view);
|
|
63
|
-
if (link.query) {
|
|
64
|
-
q.merge(link.query);
|
|
65
|
-
}
|
|
66
|
-
return q.first();
|
|
49
|
+
if (schema.many) {
|
|
50
|
+
return links.data;
|
|
67
51
|
}
|
|
68
|
-
else
|
|
69
|
-
|
|
70
|
-
const pivotSelfKey = this.bucket.schema.name + '_id';
|
|
71
|
-
const pivotOtherKey = link.bucket + '_id';
|
|
72
|
-
const pivotObj = await linkBucket.query({
|
|
73
|
-
[pivotSelfKey]: selfValue
|
|
74
|
-
}, view).first();
|
|
75
|
-
const pivotValue = pivotObj[pivotOtherKey];
|
|
76
|
-
if (pivotValue === undefined || pivotValue === null) {
|
|
77
|
-
throw error_1.NesoiError.Bucket.Graph.PivotValueIsUndefined(link.name);
|
|
78
|
-
}
|
|
79
|
-
const q = linkBucket.query({
|
|
80
|
-
[link.otherKey]: pivotValue
|
|
81
|
-
}, view);
|
|
82
|
-
if (link.query) {
|
|
83
|
-
q.merge(link.query);
|
|
84
|
-
}
|
|
85
|
-
return q.first();
|
|
52
|
+
else {
|
|
53
|
+
return links.data[0];
|
|
86
54
|
}
|
|
87
55
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Read the data from a link and build it with a given view
|
|
58
|
+
*
|
|
59
|
+
* - Options
|
|
60
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
61
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
62
|
+
*/
|
|
63
|
+
async viewLink(trx, obj, link, view, options) {
|
|
64
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
65
|
+
const schema = this.schema.links[link];
|
|
66
|
+
const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
|
|
67
|
+
const links = await this.readLink(trx, obj, link, options);
|
|
68
|
+
if (!links)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (Array.isArray(links)) {
|
|
71
|
+
const output = [];
|
|
72
|
+
for (const link of links) {
|
|
73
|
+
output.push(await otherBucket.buildOne(trx, link, view));
|
|
105
74
|
}
|
|
106
|
-
return
|
|
75
|
+
return output;
|
|
107
76
|
}
|
|
108
|
-
else
|
|
109
|
-
|
|
110
|
-
const pivotSelfKey = this.bucket.schema.name + '_id';
|
|
111
|
-
const pivotOtherKey = link.bucket + '_id';
|
|
112
|
-
const q = pivotBucket.query({
|
|
113
|
-
[pivotSelfKey]: selfValue
|
|
114
|
-
}, view);
|
|
115
|
-
if (link.query) {
|
|
116
|
-
q.merge(link.query);
|
|
117
|
-
}
|
|
118
|
-
const pivotObjs = await q.all();
|
|
119
|
-
const pivotValues = pivotObjs.map(obj => obj[pivotOtherKey]);
|
|
120
|
-
if (!pivotValues.length) {
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
return linkBucket.query({
|
|
124
|
-
[`${link.otherKey} in`]: pivotValues
|
|
125
|
-
}, view);
|
|
77
|
+
else {
|
|
78
|
+
return await otherBucket.buildOne(trx, links, view);
|
|
126
79
|
}
|
|
127
80
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Return true if the link resolves to at least one object
|
|
83
|
+
*
|
|
84
|
+
* - Options
|
|
85
|
+
* - `silent`: If not found, returns undefined instead of raising an exception
|
|
86
|
+
* - `no_tenancy`: Don't apply tenancy rules
|
|
87
|
+
*/
|
|
88
|
+
async hasLink(trx, link, obj, options) {
|
|
89
|
+
log_1.Log.trace('bucket', this.bucketName, `Has link ${link}`);
|
|
90
|
+
const schema = this.schema.links[link];
|
|
91
|
+
// Make tenancy query
|
|
92
|
+
const tenancy = (options?.no_tenancy)
|
|
93
|
+
? undefined
|
|
94
|
+
: this.bucket.getTenancyQuery(trx);
|
|
95
|
+
// Query
|
|
96
|
+
const links = await this.bucket.adapter.query(trx, {
|
|
97
|
+
...schema.query,
|
|
98
|
+
'#and': tenancy
|
|
99
|
+
}, {
|
|
100
|
+
perPage: 1,
|
|
101
|
+
}, obj);
|
|
102
|
+
return !!links.data.length;
|
|
134
103
|
}
|
|
135
104
|
}
|
|
136
105
|
exports.BucketGraph = BucketGraph;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $Dependency } from "../../../../engine/dependency";
|
|
2
2
|
import { $Bucket } from '../bucket.schema';
|
|
3
|
-
import {
|
|
3
|
+
import { NQL_AnyQuery } from '../query/nql.schema';
|
|
4
4
|
export declare class $BucketGraphLink {
|
|
5
5
|
name: string;
|
|
6
6
|
alias: string;
|
|
@@ -9,14 +9,11 @@ export declare class $BucketGraphLink {
|
|
|
9
9
|
many: boolean;
|
|
10
10
|
optional: boolean;
|
|
11
11
|
keyOwner: 'self' | 'other' | 'pivot';
|
|
12
|
-
|
|
13
|
-
otherKey: string;
|
|
14
|
-
pivotBucket?: string | undefined;
|
|
15
|
-
query?: AnyQuery<any, any> | undefined;
|
|
12
|
+
query: NQL_AnyQuery;
|
|
16
13
|
$t: string;
|
|
17
14
|
'#bucket': $Bucket;
|
|
18
15
|
'#many': boolean;
|
|
19
|
-
constructor(name: string, alias: string, bucket: $Dependency, rel: 'aggregation' | 'composition', many: boolean, optional: boolean, keyOwner: 'self' | 'other' | 'pivot',
|
|
16
|
+
constructor(name: string, alias: string, bucket: $Dependency, rel: 'aggregation' | 'composition', many: boolean, optional: boolean, keyOwner: 'self' | 'other' | 'pivot', query: NQL_AnyQuery);
|
|
20
17
|
}
|
|
21
18
|
export type $BucketGraphLinks = {
|
|
22
19
|
[x: string]: $BucketGraphLink;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.$BucketGraph = exports.$BucketGraphLink = void 0;
|
|
4
4
|
class $BucketGraphLink {
|
|
5
|
-
constructor(name, alias, bucket, rel, many, optional, keyOwner,
|
|
5
|
+
constructor(name, alias, bucket, rel, many, optional, keyOwner, query) {
|
|
6
6
|
this.name = name;
|
|
7
7
|
this.alias = alias;
|
|
8
8
|
this.bucket = bucket;
|
|
@@ -10,9 +10,6 @@ class $BucketGraphLink {
|
|
|
10
10
|
this.many = many;
|
|
11
11
|
this.optional = optional;
|
|
12
12
|
this.keyOwner = keyOwner;
|
|
13
|
-
this.selfKey = selfKey;
|
|
14
|
-
this.otherKey = otherKey;
|
|
15
|
-
this.pivotBucket = pivotBucket;
|
|
16
13
|
this.query = query;
|
|
17
14
|
this.$t = 'bucket.graph.link';
|
|
18
15
|
}
|
|
@@ -3,7 +3,7 @@ import { $BucketGraphLink } from './bucket_graph.schema';
|
|
|
3
3
|
import { BucketBuilderNode } from '../bucket.builder';
|
|
4
4
|
import { $Dependency } from "../../../../engine/dependency";
|
|
5
5
|
import { $Bucket } from '../bucket.schema';
|
|
6
|
-
import { NQL_Query } from '../query/nql.schema';
|
|
6
|
+
import { NQL_AnyQuery, NQL_Query } from '../query/nql.schema';
|
|
7
7
|
export declare class BucketGraphLinkFactory<Module extends $Module, SelfBucket extends $Bucket, Fieldpaths = NoInfer<SelfBucket['#fieldpath']>> {
|
|
8
8
|
private module;
|
|
9
9
|
private alias?;
|
|
@@ -20,16 +20,12 @@ export declare class BucketGraphLinkBuilder<Module extends $Module, SelfBucket e
|
|
|
20
20
|
private query;
|
|
21
21
|
private many;
|
|
22
22
|
private alias?;
|
|
23
|
-
private keyOwner;
|
|
24
|
-
private pivotBucket?;
|
|
25
|
-
private selfKey?;
|
|
26
|
-
private otherKey?;
|
|
27
|
-
private _query?;
|
|
28
23
|
private _optional;
|
|
29
|
-
constructor(bucket: $Dependency, rel: 'aggregation' | 'composition', query:
|
|
24
|
+
constructor(bucket: $Dependency, rel: 'aggregation' | 'composition', query: NQL_AnyQuery, many: boolean, alias?: string | undefined);
|
|
30
25
|
as(alias: string): this;
|
|
31
26
|
get optional(): this;
|
|
32
27
|
static build(node: BucketBuilderNode, builder: BucketGraphLinkBuilder<any, any, any>, name: string): $BucketGraphLink;
|
|
28
|
+
static inferKeyOwner(query: NQL_AnyQuery): "self";
|
|
33
29
|
}
|
|
34
30
|
export type BucketGraphLinkBuilders = {
|
|
35
31
|
[x: string]: BucketGraphLinkBuilder<any, any, any>;
|
|
@@ -38,7 +38,6 @@ class BucketGraphLinkBuilder {
|
|
|
38
38
|
this.query = query;
|
|
39
39
|
this.many = many;
|
|
40
40
|
this.alias = alias;
|
|
41
|
-
this.keyOwner = 'self';
|
|
42
41
|
this._optional = false;
|
|
43
42
|
}
|
|
44
43
|
as(alias) {
|
|
@@ -50,7 +49,12 @@ class BucketGraphLinkBuilder {
|
|
|
50
49
|
return this;
|
|
51
50
|
}
|
|
52
51
|
static build(node, builder, name) {
|
|
53
|
-
return new bucket_graph_schema_1.$BucketGraphLink(name, builder.alias || name, builder.bucket, builder.rel, builder.many, builder._optional,
|
|
52
|
+
return new bucket_graph_schema_1.$BucketGraphLink(name, builder.alias || name, builder.bucket, builder.rel, builder.many, builder._optional, this.inferKeyOwner(builder.query), builder.query);
|
|
53
|
+
}
|
|
54
|
+
static inferKeyOwner(query) {
|
|
55
|
+
const keyOwner = 'self';
|
|
56
|
+
// TODO
|
|
57
|
+
return keyOwner;
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
exports.BucketGraphLinkBuilder = BucketGraphLinkBuilder;
|
|
@@ -18,7 +18,7 @@ class BucketModelBuilder {
|
|
|
18
18
|
// Build
|
|
19
19
|
static build(builder) {
|
|
20
20
|
const fields = bucket_model_field_builder_1.BucketModelFieldBuilder.buildChildren(builder.module, builder.builders);
|
|
21
|
-
return new bucket_model_schema_1.$BucketModel(fields.schema, fields.defaults);
|
|
21
|
+
return new bucket_model_schema_1.$BucketModel(fields.schema, fields.defaults, fields.hasFileField, fields.hasEncryptedField);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
exports.BucketModelBuilder = BucketModelBuilder;
|
|
@@ -37,9 +37,9 @@ function convertToMessage(module, model, name, alias, include = [], exclude = []
|
|
|
37
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
msgFields[f] = new message_template_schema_1.$MessageTemplateField(field.type, field.name, field.alias, path, field.array, field.required, undefined, false, [], {
|
|
40
|
-
enum: field.
|
|
41
|
-
options: field.
|
|
42
|
-
dep: field.
|
|
40
|
+
enum: field.meta?.enum ? {
|
|
41
|
+
options: field.meta.enum.options,
|
|
42
|
+
dep: field.meta.enum.dep ? new dependency_1.$Dependency(module, 'constants', `${field.meta.enum.dep.module}::${field.meta.enum.dep.name}`) : undefined
|
|
43
43
|
} : undefined
|
|
44
44
|
}, field.children ? convertFields(field.children, include, exclude) : undefined);
|
|
45
45
|
}
|
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
import { $Dependency } from "../../../../engine/dependency";
|
|
2
2
|
export type $BucketModelFieldType = 'boolean' | 'date' | 'datetime' | 'decimal' | 'enum' | 'file' | 'float' | 'int' | 'string' | 'obj' | 'unknown' | 'dict';
|
|
3
|
+
export type $BucketModelFieldCrypto = {
|
|
4
|
+
algorithm: string;
|
|
5
|
+
key: string;
|
|
6
|
+
};
|
|
3
7
|
export declare class $BucketModelField {
|
|
4
8
|
name: string;
|
|
9
|
+
path: string;
|
|
5
10
|
type: $BucketModelFieldType;
|
|
6
11
|
alias: string;
|
|
7
12
|
array: boolean;
|
|
8
13
|
required: boolean;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
meta?: {
|
|
15
|
+
enum?: {
|
|
16
|
+
options: string | string[];
|
|
17
|
+
dep?: $Dependency;
|
|
18
|
+
};
|
|
19
|
+
decimal?: {
|
|
20
|
+
left?: number;
|
|
21
|
+
right?: number;
|
|
22
|
+
};
|
|
23
|
+
file?: {
|
|
24
|
+
extnames?: string[];
|
|
25
|
+
maxsize?: number;
|
|
26
|
+
};
|
|
12
27
|
} | undefined;
|
|
13
28
|
defaultValue?: any | undefined;
|
|
14
29
|
children?: $BucketModelFields | undefined;
|
|
15
30
|
or?: $BucketModelField | undefined;
|
|
31
|
+
crypto?: $BucketModelFieldCrypto | undefined;
|
|
16
32
|
$t: string;
|
|
17
|
-
constructor(name: string, type: $BucketModelFieldType, alias: string, array: boolean, required: boolean,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
33
|
+
constructor(name: string, path: string, type: $BucketModelFieldType, alias: string, array: boolean, required: boolean, meta?: {
|
|
34
|
+
enum?: {
|
|
35
|
+
options: string | string[];
|
|
36
|
+
dep?: $Dependency;
|
|
37
|
+
};
|
|
38
|
+
decimal?: {
|
|
39
|
+
left?: number;
|
|
40
|
+
right?: number;
|
|
41
|
+
};
|
|
42
|
+
file?: {
|
|
43
|
+
extnames?: string[];
|
|
44
|
+
maxsize?: number;
|
|
45
|
+
};
|
|
46
|
+
} | undefined, defaultValue?: any | undefined, children?: $BucketModelFields | undefined, or?: $BucketModelField | undefined, crypto?: $BucketModelFieldCrypto | undefined);
|
|
21
47
|
}
|
|
22
48
|
export type $BucketModelFields = {
|
|
23
49
|
[x: string]: $BucketModelField;
|
|
@@ -27,9 +53,12 @@ export declare class $BucketModel {
|
|
|
27
53
|
id: $BucketModelField;
|
|
28
54
|
};
|
|
29
55
|
defaults: Record<string, any>;
|
|
56
|
+
hasFileField: boolean;
|
|
57
|
+
hasEncryptedField: boolean;
|
|
30
58
|
$t: string;
|
|
31
59
|
constructor(fields: $BucketModelFields & {
|
|
32
60
|
id: $BucketModelField;
|
|
33
|
-
}, defaults?: Record<string, any
|
|
61
|
+
}, defaults?: Record<string, any>, hasFileField?: boolean, hasEncryptedField?: boolean);
|
|
34
62
|
static get(model: $BucketModel, fieldpath: string): $BucketModelField | undefined;
|
|
63
|
+
static fieldsOfType(model: $BucketModel, type: $BucketModelFieldType): $BucketModelField[];
|
|
35
64
|
}
|