nesoi 3.4.2 → 3.4.4

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.
Files changed (37) hide show
  1. package/lib/elements/blocks/job/internal/resource_job.schema.d.ts +1 -0
  2. package/lib/elements/blocks/resource/resource.builder.js +2 -2
  3. package/lib/elements/blocks/resource/resource_query.builder.d.ts +3 -0
  4. package/lib/elements/blocks/resource/resource_query.builder.js +7 -1
  5. package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +5 -3
  6. package/lib/elements/entities/bucket/adapters/bucket_adapter.js +3 -3
  7. package/lib/elements/entities/bucket/adapters/memory.bucket_adapter.d.ts +2 -2
  8. package/lib/elements/entities/bucket/adapters/memory.bucket_adapter.js +5 -5
  9. package/lib/elements/entities/bucket/adapters/memory.nql.d.ts +3 -1
  10. package/lib/elements/entities/bucket/adapters/memory.nql.js +14 -5
  11. package/lib/elements/entities/bucket/adapters/rest.nql.d.ts +1 -1
  12. package/lib/elements/entities/bucket/adapters/rest.nql.js +1 -1
  13. package/lib/elements/entities/bucket/bucket.d.ts +12 -0
  14. package/lib/elements/entities/bucket/bucket.js +23 -4
  15. package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +4 -2
  16. package/lib/elements/entities/bucket/cache/bucket_cache.js +7 -3
  17. package/lib/elements/entities/bucket/graph/bucket_graph.d.ts +10 -1
  18. package/lib/elements/entities/bucket/graph/bucket_graph.js +50 -4
  19. package/lib/elements/entities/bucket/model/bucket_model.d.ts +8 -2
  20. package/lib/elements/entities/bucket/model/bucket_model.js +287 -275
  21. package/lib/elements/entities/bucket/query/nql_engine.d.ts +2 -2
  22. package/lib/elements/entities/bucket/query/nql_engine.js +2 -2
  23. package/lib/elements/entities/bucket/view/bucket_view.js +48 -9
  24. package/lib/elements/entities/message/template/message_template_parser.js +3 -3
  25. package/lib/engine/data/error.d.ts +4 -0
  26. package/lib/engine/data/error.js +4 -0
  27. package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +5 -1
  28. package/lib/engine/transaction/nodes/bucket.trx_node.js +8 -0
  29. package/lib/engine/transaction/nodes/bucket_query.trx_node.d.ts +4 -0
  30. package/lib/engine/transaction/nodes/bucket_query.trx_node.js +22 -0
  31. package/lib/engine/transaction/trx_engine.d.ts +2 -2
  32. package/lib/engine/transaction/trx_engine.js +14 -13
  33. package/lib/engine/util/parse.d.ts +0 -7
  34. package/package.json +1 -1
  35. package/tools/joaquin/bucket.d.ts +4 -0
  36. package/tools/joaquin/bucket.js +13 -0
  37. package/tsconfig.build.tsbuildinfo +1 -1
@@ -25,5 +25,6 @@ export type $ResourceQueryRoutes = {
25
25
  view: string;
26
26
  auth: $BlockAuth[];
27
27
  query?: NQL_AnyQuery;
28
+ serialize: boolean;
28
29
  };
29
30
  };
@@ -68,7 +68,7 @@ class ResourceBuilder extends block_builder_1.BlockBuilder {
68
68
  meta = resource_query_builder_1.ResourceQueryRouteBuilder.build(meta_builder);
69
69
  }
70
70
  if (this._routes) {
71
- this._routes[view] = meta || { view, auth: [] };
71
+ this._routes[view] = meta || { view, auth: [], serialize: true };
72
72
  return this;
73
73
  }
74
74
  const jobBuilder = new resource_job_builder_1.ResourceJobBuilder(this.module, name, this._bucket.tag.short, 'query', alias, resource_1.Resource.query, [...this._auth])
@@ -88,7 +88,7 @@ class ResourceBuilder extends block_builder_1.BlockBuilder {
88
88
  }));
89
89
  this._jobs.query = new dependency_1.Dependency(this.module, new dependency_1.Tag(this.module, 'job', name), { runtime: true });
90
90
  this._routes = jobBuilder._routes;
91
- this._routes[view] = meta || { view, auth: [] };
91
+ this._routes[view] = meta || { view, auth: [], serialize: true };
92
92
  return this;
93
93
  }
94
94
  /* Create/Update/Delete */
@@ -5,14 +5,17 @@ export declare class ResourceQueryRouteBuilder<Space extends $Space, Module exte
5
5
  protected _view: string;
6
6
  protected _auth: $BlockAuth[];
7
7
  protected _query?: NQL_AnyQuery;
8
+ protected _serialize: boolean;
8
9
  constructor(_view: string);
9
10
  auth<U extends keyof Space['authnUsers']>(provider: U, resolver?: (user: Space['authnUsers'][U]) => boolean): this;
10
11
  view<ViewName extends keyof Bucket['views'] & string>(view: ViewName): this;
11
12
  query(query: NQL_Query<Module, Bucket>): this;
13
+ serialize(value?: boolean): this;
12
14
  static build(builder: ResourceQueryRouteBuilder<any, any, any>): {
13
15
  view: string;
14
16
  auth: $BlockAuth[];
15
17
  query?: NQL_AnyQuery;
18
+ serialize: boolean;
16
19
  };
17
20
  }
18
21
  export type ResourceQueryRouteDef<Space extends $Space, Module extends $Module, Bucket extends $Bucket> = (builder: ResourceQueryRouteBuilder<Space, Module, Bucket>) => ResourceQueryRouteBuilder<Space, Module, Bucket>;
@@ -5,6 +5,7 @@ class ResourceQueryRouteBuilder {
5
5
  _view;
6
6
  _auth = [];
7
7
  _query;
8
+ _serialize = true;
8
9
  constructor(_view) {
9
10
  this._view = _view;
10
11
  }
@@ -29,11 +30,16 @@ class ResourceQueryRouteBuilder {
29
30
  this._query = query;
30
31
  return this;
31
32
  }
33
+ serialize(value) {
34
+ this._serialize = !!value;
35
+ return this;
36
+ }
32
37
  static build(builder) {
33
38
  const meta = {
34
39
  view: builder._view,
35
40
  auth: builder._auth,
36
- query: builder._query
41
+ query: builder._query,
42
+ serialize: builder._serialize,
37
43
  };
38
44
  return meta;
39
45
  }
@@ -137,13 +137,14 @@ export declare abstract class BucketAdapter<Obj extends NesoiObj, Config extends
137
137
  /**
138
138
  * Return the results of a query
139
139
  * - `pagination`: Limits the number of results.
140
- * - `perPage`: If 0, returns no results (useful with config.metadataOnly). If -1, returns all results.
140
+ * - `perPage`: If 0, returns no results (useful with config.metadata_only). If -1, returns all results.
141
141
  * - `params`: Objects to be used when filling param values. The query returns objects matching *any* of the param objects.
142
142
  * - `param_templates`: Path parameter replacements to be used when filling param_with_$ values. The query returns objects matching *any* of the param objects.
143
143
  */
144
144
  query<MetadataOnly extends boolean>(trx: AnyTrxNode, query: NQL_AnyQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
145
145
  view?: string;
146
- metadataOnly?: MetadataOnly;
146
+ metadata_only?: MetadataOnly;
147
+ serialize?: boolean;
147
148
  }, custom?: {
148
149
  module?: string;
149
150
  buckets?: Record<string, {
@@ -163,7 +164,8 @@ export declare abstract class BucketAdapter<Obj extends NesoiObj, Config extends
163
164
  }): Promise<NQL_CompiledQuery>;
164
165
  _queryCompiled<MetadataOnly extends boolean>(trx: AnyTrxNode, compiled: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
165
166
  view?: string;
166
- metadataOnly?: MetadataOnly;
167
+ metadata_only?: MetadataOnly;
168
+ serialize?: boolean;
167
169
  }, custom?: {
168
170
  module?: string;
169
171
  buckets?: Record<string, {
@@ -29,7 +29,7 @@ class BucketAdapter {
29
29
  /**
30
30
  * Return the results of a query
31
31
  * - `pagination`: Limits the number of results.
32
- * - `perPage`: If 0, returns no results (useful with config.metadataOnly). If -1, returns all results.
32
+ * - `perPage`: If 0, returns no results (useful with config.metadata_only). If -1, returns all results.
33
33
  * - `params`: Objects to be used when filling param values. The query returns objects matching *any* of the param objects.
34
34
  * - `param_templates`: Path parameter replacements to be used when filling param_with_$ values. The query returns objects matching *any* of the param objects.
35
35
  */
@@ -59,8 +59,8 @@ class BucketAdapter {
59
59
  ...trx_node_1.TrxNode.getCacheCustomBuckets(trx)
60
60
  };
61
61
  const view = config?.view ? this.schema.views[config.view] : undefined;
62
- const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view, customBuckets);
63
- if (config?.metadataOnly) {
62
+ const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view, customBuckets, config?.serialize);
63
+ if (config?.metadata_only) {
64
64
  result.data = result.data.map(obj => ({
65
65
  id: obj.id,
66
66
  [this.config.meta.updated_at]: this.getUpdateEpoch(obj)
@@ -25,8 +25,8 @@ export declare class MemoryBucketAdapter<B extends $Bucket, Obj extends B['#data
25
25
  avgTime: number;
26
26
  };
27
27
  protected deleteEverything(trx: AnyTrxNode): Promise<void>;
28
- index(trx: AnyTrxNode): Promise<Obj[]>;
29
- get(trx: AnyTrxNode, id: Obj['id']): Promise<Obj | undefined>;
28
+ index(trx: AnyTrxNode, serialize?: boolean): Promise<Obj[]>;
29
+ get(trx: AnyTrxNode, id: Obj['id'], serialize?: boolean): Promise<Obj | undefined>;
30
30
  create(trx: AnyTrxNode, obj: ObjWithOptionalId<Obj>): Promise<Obj>;
31
31
  createMany(trx: AnyTrxNode, objs: ObjWithOptionalId<Obj>[]): Promise<Obj[]>;
32
32
  replace(trx: AnyTrxNode, obj: ObjWithOptionalId<Obj>): Promise<Obj>;
@@ -40,14 +40,14 @@ class MemoryBucketAdapter extends bucket_adapter_1.BucketAdapter {
40
40
  return Promise.resolve();
41
41
  }
42
42
  /* Read operations */
43
- index(trx) {
44
- const objs = Object.values(this.data).map(obj => this.model.copy(obj, 'load'));
43
+ index(trx, serialize) {
44
+ const objs = Object.values(this.data).map(obj => this.model.copy(obj, 'load', () => !!serialize));
45
45
  return Promise.resolve(objs);
46
46
  }
47
- get(trx, id) {
47
+ get(trx, id, serialize) {
48
48
  if (!(id in this.data))
49
49
  return Promise.resolve(undefined);
50
- const output = this.model.copy(this.data[id], 'load');
50
+ const output = this.model.copy(this.data[id], 'load', () => !!serialize);
51
51
  return Promise.resolve(output);
52
52
  }
53
53
  /* Write Operations */
@@ -92,7 +92,7 @@ class MemoryBucketAdapter extends bucket_adapter_1.BucketAdapter {
92
92
  throw new Error(`Object with id ${obj.id} not found for patch`);
93
93
  }
94
94
  const data = this.data[obj.id];
95
- const input = this.model.copy(obj, 'save');
95
+ const input = this.model.copy(obj, 'save', undefined, Object.keys(obj));
96
96
  for (const key in input) {
97
97
  if (input[key] === null) {
98
98
  delete data[key];
@@ -2,15 +2,17 @@ import { NQLRunner } from '../query/nql_engine';
2
2
  import { AnyTrxNode } from "../../../../engine/transaction/trx_node";
3
3
  import { NQL_Pagination, NQL_Part } from '../query/nql.schema';
4
4
  import { AnyMemoryBucketAdapter } from './memory.bucket_adapter';
5
+ import { BucketModel } from '../model/bucket_model';
5
6
  type Obj = Record<string, any>;
6
7
  /**
7
8
  * @category NQL
8
9
  * */
9
10
  export declare class MemoryNQLRunner extends NQLRunner {
10
11
  protected adapter?: AnyMemoryBucketAdapter;
12
+ protected model?: BucketModel<any, any>;
11
13
  constructor();
12
14
  bind(adapter: AnyMemoryBucketAdapter): void;
13
- run(trx: AnyTrxNode, part: NQL_Part, params: Obj[], param_templates: Record<string, string>[], pagination?: NQL_Pagination): Promise<{
15
+ run(trx: AnyTrxNode, part: NQL_Part, params: Obj[], param_templates: Record<string, string>[], pagination?: NQL_Pagination, view?: any, serialize?: boolean): Promise<{
14
16
  data: any[];
15
17
  totalItems: number | undefined;
16
18
  page: number | undefined;
@@ -4,18 +4,21 @@ exports.MemoryNQLRunner = void 0;
4
4
  const nql_engine_1 = require("../query/nql_engine");
5
5
  const tree_1 = require("../../../../engine/data/tree");
6
6
  const datetime_1 = require("../../../../engine/data/datetime");
7
+ const bucket_model_1 = require("../model/bucket_model");
7
8
  /**
8
9
  * @category NQL
9
10
  * */
10
11
  class MemoryNQLRunner extends nql_engine_1.NQLRunner {
11
12
  adapter;
13
+ model;
12
14
  constructor() {
13
15
  super();
14
16
  }
15
17
  bind(adapter) {
16
18
  this.adapter = adapter;
19
+ this.model = new bucket_model_1.BucketModel(this.adapter.schema.model, this.adapter.config);
17
20
  }
18
- async run(trx, part, params, param_templates, pagination) {
21
+ async run(trx, part, params, param_templates, pagination, view, serialize) {
19
22
  if (!this.adapter) {
20
23
  throw new Error('No adapter bound to NQL Runner');
21
24
  }
@@ -27,7 +30,7 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
27
30
  }
28
31
  // Non-empty query
29
32
  else {
30
- response = await this.filter(part, data, params, param_templates);
33
+ response = await this.filter(part, data, params, param_templates, serialize);
31
34
  }
32
35
  let output = Object.values(response);
33
36
  if (part.union.sort?.length) {
@@ -129,7 +132,7 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
129
132
  * testing objects unnecessarily. Returns a dict of results by id.
130
133
  * @returns A dict of results by id
131
134
  */
132
- filter(part, objs, params, param_templates) {
135
+ filter(part, objs, params, param_templates, serialize) {
133
136
  // Accumulate results from n intersections,
134
137
  // avoiding a re-check of already matched objects.
135
138
  const _union = (union, objs, params, param_templates) => {
@@ -188,6 +191,9 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
188
191
  if (rule.select) {
189
192
  out[obj.id] = obj[rule.select];
190
193
  }
194
+ else if (serialize) {
195
+ out[obj.id] = this.model.copy(obj, 'load', () => true);
196
+ }
191
197
  else {
192
198
  out[obj.id] = obj;
193
199
  }
@@ -257,10 +263,13 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
257
263
  out[obj.id] = obj;
258
264
  }
259
265
  }
260
- if (rule.select) {
261
- for (const id in out) {
266
+ for (const id in out) {
267
+ if (rule.select) {
262
268
  out[id] = out[id][rule.select];
263
269
  }
270
+ else if (serialize) {
271
+ out[id] = this.model.copy(out[id], 'load', () => true);
272
+ }
264
273
  }
265
274
  return out;
266
275
  };
@@ -10,6 +10,6 @@ export declare class RESTNQLRunner extends NQLRunner {
10
10
  protected adapter?: AnyRESTBucketAdapter;
11
11
  constructor();
12
12
  bind(adapter: AnyRESTBucketAdapter): void;
13
- run(trx: AnyTrxNode, part: NQL_Part, params: Obj[], param_templates: Record<string, string>[], pagination?: NQL_Pagination): Promise<NQL_Result>;
13
+ run(trx: AnyTrxNode, part: NQL_Part, params: Obj[], param_templates: Record<string, string>[], pagination?: NQL_Pagination, view?: any, serialize?: boolean): Promise<NQL_Result>;
14
14
  }
15
15
  export {};
@@ -14,7 +14,7 @@ class RESTNQLRunner extends nql_engine_1.NQLRunner {
14
14
  bind(adapter) {
15
15
  this.adapter = adapter;
16
16
  }
17
- async run(trx, part, params, param_templates, pagination) {
17
+ async run(trx, part, params, param_templates, pagination, view, serialize) {
18
18
  if (!this.adapter) {
19
19
  throw new Error('No adapter bound to NQL Runner');
20
20
  }
@@ -108,6 +108,7 @@ export declare class Bucket<M extends $Module, $ extends $Bucket> {
108
108
  silent?: boolean;
109
109
  no_tenancy?: boolean;
110
110
  indexes?: string[][];
111
+ serialize?: boolean;
111
112
  }): Promise<Link['#many'] extends true ? Obj[] : (Obj | undefined)>;
112
113
  /**
113
114
  * Read the view of an entity of a graph link
@@ -130,6 +131,15 @@ export declare class Bucket<M extends $Module, $ extends $Bucket> {
130
131
  hasLink<LinkName extends keyof $['graph']['links']>(trx: AnyTrxNode, id: $['#data']['id'], link: LinkName, options?: {
131
132
  no_tenancy?: boolean;
132
133
  }): Promise<boolean | undefined>;
134
+ /**
135
+ * Return the number of objects matching a given link
136
+ *
137
+ * - Options:
138
+ * - `no_tenancy`: Don't apply tenancy rules.
139
+ */
140
+ countLink<LinkName extends keyof $['graph']['links']>(trx: AnyTrxNode, id: $['#data']['id'], link: LinkName, options?: {
141
+ no_tenancy?: boolean;
142
+ }): Promise<boolean | undefined>;
133
143
  /**
134
144
  * Build one object with a view
135
145
  */
@@ -208,9 +218,11 @@ export declare class Bucket<M extends $Module, $ extends $Bucket> {
208
218
  * - `params`: NQL parameters
209
219
  */
210
220
  query<V extends ViewName<$>, Obj extends ViewObj<$, V>>(trx: AnyTrxNode, query: NQL_AnyQuery, pagination?: NQL_Pagination, view?: V, options?: {
221
+ metadata_only?: boolean;
211
222
  no_tenancy?: boolean;
212
223
  params?: Record<string, any>[];
213
224
  param_templates?: Record<string, any>[];
225
+ serialize?: boolean;
214
226
  }): Promise<NQL_Result<Obj>>;
215
227
  /**
216
228
  * Add `created_by`, `created_at`, `updated_by` and `updated_at` fields to object
@@ -300,6 +300,22 @@ class Bucket {
300
300
  // Check Link
301
301
  return this.graph.hasLink(trx, link, obj, options);
302
302
  }
303
+ /**
304
+ * Return the number of objects matching a given link
305
+ *
306
+ * - Options:
307
+ * - `no_tenancy`: Don't apply tenancy rules.
308
+ */
309
+ async countLink(trx, id, link, options) {
310
+ log_1.Log.debug('bucket', this.schema.name, `Count Link, id=${id} l=${link}`);
311
+ // Read Object
312
+ const obj = await this.readOne(trx, id, options);
313
+ if (!obj) {
314
+ return undefined;
315
+ }
316
+ // Check Link
317
+ return this.graph.countLink(trx, link, obj, options);
318
+ }
303
319
  // Build
304
320
  /**
305
321
  * Build one object with a view
@@ -440,7 +456,7 @@ class Bucket {
440
456
  id: obj.id,
441
457
  '#and __tenancy__': tenancy
442
458
  }, { perPage: 1 }, undefined, undefined, {
443
- metadataOnly: true
459
+ metadata_only: true
444
460
  });
445
461
  oldObj = result.data[0];
446
462
  }
@@ -572,7 +588,7 @@ class Bucket {
572
588
  result = await this.adapter.query(trx, {
573
589
  id, '#and __tenancy__': tenancy
574
590
  }, { perPage: 1 }, undefined, undefined, {
575
- metadataOnly: true
591
+ metadata_only: true
576
592
  });
577
593
  if (!result.data.length && !options?.unsafe) {
578
594
  throw error_1.NesoiError.Bucket.ObjNotFound({ bucket: this.schema.alias, id });
@@ -654,7 +670,7 @@ class Bucket {
654
670
  'id in': ids,
655
671
  '#and __tenancy__': tenancy
656
672
  }, undefined, undefined, undefined, {
657
- metadataOnly: true
673
+ metadata_only: true
658
674
  });
659
675
  ids = result.data.map(obj => obj.id);
660
676
  }
@@ -729,7 +745,10 @@ class Bucket {
729
745
  }
730
746
  // Query
731
747
  const adapter = await trx_1.Trx.getCache(trx, this) || this.cache || this.adapter;
732
- const result = await adapter.query(trx, query, pagination, options?.params, options?.param_templates);
748
+ const result = await adapter.query(trx, query, pagination, options?.params, options?.param_templates, {
749
+ metadata_only: options?.metadata_only,
750
+ serialize: options?.serialize
751
+ });
733
752
  if (!result.data.length)
734
753
  return result;
735
754
  // Encryption
@@ -38,7 +38,8 @@ export declare class BucketCache<Obj extends NesoiObj> {
38
38
  }[]>;
39
39
  query<MetadataOnly extends boolean>(trx: AnyTrxNode, query: NQL_AnyQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
40
40
  view?: string;
41
- metadataOnly?: MetadataOnly;
41
+ metadata_only?: MetadataOnly;
42
+ serialize?: boolean;
42
43
  }): Promise<NQL_Result<MetadataOnly extends true ? {
43
44
  id: Obj['id'];
44
45
  [x: string]: any;
@@ -52,7 +53,8 @@ export declare class BucketCache<Obj extends NesoiObj> {
52
53
  }): Promise<NQL_CompiledQuery>;
53
54
  _queryCompiled<MetadataOnly extends boolean>(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
54
55
  view?: string;
55
- metadataOnly?: MetadataOnly;
56
+ metadata_only?: MetadataOnly;
57
+ serialize?: boolean;
56
58
  }): Promise<NQL_Result<MetadataOnly extends true ? {
57
59
  id: Obj['id'];
58
60
  [x: string]: any;
@@ -142,7 +142,9 @@ class BucketCache {
142
142
  else if (mode === 'all') {
143
143
  const { action, sync } = await this.syncAll(trx);
144
144
  log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.all, ${action}`);
145
- const entries = (await this.innerAdapter._queryCompiled(trx, query, pagination, params, undefined, undefined, {
145
+ const entries = (await this.innerAdapter._queryCompiled(trx, query, pagination, params, undefined, {
146
+ serialize: config?.serialize
147
+ }, {
146
148
  module: this.bucket.schema.module
147
149
  })).data;
148
150
  data = [];
@@ -153,7 +155,9 @@ class BucketCache {
153
155
  }
154
156
  // Invalid mode, bypass cache
155
157
  else {
156
- const result = await this.outerAdapter.query(trx, query /* TODO */, pagination, params);
158
+ const result = await this.outerAdapter.query(trx, query /* TODO */, pagination, params, param_templates, config, {
159
+ module: this.bucket.schema.module
160
+ });
157
161
  data = result.data;
158
162
  }
159
163
  for (const entry of data) {
@@ -270,7 +274,7 @@ class BucketCache {
270
274
  async syncQuery(trx, query, pagination, params) {
271
275
  // 1. Query id and epoch from outer adapter
272
276
  const outerMetadata = await this.outerAdapter.query(trx, query, pagination, params, undefined, {
273
- metadataOnly: true
277
+ metadata_only: true
274
278
  });
275
279
  if (!outerMetadata.data.length) {
276
280
  return { action: 'none', sync: [] };
@@ -38,6 +38,7 @@ export declare class BucketGraph<M extends $Module, $ extends $Bucket> {
38
38
  }, options?: {
39
39
  silent?: boolean;
40
40
  no_tenancy?: boolean;
41
+ serialize?: boolean;
41
42
  }): Promise<Obj[] | Obj[][]>;
42
43
  /**
43
44
  * Read the data from a link and build it with a given view
@@ -58,11 +59,19 @@ export declare class BucketGraph<M extends $Module, $ extends $Bucket> {
58
59
  * Return true if the link resolves to at least one object
59
60
  *
60
61
  * - Options
61
- * - `silent`: If not found, returns undefined instead of raising an exception
62
62
  * - `no_tenancy`: Don't apply tenancy rules
63
63
  */
64
64
  hasLink<LinkName extends keyof $['graph']['links']>(trx: AnyTrxNode, link: LinkName, obj: $['#data'], options?: {
65
65
  no_tenancy?: boolean;
66
66
  }): Promise<boolean>;
67
+ /**
68
+ * Return the number of objects matching a given link
69
+ *
70
+ * - Options
71
+ * - `no_tenancy`: Don't apply tenancy rules
72
+ */
73
+ countLink<LinkName extends keyof $['graph']['links']>(trx: AnyTrxNode, link: LinkName, obj: $['#data'], options?: {
74
+ no_tenancy?: boolean;
75
+ }): Promise<boolean>;
67
76
  }
68
77
  export type AnyBucket = Bucket<any, any>;
@@ -165,12 +165,16 @@ class BucketGraph {
165
165
  if (tempAdapter instanceof bucket_cache_1.BucketCache) {
166
166
  result = await tempAdapter._queryCompiled(trx, compiled, {
167
167
  perPage: schema.many ? undefined : 1,
168
- }, param, param_template);
168
+ }, param, param_template, {
169
+ serialize: options?.serialize
170
+ });
169
171
  }
170
172
  else {
171
173
  result = await tempAdapter._queryCompiled(trx, compiled, {
172
174
  perPage: schema.many ? undefined : 1,
173
- }, param, param_template, undefined, {
175
+ }, param, param_template, {
176
+ serialize: options?.serialize
177
+ }, {
174
178
  module: schema.bucket.module,
175
179
  buckets: {
176
180
  [schema.bucket.short]: {
@@ -228,7 +232,6 @@ class BucketGraph {
228
232
  * Return true if the link resolves to at least one object
229
233
  *
230
234
  * - Options
231
- * - `silent`: If not found, returns undefined instead of raising an exception
232
235
  * - `no_tenancy`: Don't apply tenancy rules
233
236
  */
234
237
  async hasLink(trx, link, obj, options) {
@@ -260,7 +263,50 @@ class BucketGraph {
260
263
  '#and__tenancy__': tenancy
261
264
  };
262
265
  const adapter = await trx_1.Trx.getCache(trx, otherBucket) || otherBucket.cache || otherBucket.adapter;
263
- links = await adapter.query(trx, query, page, params);
266
+ links = await adapter.query(trx, query, page, params, undefined, {
267
+ metadata_only: true,
268
+ });
269
+ }
270
+ return !!links.data.length;
271
+ }
272
+ /**
273
+ * Return the number of objects matching a given link
274
+ *
275
+ * - Options
276
+ * - `no_tenancy`: Don't apply tenancy rules
277
+ */
278
+ async countLink(trx, link, obj, options) {
279
+ log_1.Log.trace('bucket', this.bucketName, `Count link ${link}`);
280
+ const schema = this.schema.links[link];
281
+ // Query
282
+ const module = trx_node_1.TrxNode.getModule(trx);
283
+ const params = [{ ...obj }];
284
+ const page = {
285
+ perPage: 1,
286
+ };
287
+ // External
288
+ let links;
289
+ if (schema.bucket.module !== module.name) {
290
+ links = await trx.bucket(schema.bucket.short)
291
+ .query(schema.query)
292
+ .params(params)
293
+ .page(page);
294
+ }
295
+ // Internal
296
+ else {
297
+ const otherBucket = dependency_1.Tag.element(schema.bucket, trx);
298
+ // Make tenancy query
299
+ const tenancy = (options?.no_tenancy)
300
+ ? undefined
301
+ : otherBucket.getTenancyQuery(trx);
302
+ const query = {
303
+ ...schema.query,
304
+ '#and__tenancy__': tenancy
305
+ };
306
+ const adapter = await trx_1.Trx.getCache(trx, otherBucket) || otherBucket.cache || otherBucket.adapter;
307
+ links = await adapter.query(trx, query, page, params, undefined, {
308
+ metadata_only: true,
309
+ });
264
310
  }
265
311
  return !!links.data.length;
266
312
  }
@@ -5,7 +5,7 @@ type BucketModelCopyCmd = {
5
5
  field: $BucketModelField;
6
6
  obj: Record<string, any>;
7
7
  copy: Record<string, any>;
8
- path: string;
8
+ key: string;
9
9
  depth: number;
10
10
  modelpath?: {
11
11
  i: number;
@@ -22,6 +22,12 @@ export declare class BucketModel<M extends $Module, $ extends $Bucket> {
22
22
  private alias;
23
23
  private schema;
24
24
  constructor(bucket: $Bucket, config?: BucketAdapterConfig | undefined);
25
- copy<T extends Record<string, any>>(obj: T, op: 'save' | 'load', serialize?: (cmd?: BucketModelCopyCmd) => boolean, modelpath?: string): T;
25
+ copy<T extends Record<string, any>>(obj: T, op: 'save' | 'load', serialize?: (cmd?: BucketModelCopyCmd) => boolean, roots?: string[]): T;
26
+ copy<T extends Record<string, any>>(obj: T, op: 'save' | 'load', serialize?: (cmd?: BucketModelCopyCmd) => boolean, modelpath?: string): {
27
+ value: any;
28
+ index: string[];
29
+ }[];
30
+ private runCopyCmdPoll;
31
+ private runCopyCmd;
26
32
  }
27
33
  export {};