rads-db 3.1.15 → 3.2.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/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as RadsConfig, T as TypeDefinition } from './types-9cb9d6e7.js';
1
+ import { g as RadsConfig, T as TypeDefinition } from './types-dd50fa7e.js';
2
2
  import '_rads-db';
3
3
 
4
4
  declare function defineRadsConfig(config: RadsConfig): RadsConfig;
package/dist/index.cjs CHANGED
@@ -1195,7 +1195,10 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
1195
1195
  deleteMany(args, ctx) {
1196
1196
  throw new Error(`"deleteMany" not supported for driver "${driverInstance.driverName}"`);
1197
1197
  },
1198
- ...driverInstance
1198
+ ...driverInstance,
1199
+ get client() {
1200
+ return driverInstance.client;
1201
+ }
1199
1202
  };
1200
1203
  }
1201
1204
  function addDryRunSupport(driverInstance, entity) {
@@ -1275,10 +1278,21 @@ const restApi = (options) => (schema, entity) => {
1275
1278
  }
1276
1279
  return responseJson;
1277
1280
  }
1278
- const { handlePlural } = schema[entity] || {};
1279
- if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
1281
+ const { handlePlural, handle } = schema[entity] || {};
1282
+ if (!handlePlural || !handle) throw new Error(`Entity ${entity} was not found in schema`);
1280
1283
  const instance = {
1281
1284
  driverName: "restApi",
1285
+ async getAgg(args, ctx) {
1286
+ args = args || {};
1287
+ const url = `${opts.baseUrl}/${handle}/agg`;
1288
+ const fetchOptions = {
1289
+ method: "POST",
1290
+ body: JSON.stringify(args),
1291
+ headers: { "Content-Type": "application/json" }
1292
+ };
1293
+ fetchOptions.headers = { ...fetchOptions.headers, ...opts.getHeaders({ args, context: ctx }) };
1294
+ return await fetchInner(url, fetchOptions);
1295
+ },
1282
1296
  async getMany(args, ctx) {
1283
1297
  args = args || {};
1284
1298
  const url = `${opts.baseUrl}/${handlePlural}`;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-9cb9d6e7.js';
2
- export { N as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, aj as DeepKeys, ae as DeepPartial, ac as DeepPartialWithNulls, ad as DeepPartialWithNullsItem, ak as EntityMethods, w as EnumDefinition, v as FieldDefinition, I as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, B as GenerateClientNormalizedOptions, A as GenerateClientOptions, a8 as Get, _ as GetAggArgs, $ as GetAggArgsAgg, a2 as GetAggArgsAny, a5 as GetAggResponse, Z as GetArgs, a1 as GetArgsAny, a4 as GetArgsInclude, O as GetManyArgs, a0 as GetManyArgsAny, a6 as GetManyResponse, a7 as GetResponse, a9 as GetResponseInclude, aa as GetResponseIncludeSelect, ab as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ag as InverseRelation, M as MinimalDriver, ai as Put, ah as PutArgs, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, L as RadsFeature, y as RadsHookDoc, K as RadsUiSlotDefinition, J as RadsUiSlotName, H as RadsVitePluginOptions, af as Relation, i as RequiredFields, l as RestDriverOptions, z as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, T as TypeDefinition, j as ValidateStringDecoratorArgs, Q as VerifyManyArgs, a3 as VerifyManyArgsAny, X as VerifyManyResponse, Y as Where, W as WhereJsonContains } from './types-9cb9d6e7.js';
1
+ import { E as EntityDecoratorArgs, U as UiDecoratorArgs, a as UiFieldDecoratorArgs, V as ValidateEntityDecoratorArgs, b as ValidateFieldDecoratorArgs, F as FieldDecoratorArgs, C as ComputedDecoratorArgs, S as Schema, D as DriverConstructor, c as Driver, d as ComputedContext, R as RadsRequestContext, e as CreateRadsDbArgs, f as CreateRadsDbClientArgs } from './types-dd50fa7e.js';
2
+ export { N as Change, x as ComputedContextGlobal, k as CreateRadsArgsDrivers, m as CreateRadsDbArgsNormalized, aj as DeepKeys, ae as DeepPartial, ac as DeepPartialWithNulls, ad as DeepPartialWithNullsItem, ak as EntityMethods, w as EnumDefinition, v as FieldDefinition, I as FileSystemNode, u as FileUploadArgs, q as FileUploadDriver, p as FileUploadResult, B as GenerateClientNormalizedOptions, A as GenerateClientOptions, a8 as Get, _ as GetAggArgs, $ as GetAggArgsAgg, a2 as GetAggArgsAny, a5 as GetAggResponse, Z as GetArgs, a1 as GetArgsAny, a4 as GetArgsInclude, O as GetManyArgs, a0 as GetManyArgsAny, a6 as GetManyResponse, a7 as GetResponse, a9 as GetResponseInclude, aa as GetResponseIncludeSelect, ab as GetResponseNoInclude, s as GetRestRoutesArgs, G as GetRestRoutesOptions, t as GetRestRoutesResponse, ag as InverseRelation, M as MinimalDriver, ai as Put, ah as PutArgs, P as PutEffect, g as RadsConfig, h as RadsConfigDataSource, r as RadsDbInstance, L as RadsFeature, y as RadsHookDoc, K as RadsUiSlotDefinition, J as RadsUiSlotName, H as RadsVitePluginOptions, af as Relation, i as RequiredFields, l as RestDriverOptions, z as RestFileUploadDriverOptions, n as SchemaLoadResult, o as SchemaValidators, T as TypeDefinition, j as ValidateStringDecoratorArgs, Q as VerifyManyArgs, a3 as VerifyManyArgsAny, X as VerifyManyResponse, Y as Where, W as WhereJsonContains } from './types-dd50fa7e.js';
3
3
  import { RadsDb } from '_rads-db';
4
4
  export { RadsDb } from '_rads-db';
5
5
 
package/dist/index.mjs CHANGED
@@ -1188,7 +1188,10 @@ function getDriverInstanceInner(schema, key, driverConstructor) {
1188
1188
  deleteMany(args, ctx) {
1189
1189
  throw new Error(`"deleteMany" not supported for driver "${driverInstance.driverName}"`);
1190
1190
  },
1191
- ...driverInstance
1191
+ ...driverInstance,
1192
+ get client() {
1193
+ return driverInstance.client;
1194
+ }
1192
1195
  };
1193
1196
  }
1194
1197
  function addDryRunSupport(driverInstance, entity) {
@@ -1268,10 +1271,21 @@ const restApi = (options) => (schema, entity) => {
1268
1271
  }
1269
1272
  return responseJson;
1270
1273
  }
1271
- const { handlePlural } = schema[entity] || {};
1272
- if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
1274
+ const { handlePlural, handle } = schema[entity] || {};
1275
+ if (!handlePlural || !handle) throw new Error(`Entity ${entity} was not found in schema`);
1273
1276
  const instance = {
1274
1277
  driverName: "restApi",
1278
+ async getAgg(args, ctx) {
1279
+ args = args || {};
1280
+ const url = `${opts.baseUrl}/${handle}/agg`;
1281
+ const fetchOptions = {
1282
+ method: "POST",
1283
+ body: JSON.stringify(args),
1284
+ headers: { "Content-Type": "application/json" }
1285
+ };
1286
+ fetchOptions.headers = { ...fetchOptions.headers, ...opts.getHeaders({ args, context: ctx }) };
1287
+ return await fetchInner(url, fetchOptions);
1288
+ },
1275
1289
  async getMany(args, ctx) {
1276
1290
  args = args || {};
1277
1291
  const url = `${opts.baseUrl}/${handlePlural}`;
@@ -5,7 +5,7 @@ type Change<T> = {
5
5
  [K in keyof T]?: T[K] extends any[] ? T[K] : T[K] extends {} ? Change<T[K]> : T[K];
6
6
  };
7
7
  interface GetManyArgs<EN extends keyof EntityMeta> extends GetArgs<EN> {
8
- cursor?: string | null;
8
+ cursor?: string | undefined;
9
9
  maxItemCount?: number;
10
10
  orderBy?: string;
11
11
  orderByArray?: OrderBy<EntityMeta[EN]>;
@@ -15,7 +15,7 @@ interface VerifyManyArgs<EN extends keyof EntityMeta> extends GetManyArgs<EN> {
15
15
  dryRun?: boolean;
16
16
  }
17
17
  interface VerifyManyResponse {
18
- cursor: string | null;
18
+ cursor: string | undefined;
19
19
  correctCount: number;
20
20
  incorrectCount: number;
21
21
  incorrectDocs: {
@@ -55,7 +55,7 @@ type GetAggResponse<EN extends keyof EntityMeta, A extends GetAggArgs<EN>> = {
55
55
  };
56
56
  interface GetManyResponse<EN extends keyof EntityMeta, A extends GetArgs<EN>> {
57
57
  nodes: GetResponse<EN, A>[];
58
- cursor: string | null;
58
+ cursor: string | undefined;
59
59
  }
60
60
  type GetResponse<EN extends keyof EntityMeta, A extends GetArgs<EN>> = A extends {
61
61
  include: any;
@@ -309,23 +309,24 @@ interface MinimalDriver {
309
309
  driverName: string;
310
310
  /** raw underlying data access service - e.g. sql client or azure storage client */
311
311
  client?: any;
312
- putMany: (item: Record<string, any>[], ctx?: RadsRequestContext) => MaybePromise<void>;
312
+ putMany: (items: Record<string, any>[], ctx?: RadsRequestContext) => MaybePromise<void>;
313
313
  getMany: (args?: GetManyArgsAny, ctx?: RadsRequestContext) => MaybePromise<{
314
314
  nodes: Record<string, any>[];
315
- cursor: string | null;
315
+ cursor: string | undefined;
316
316
  }>;
317
- get?: (args: GetArgsAny, ctx?: RadsRequestContext) => MaybePromise<Record<string, any> | null>;
317
+ get?: (args: GetArgsAny, ctx?: RadsRequestContext) => MaybePromise<Record<string, any> | undefined>;
318
318
  getAll?: (args: GetManyArgsAny, ctx?: RadsRequestContext) => MaybePromise<Record<string, any>[]>;
319
319
  getAgg?: (args: GetAggArgsAny, ctx?: RadsRequestContext) => MaybePromise<Record<string, any>>;
320
320
  deleteMany?: (args: GetManyArgsAny, ctx?: RadsRequestContext) => MaybePromise<{
321
321
  nodes: Record<string, any>[];
322
- cursor: string | null;
322
+ cursor: string | undefined;
323
323
  }>;
324
324
  deleteAll?: (args: GetManyArgsAny, ctx?: RadsRequestContext) => MaybePromise<Record<string, any>[]>;
325
325
  put?: (data: Record<string, any>, ctx?: RadsRequestContext) => MaybePromise<void>;
326
326
  verifyMany?: (args?: VerifyManyArgsAny, ctx?: RadsRequestContext) => MaybePromise<VerifyManyResponse>;
327
+ generateMigrationScript?: () => MaybePromise<string | undefined>;
327
328
  }
328
- type Driver = Required<Omit<MinimalDriver, 'verifyMany' | 'client'>> & Pick<MinimalDriver, 'verifyMany' | 'client'>;
329
+ type Driver = Required<Omit<MinimalDriver, 'verifyMany' | 'client' | 'generateMigrationScript'>> & Pick<MinimalDriver, 'verifyMany' | 'client' | 'generateMigrationScript'>;
329
330
  interface FieldDefinition {
330
331
  name: string;
331
332
  type: string;
@@ -57,14 +57,14 @@ var _default = options => (schema, entity) => {
57
57
  const items = await getItemByIds([where.id], ctx, args.include);
58
58
  return {
59
59
  nodes: [items[0]].filter(x => x),
60
- cursor: null
60
+ cursor: void 0
61
61
  };
62
62
  }
63
63
  if (whereKeys[0] === "id_in" && where.id_in != null) {
64
64
  const items = await getItemByIds(where.id_in, ctx, args.include);
65
65
  return {
66
66
  nodes: items.filter(x => x),
67
- cursor: null
67
+ cursor: void 0
68
68
  };
69
69
  }
70
70
  }
@@ -90,13 +90,47 @@ var _default = options => (schema, entity) => {
90
90
  });
91
91
  return {
92
92
  nodes: page.resources,
93
- cursor: page.continuationToken || null
93
+ cursor: page.continuationToken || void 0
94
94
  };
95
95
  }
96
96
  const instance = {
97
97
  driverName: "azureCosmos",
98
98
  client,
99
99
  getMany,
100
+ async getAgg(args, ctx) {
101
+ args = args || {};
102
+ const where = args.where || {};
103
+ const {
104
+ query,
105
+ parameters
106
+ } = getCosmosQuery(schema, entity, args);
107
+ let cursor;
108
+ const response = client.items.query({
109
+ query,
110
+ parameters: Object.keys(parameters).map(k => ({
111
+ name: `@${k}`,
112
+ value: parameters[k]
113
+ }))
114
+ }, {
115
+ continuationToken: args.cursor || void 0,
116
+ continuationTokenLimitInKB: 4,
117
+ maxItemCount: args.maxItemCount
118
+ });
119
+ const page = await response.fetchNext();
120
+ let result = {};
121
+ for (const r of page.resources) {
122
+ result = {
123
+ ...result,
124
+ ...r
125
+ };
126
+ }
127
+ ctx?.log?.({
128
+ charge: page.requestCharge,
129
+ request: query
130
+ });
131
+ if (page.continuationToken) result.cursor = page.continuationToken;
132
+ return result;
133
+ },
100
134
  async deleteMany(args, ctx) {
101
135
  const {
102
136
  nodes,
@@ -155,11 +189,32 @@ function getCosmosQuery(schema, entity, args) {
155
189
  entity
156
190
  }, parameters, where)].filter(x => x);
157
191
  const orderByClause = getCosmosOrderBy(args);
158
- let colums = "*";
192
+ let columns = "*";
159
193
  if (args.include?._pick) {
160
- colums = getCosmosSelectValue(args.include);
194
+ columns = getCosmosSelectValue(args.include);
195
+ }
196
+ if (args.agg) {
197
+ const columnsArray = [];
198
+ for (const key of args.agg) {
199
+ const [field, aggOp] = key.split("_");
200
+ if (aggOp === "count") {
201
+ columnsArray.push("COUNT(1) AS _count");
202
+ }
203
+ if (aggOp === "max" && field) {
204
+ columnsArray.push(`MAX(r["${field}"]) AS ${field}_max`);
205
+ }
206
+ if (aggOp === "min" && field) {
207
+ columnsArray.push(`MIN(r["${field}"]) AS ${field}_min`);
208
+ }
209
+ if (aggOp === "sum" && field) {
210
+ columnsArray.push(`SUM(r["${field}"]) AS ${field}_sum`);
211
+ }
212
+ }
213
+ if (columnsArray.length) {
214
+ columns = columnsArray.join(", ");
215
+ }
161
216
  }
162
- const query = `select ${colums} from r where ${whereClauses.join(" AND ")} ${orderByClause}`;
217
+ const query = `select ${columns} from r where ${whereClauses.join(" AND ")} ${orderByClause}`;
163
218
  return {
164
219
  query,
165
220
  parameters
@@ -588,7 +643,20 @@ async function createDatabaseIfNotExists(options, client) {
588
643
  async function bulkSendWithRetry(client, chunkToSend) {
589
644
  const responses = [];
590
645
  for (let i = 0; i < 20; i++) {
591
- const response = await client.items.bulk(chunkToSend);
646
+ let response;
647
+ try {
648
+ response = await client.items.bulk(chunkToSend);
649
+ } catch (e) {
650
+ const is429 = e?.message?.includes("cosmosdb-error-429");
651
+ if (is429) {
652
+ const delay2 = 50 + i * 100;
653
+ console.warn(`Db overloaded. Retrying after ${delay2}ms...`);
654
+ await new Promise(resolve => setTimeout(resolve, delay2));
655
+ continue;
656
+ } else {
657
+ throw e;
658
+ }
659
+ }
592
660
  const newChunkToSend = [];
593
661
  for (let i2 = 0; i2 < chunkToSend.length; i2++) {
594
662
  if (response[i2].statusCode !== 429) {
@@ -34,11 +34,11 @@ export default (options) => (schema, entity) => {
34
34
  if (whereKeys.length === 1) {
35
35
  if (whereKeys[0] === "id" && where.id != null) {
36
36
  const items = await getItemByIds([where.id], ctx, args.include);
37
- return { nodes: [items[0]].filter((x) => x), cursor: null };
37
+ return { nodes: [items[0]].filter((x) => x), cursor: void 0 };
38
38
  }
39
39
  if (whereKeys[0] === "id_in" && where.id_in != null) {
40
40
  const items = await getItemByIds(where.id_in, ctx, args.include);
41
- return { nodes: items.filter((x) => x), cursor: null };
41
+ return { nodes: items.filter((x) => x), cursor: void 0 };
42
42
  }
43
43
  }
44
44
  const { query, parameters } = getCosmosQuery(schema, entity, args);
@@ -57,13 +57,38 @@ export default (options) => (schema, entity) => {
57
57
  ctx?.log?.({ charge: page.requestCharge, request: query });
58
58
  return {
59
59
  nodes: page.resources,
60
- cursor: page.continuationToken || null
60
+ cursor: page.continuationToken || void 0
61
61
  };
62
62
  }
63
63
  const instance = {
64
64
  driverName: "azureCosmos",
65
65
  client,
66
66
  getMany,
67
+ async getAgg(args, ctx) {
68
+ args = args || {};
69
+ const where = args.where || {};
70
+ const { query, parameters } = getCosmosQuery(schema, entity, args);
71
+ let cursor;
72
+ const response = client.items.query(
73
+ {
74
+ query,
75
+ parameters: Object.keys(parameters).map((k) => ({ name: `@${k}`, value: parameters[k] }))
76
+ },
77
+ {
78
+ continuationToken: args.cursor || void 0,
79
+ continuationTokenLimitInKB: 4,
80
+ maxItemCount: args.maxItemCount
81
+ }
82
+ );
83
+ const page = await response.fetchNext();
84
+ let result = {};
85
+ for (const r of page.resources) {
86
+ result = { ...result, ...r };
87
+ }
88
+ ctx?.log?.({ charge: page.requestCharge, request: query });
89
+ if (page.continuationToken) result.cursor = page.continuationToken;
90
+ return result;
91
+ },
67
92
  async deleteMany(args, ctx) {
68
93
  const { nodes, cursor } = await getMany(args, ctx);
69
94
  for (const chunk of _.chunk(nodes, 100)) {
@@ -111,11 +136,32 @@ function getCosmosQuery(schema, entity, args) {
111
136
  getCosmosQueryWhere({ schema, entity }, parameters, where)
112
137
  ].filter((x) => x);
113
138
  const orderByClause = getCosmosOrderBy(args);
114
- let colums = "*";
139
+ let columns = "*";
115
140
  if (args.include?._pick) {
116
- colums = getCosmosSelectValue(args.include);
141
+ columns = getCosmosSelectValue(args.include);
142
+ }
143
+ if (args.agg) {
144
+ const columnsArray = [];
145
+ for (const key of args.agg) {
146
+ const [field, aggOp] = key.split("_");
147
+ if (aggOp === "count") {
148
+ columnsArray.push("COUNT(1) AS _count");
149
+ }
150
+ if (aggOp === "max" && field) {
151
+ columnsArray.push(`MAX(r["${field}"]) AS ${field}_max`);
152
+ }
153
+ if (aggOp === "min" && field) {
154
+ columnsArray.push(`MIN(r["${field}"]) AS ${field}_min`);
155
+ }
156
+ if (aggOp === "sum" && field) {
157
+ columnsArray.push(`SUM(r["${field}"]) AS ${field}_sum`);
158
+ }
159
+ }
160
+ if (columnsArray.length) {
161
+ columns = columnsArray.join(", ");
162
+ }
117
163
  }
118
- const query = `select ${colums} from r where ${whereClauses.join(" AND ")} ${orderByClause}`;
164
+ const query = `select ${columns} from r where ${whereClauses.join(" AND ")} ${orderByClause}`;
119
165
  return { query, parameters };
120
166
  }
121
167
  const operatorHandlers = {
@@ -385,7 +431,20 @@ async function createDatabaseIfNotExists(options, client) {
385
431
  async function bulkSendWithRetry(client, chunkToSend) {
386
432
  const responses = [];
387
433
  for (let i = 0; i < 20; i++) {
388
- const response = await client.items.bulk(chunkToSend);
434
+ let response;
435
+ try {
436
+ response = await client.items.bulk(chunkToSend);
437
+ } catch (e) {
438
+ const is429 = e?.message?.includes("cosmosdb-error-429");
439
+ if (is429) {
440
+ const delay2 = 50 + i * 100;
441
+ console.warn(`Db overloaded. Retrying after ${delay2}ms...`);
442
+ await new Promise((resolve) => setTimeout(resolve, delay2));
443
+ continue;
444
+ } else {
445
+ throw e;
446
+ }
447
+ }
389
448
  const newChunkToSend = [];
390
449
  for (let i2 = 0; i2 < chunkToSend.length; i2++) {
391
450
  if (response[i2].statusCode !== 429) {
@@ -43,14 +43,14 @@ var _default = options => (schema, entity) => {
43
43
  const items = await getItemByIds([where.id], ctx);
44
44
  return {
45
45
  nodes: [items[0]].filter(x => x),
46
- cursor: null
46
+ cursor: void 0
47
47
  };
48
48
  }
49
49
  if (whereKeys[0] === "id_in" && where.id_in != null) {
50
50
  const items = await getItemByIds(where.id_in, ctx);
51
51
  return {
52
52
  nodes: items.filter(x => x),
53
- cursor: null
53
+ cursor: void 0
54
54
  };
55
55
  }
56
56
  }
@@ -69,12 +69,12 @@ var _default = options => (schema, entity) => {
69
69
  const nodes = await getBlobsByNames(ids, ctx);
70
70
  return {
71
71
  nodes,
72
- cursor: page.continuationToken || null
72
+ cursor: page.continuationToken || void 0
73
73
  };
74
74
  }
75
75
  return {
76
76
  nodes: [],
77
- cursor: null
77
+ cursor: void 0
78
78
  };
79
79
  }
80
80
  const instance = {
@@ -33,11 +33,11 @@ export default (options) => (schema, entity) => {
33
33
  if (whereKeys.length === 1) {
34
34
  if (whereKeys[0] === "id" && where.id != null) {
35
35
  const items = await getItemByIds([where.id], ctx);
36
- return { nodes: [items[0]].filter((x) => x), cursor: null };
36
+ return { nodes: [items[0]].filter((x) => x), cursor: void 0 };
37
37
  }
38
38
  if (whereKeys[0] === "id_in" && where.id_in != null) {
39
39
  const items = await getItemByIds(where.id_in, ctx);
40
- return { nodes: items.filter((x) => x), cursor: null };
40
+ return { nodes: items.filter((x) => x), cursor: void 0 };
41
41
  }
42
42
  }
43
43
  if (whereKeys.length > 1) throw new Error("Complex queries are not supported by azureStorageBlob");
@@ -52,12 +52,12 @@ export default (options) => (schema, entity) => {
52
52
  const nodes = await getBlobsByNames(ids, ctx);
53
53
  return {
54
54
  nodes,
55
- cursor: page.continuationToken || null
55
+ cursor: page.continuationToken || void 0
56
56
  };
57
57
  }
58
58
  return {
59
59
  nodes: [],
60
- cursor: null
60
+ cursor: void 0
61
61
  };
62
62
  }
63
63
  const instance = {
@@ -28,11 +28,31 @@ var _default = options => (schema, entity) => {
28
28
  return responseJson;
29
29
  }
30
30
  const {
31
- handlePlural
31
+ handlePlural,
32
+ handle
32
33
  } = schema[entity] || {};
33
- if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
34
+ if (!handlePlural || !handle) throw new Error(`Entity ${entity} was not found in schema`);
34
35
  const instance = {
35
36
  driverName: "restApi",
37
+ async getAgg(args, ctx) {
38
+ args = args || {};
39
+ const url = `${opts.baseUrl}/${handle}/agg`;
40
+ const fetchOptions = {
41
+ method: "POST",
42
+ body: JSON.stringify(args),
43
+ headers: {
44
+ "Content-Type": "application/json"
45
+ }
46
+ };
47
+ fetchOptions.headers = {
48
+ ...fetchOptions.headers,
49
+ ...opts.getHeaders({
50
+ args,
51
+ context: ctx
52
+ })
53
+ };
54
+ return await fetchInner(url, fetchOptions);
55
+ },
36
56
  async getMany(args, ctx) {
37
57
  args = args || {};
38
58
  const url = `${opts.baseUrl}/${handlePlural}`;
@@ -21,10 +21,21 @@ export default (options) => (schema, entity) => {
21
21
  }
22
22
  return responseJson;
23
23
  }
24
- const { handlePlural } = schema[entity] || {};
25
- if (!handlePlural) throw new Error(`Entity ${entity} was not found in schema`);
24
+ const { handlePlural, handle } = schema[entity] || {};
25
+ if (!handlePlural || !handle) throw new Error(`Entity ${entity} was not found in schema`);
26
26
  const instance = {
27
27
  driverName: "restApi",
28
+ async getAgg(args, ctx) {
29
+ args = args || {};
30
+ const url = `${opts.baseUrl}/${handle}/agg`;
31
+ const fetchOptions = {
32
+ method: "POST",
33
+ body: JSON.stringify(args),
34
+ headers: { "Content-Type": "application/json" }
35
+ };
36
+ fetchOptions.headers = { ...fetchOptions.headers, ...opts.getHeaders({ args, context: ctx }) };
37
+ return await fetchInner(url, fetchOptions);
38
+ },
28
39
  async getMany(args, ctx) {
29
40
  args = args || {};
30
41
  const url = `${opts.baseUrl}/${handlePlural}`;