@apito-io/js-admin-sdk 2.0.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/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/index.d.mts +218 -0
- package/dist/index.d.ts +218 -0
- package/dist/index.js +135 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +135 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +82 -0
- package/src/__tests__/client.test.ts +493 -0
- package/src/client.ts +467 -0
- package/src/index.ts +30 -0
- package/src/typed-operations.ts +93 -0
- package/src/types.ts +170 -0
- package/src/version.ts +11 -0
package/src/client.ts
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
import {
|
|
3
|
+
ClientConfig,
|
|
4
|
+
DefaultDocumentStructure,
|
|
5
|
+
SearchResult,
|
|
6
|
+
TypedDocumentStructure,
|
|
7
|
+
TypedSearchResult,
|
|
8
|
+
CreateAndUpdateRequest,
|
|
9
|
+
GraphQLResponse,
|
|
10
|
+
GraphQLError as SDKGraphQLError,
|
|
11
|
+
ApitoError,
|
|
12
|
+
ValidationError,
|
|
13
|
+
InjectedDBOperationInterface,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Apito SDK Client - JavaScript implementation matching the Go SDK
|
|
18
|
+
*/
|
|
19
|
+
export class ApitoClient implements InjectedDBOperationInterface {
|
|
20
|
+
private httpClient: AxiosInstance;
|
|
21
|
+
private baseURL: string;
|
|
22
|
+
private apiKey: string;
|
|
23
|
+
private tenantId?: string;
|
|
24
|
+
|
|
25
|
+
constructor(config: ClientConfig) {
|
|
26
|
+
this.baseURL = config.baseURL;
|
|
27
|
+
this.apiKey = config.apiKey;
|
|
28
|
+
this.tenantId = config.tenantId;
|
|
29
|
+
|
|
30
|
+
// Create axios instance with default configuration
|
|
31
|
+
this.httpClient = axios.create({
|
|
32
|
+
timeout: config.timeout || 30000,
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
'X-Apito-Key': this.apiKey,
|
|
36
|
+
},
|
|
37
|
+
...config.httpClient,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Add tenant ID to headers if provided
|
|
41
|
+
if (this.tenantId) {
|
|
42
|
+
this.httpClient.defaults.headers['X-Apito-Tenant-ID'] = this.tenantId;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Execute a GraphQL query or mutation
|
|
48
|
+
*/
|
|
49
|
+
private async executeGraphQL<T = any>(
|
|
50
|
+
query: string,
|
|
51
|
+
variables?: Record<string, any>,
|
|
52
|
+
options?: { tenantId?: string }
|
|
53
|
+
): Promise<GraphQLResponse> {
|
|
54
|
+
try {
|
|
55
|
+
const payload = {
|
|
56
|
+
query,
|
|
57
|
+
variables: variables || {},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const headers: Record<string, string> = {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
'X-Apito-Key': this.apiKey,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
if (options?.tenantId || this.tenantId) {
|
|
66
|
+
headers['X-Apito-Tenant-ID'] = options?.tenantId || this.tenantId!;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const response = await this.httpClient.post<GraphQLResponse>(
|
|
70
|
+
this.baseURL,
|
|
71
|
+
payload,
|
|
72
|
+
{ headers }
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (response.data.errors && response.data.errors.length > 0) {
|
|
76
|
+
throw new SDKGraphQLError(
|
|
77
|
+
'GraphQL query failed',
|
|
78
|
+
response.data.errors,
|
|
79
|
+
response.data
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return response.data;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (axios.isAxiosError(error)) {
|
|
86
|
+
throw new ApitoError(
|
|
87
|
+
error.response?.data?.message || error.message,
|
|
88
|
+
'HTTP_ERROR',
|
|
89
|
+
error.response?.status,
|
|
90
|
+
error.response?.data
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generate a new tenant token for the specified tenant ID
|
|
99
|
+
*/
|
|
100
|
+
async generateTenantToken(token: string, tenantId: string): Promise<string> {
|
|
101
|
+
const query = `
|
|
102
|
+
mutation GenerateTenantToken($token: String!, $tenantId: String!) {
|
|
103
|
+
generateTenantToken(token: $token, tenant_id: $tenantId) {
|
|
104
|
+
token
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
const variables = { token, tenantId };
|
|
110
|
+
const response = await this.executeGraphQL(query, variables, { tenantId });
|
|
111
|
+
|
|
112
|
+
const data = response.data?.generateTenantToken;
|
|
113
|
+
if (!data?.token) {
|
|
114
|
+
throw new ValidationError('Invalid response format for tenant token');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return data.token;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get a single resource by model and ID
|
|
122
|
+
*/
|
|
123
|
+
async getSingleResource(
|
|
124
|
+
model: string,
|
|
125
|
+
id: string,
|
|
126
|
+
singlePageData: boolean = false
|
|
127
|
+
): Promise<DefaultDocumentStructure> {
|
|
128
|
+
const query = `
|
|
129
|
+
query GetSingleData($model: String, $_id: String!, $single_page_data: Boolean) {
|
|
130
|
+
getSingleData(model: $model, _id: $_id, single_page_data: $single_page_data) {
|
|
131
|
+
_key
|
|
132
|
+
data
|
|
133
|
+
meta {
|
|
134
|
+
created_at
|
|
135
|
+
updated_at
|
|
136
|
+
status
|
|
137
|
+
revision
|
|
138
|
+
revision_at
|
|
139
|
+
}
|
|
140
|
+
id
|
|
141
|
+
expire_at
|
|
142
|
+
relation_doc_id
|
|
143
|
+
type
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const variables = {
|
|
149
|
+
model,
|
|
150
|
+
_id: id,
|
|
151
|
+
single_page_data: singlePageData,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const response = await this.executeGraphQL(query, variables);
|
|
155
|
+
|
|
156
|
+
if (!response.data?.getSingleData) {
|
|
157
|
+
throw new ValidationError('Resource not found');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return response.data.getSingleData;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Search resources in a model
|
|
165
|
+
*/
|
|
166
|
+
async searchResources(
|
|
167
|
+
model: string,
|
|
168
|
+
filter: Record<string, any> = {},
|
|
169
|
+
aggregate: boolean = false
|
|
170
|
+
): Promise<SearchResult> {
|
|
171
|
+
const query = `
|
|
172
|
+
query GetModelData(
|
|
173
|
+
$model: String!
|
|
174
|
+
$page: Int
|
|
175
|
+
$limit: Int
|
|
176
|
+
$_key: JSON
|
|
177
|
+
$where: JSON
|
|
178
|
+
$search: String
|
|
179
|
+
) {
|
|
180
|
+
getModelData(
|
|
181
|
+
model: $model
|
|
182
|
+
page: $page
|
|
183
|
+
limit: $limit
|
|
184
|
+
_key: $_key
|
|
185
|
+
where: $where
|
|
186
|
+
search: $search
|
|
187
|
+
) {
|
|
188
|
+
results {
|
|
189
|
+
id
|
|
190
|
+
relation_doc_id
|
|
191
|
+
data
|
|
192
|
+
type
|
|
193
|
+
expire_at
|
|
194
|
+
meta {
|
|
195
|
+
created_at
|
|
196
|
+
updated_at
|
|
197
|
+
status
|
|
198
|
+
root_revision_id
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
count
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
// Only forward keys declared on the GraphQL operation (matches go-internal-sdk)
|
|
207
|
+
const variables: Record<string, any> = { model };
|
|
208
|
+
if (filter && typeof filter === 'object') {
|
|
209
|
+
if (filter._key !== undefined) {
|
|
210
|
+
variables._key = filter._key;
|
|
211
|
+
}
|
|
212
|
+
if (filter.page !== undefined) {
|
|
213
|
+
variables.page = filter.page;
|
|
214
|
+
}
|
|
215
|
+
if (filter.limit !== undefined) {
|
|
216
|
+
variables.limit = filter.limit;
|
|
217
|
+
}
|
|
218
|
+
if (filter.where !== undefined) {
|
|
219
|
+
variables.where = filter.where;
|
|
220
|
+
}
|
|
221
|
+
if (filter.search !== undefined) {
|
|
222
|
+
variables.search = filter.search;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const response = await this.executeGraphQL(query, variables);
|
|
227
|
+
|
|
228
|
+
if (!response.data?.getModelData) {
|
|
229
|
+
throw new ValidationError('Invalid search response format');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return response.data.getModelData;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get related documents
|
|
237
|
+
*/
|
|
238
|
+
async getRelationDocuments(
|
|
239
|
+
id: string,
|
|
240
|
+
connection: Record<string, any>
|
|
241
|
+
): Promise<SearchResult> {
|
|
242
|
+
const query = `
|
|
243
|
+
query GetModelData($model: String!, $page: Int, $limit: Int, $where: JSON, $search: String, $connection : ListAllDataDetailedOfAModelConnectionPayload) {
|
|
244
|
+
getModelData(model: $model, page: $page, limit: $limit, where: $where, search: $search, connection: $connection) {
|
|
245
|
+
results {
|
|
246
|
+
id
|
|
247
|
+
relation_doc_id
|
|
248
|
+
data
|
|
249
|
+
type
|
|
250
|
+
expire_at
|
|
251
|
+
meta {
|
|
252
|
+
created_at
|
|
253
|
+
updated_at
|
|
254
|
+
status
|
|
255
|
+
root_revision_id
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
count
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
`;
|
|
262
|
+
|
|
263
|
+
const variables: Record<string, any> = {
|
|
264
|
+
connection,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Extract model from connection if available
|
|
268
|
+
if (connection.model) {
|
|
269
|
+
variables.model = connection.model;
|
|
270
|
+
} else {
|
|
271
|
+
throw new ValidationError('model is required in connection parameters');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Add filter parameters if provided in connection
|
|
275
|
+
if (connection.filter) {
|
|
276
|
+
const filter = connection.filter;
|
|
277
|
+
if (filter.page !== undefined) {
|
|
278
|
+
variables.page = filter.page;
|
|
279
|
+
}
|
|
280
|
+
if (filter.limit !== undefined) {
|
|
281
|
+
variables.limit = filter.limit;
|
|
282
|
+
}
|
|
283
|
+
if (filter.where !== undefined) {
|
|
284
|
+
variables.where = filter.where;
|
|
285
|
+
}
|
|
286
|
+
if (filter.search !== undefined) {
|
|
287
|
+
variables.search = filter.search;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const response = await this.executeGraphQL(query, variables);
|
|
292
|
+
|
|
293
|
+
if (!response.data?.getModelData) {
|
|
294
|
+
throw new ValidationError('Invalid relation documents response format');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return response.data.getModelData;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Create a new resource
|
|
302
|
+
*/
|
|
303
|
+
async createNewResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure> {
|
|
304
|
+
if (!request.model) {
|
|
305
|
+
throw new ValidationError('model is required');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!request.payload) {
|
|
309
|
+
throw new ValidationError('payload is required');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const query = `
|
|
313
|
+
mutation CreateNewData($model: String!, $single_page_data: Boolean, $payload: JSON!, $connect: JSON) {
|
|
314
|
+
upsertModelData(
|
|
315
|
+
connect: $connect
|
|
316
|
+
model_name: $model
|
|
317
|
+
single_page_data: $single_page_data
|
|
318
|
+
payload: $payload
|
|
319
|
+
) {
|
|
320
|
+
id
|
|
321
|
+
type
|
|
322
|
+
data
|
|
323
|
+
meta {
|
|
324
|
+
created_at
|
|
325
|
+
updated_at
|
|
326
|
+
status
|
|
327
|
+
revision
|
|
328
|
+
revision_at
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
`;
|
|
333
|
+
|
|
334
|
+
const variables: Record<string, any> = {
|
|
335
|
+
model: request.model,
|
|
336
|
+
payload: request.payload,
|
|
337
|
+
single_page_data: request.singlePageData || false,
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
if (request.connect) {
|
|
341
|
+
variables.connect = request.connect;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const response = await this.executeGraphQL(query, variables);
|
|
345
|
+
|
|
346
|
+
if (!response.data?.upsertModelData) {
|
|
347
|
+
throw new ValidationError('Invalid create response format');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return response.data.upsertModelData;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Update an existing resource
|
|
355
|
+
*/
|
|
356
|
+
async updateResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure> {
|
|
357
|
+
if (!request.id) {
|
|
358
|
+
throw new ValidationError('id is required');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (!request.model) {
|
|
362
|
+
throw new ValidationError('model is required');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!request.payload) {
|
|
366
|
+
throw new ValidationError('payload is required');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const query = `
|
|
370
|
+
mutation UpdateModelData($_id: String!, $model: String!, $single_page_data: Boolean, $force_update: Boolean, $payload: JSON!, $connect: JSON, $disconnect: JSON) {
|
|
371
|
+
upsertModelData(
|
|
372
|
+
connect: $connect
|
|
373
|
+
model_name: $model
|
|
374
|
+
single_page_data: $single_page_data
|
|
375
|
+
force_update: $force_update
|
|
376
|
+
disconnect: $disconnect
|
|
377
|
+
_id: $_id
|
|
378
|
+
payload: $payload
|
|
379
|
+
) {
|
|
380
|
+
id
|
|
381
|
+
type
|
|
382
|
+
data
|
|
383
|
+
meta {
|
|
384
|
+
created_at
|
|
385
|
+
updated_at
|
|
386
|
+
status
|
|
387
|
+
revision
|
|
388
|
+
revision_at
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
`;
|
|
393
|
+
|
|
394
|
+
const variables: Record<string, any> = {
|
|
395
|
+
_id: request.id,
|
|
396
|
+
model: request.model,
|
|
397
|
+
payload: request.payload,
|
|
398
|
+
single_page_data: request.singlePageData || false,
|
|
399
|
+
force_update: request.forceUpdate || false,
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
if (request.connect) {
|
|
403
|
+
variables.connect = request.connect;
|
|
404
|
+
}
|
|
405
|
+
if (request.disconnect) {
|
|
406
|
+
variables.disconnect = request.disconnect;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const response = await this.executeGraphQL(query, variables);
|
|
410
|
+
|
|
411
|
+
if (!response.data?.upsertModelData) {
|
|
412
|
+
throw new ValidationError('Invalid update response format');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return response.data.upsertModelData;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Delete a resource by model and ID
|
|
420
|
+
*/
|
|
421
|
+
async deleteResource(model: string, id: string): Promise<void> {
|
|
422
|
+
const query = `
|
|
423
|
+
mutation DeleteData($model: String!, $_id: String!) {
|
|
424
|
+
deleteModelData(model_name: $model, _id: $_id) {
|
|
425
|
+
id
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
`;
|
|
429
|
+
|
|
430
|
+
const variables = {
|
|
431
|
+
model,
|
|
432
|
+
_id: id,
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
await this.executeGraphQL(query, variables);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Debug is used to debug the plugin, you can pass data here to debug the plugin
|
|
440
|
+
*/
|
|
441
|
+
async debug(stage: string, ...data: any[]): Promise<any> {
|
|
442
|
+
const query = `
|
|
443
|
+
mutation Debug($stage: String!, $data: JSON) {
|
|
444
|
+
debug(stage: $stage, data: $data) {
|
|
445
|
+
message
|
|
446
|
+
data
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
`;
|
|
450
|
+
|
|
451
|
+
const variables = {
|
|
452
|
+
stage,
|
|
453
|
+
data,
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const response = await this.executeGraphQL(query, variables);
|
|
457
|
+
|
|
458
|
+
return response.data?.debug;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Factory function to create a new Apito client
|
|
464
|
+
*/
|
|
465
|
+
export function createClient(config: ClientConfig): ApitoClient {
|
|
466
|
+
return new ApitoClient(config);
|
|
467
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apito JavaScript SDK
|
|
3
|
+
* A comprehensive JavaScript SDK for communicating with Apito GraphQL API endpoints
|
|
4
|
+
*
|
|
5
|
+
* @module @apito-io/js-admin-sdk
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export main client and types
|
|
9
|
+
export { ApitoClient, createClient } from './client';
|
|
10
|
+
export { TypedOperations } from './typed-operations';
|
|
11
|
+
export { Version, getVersion } from './version';
|
|
12
|
+
export * from './types';
|
|
13
|
+
|
|
14
|
+
// Re-export commonly used types for convenience
|
|
15
|
+
export type {
|
|
16
|
+
ClientConfig,
|
|
17
|
+
DefaultDocumentStructure,
|
|
18
|
+
SearchResult,
|
|
19
|
+
TypedDocumentStructure,
|
|
20
|
+
TypedSearchResult,
|
|
21
|
+
CreateAndUpdateRequest,
|
|
22
|
+
GraphQLResponse,
|
|
23
|
+
GraphQLError,
|
|
24
|
+
ApitoError,
|
|
25
|
+
ValidationError,
|
|
26
|
+
InjectedDBOperationInterface,
|
|
27
|
+
} from './types';
|
|
28
|
+
|
|
29
|
+
// Default export for convenience
|
|
30
|
+
export { ApitoClient as default } from './client';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DefaultDocumentStructure,
|
|
3
|
+
TypedDocumentStructure,
|
|
4
|
+
TypedSearchResult,
|
|
5
|
+
CreateAndUpdateRequest,
|
|
6
|
+
} from './types';
|
|
7
|
+
import { ApitoClient } from './client';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typed operations wrapper for the Apito SDK
|
|
11
|
+
* Provides type-safe methods for working with typed data
|
|
12
|
+
*/
|
|
13
|
+
export class TypedOperations {
|
|
14
|
+
constructor(private client: ApitoClient) {}
|
|
15
|
+
|
|
16
|
+
private static toTypedDocument<T>(raw: DefaultDocumentStructure): TypedDocumentStructure<T> {
|
|
17
|
+
const data = JSON.parse(JSON.stringify(raw.data)) as T;
|
|
18
|
+
return {
|
|
19
|
+
_key: raw._key,
|
|
20
|
+
_id: raw._id,
|
|
21
|
+
data,
|
|
22
|
+
meta: raw.meta,
|
|
23
|
+
id: raw.id,
|
|
24
|
+
expire_at: raw.expire_at,
|
|
25
|
+
relation_doc_id: raw.relation_doc_id,
|
|
26
|
+
last_revision_doc_id: raw.last_revision_doc_id,
|
|
27
|
+
type: raw.type,
|
|
28
|
+
tenant_id: raw.tenant_id,
|
|
29
|
+
tenant_model: raw.tenant_model,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get a single resource with type safety
|
|
35
|
+
*/
|
|
36
|
+
async getSingleResourceTyped<T>(
|
|
37
|
+
model: string,
|
|
38
|
+
id: string,
|
|
39
|
+
singlePageData: boolean = false
|
|
40
|
+
): Promise<TypedDocumentStructure<T>> {
|
|
41
|
+
const result = await this.client.getSingleResource(model, id, singlePageData);
|
|
42
|
+
return TypedOperations.toTypedDocument<T>(result);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Search resources with type safety
|
|
47
|
+
*/
|
|
48
|
+
async searchResourcesTyped<T>(
|
|
49
|
+
model: string,
|
|
50
|
+
filter: Record<string, any> = {},
|
|
51
|
+
aggregate: boolean = false
|
|
52
|
+
): Promise<TypedSearchResult<T>> {
|
|
53
|
+
const result = await this.client.searchResources(model, filter, aggregate);
|
|
54
|
+
return {
|
|
55
|
+
results: result.results.map((doc) => TypedOperations.toTypedDocument<T>(doc)),
|
|
56
|
+
count: result.count,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get related documents with type safety
|
|
62
|
+
*/
|
|
63
|
+
async getRelationDocumentsTyped<T>(
|
|
64
|
+
id: string,
|
|
65
|
+
connection: Record<string, any>
|
|
66
|
+
): Promise<TypedSearchResult<T>> {
|
|
67
|
+
const result = await this.client.getRelationDocuments(id, connection);
|
|
68
|
+
return {
|
|
69
|
+
results: result.results.map((doc) => TypedOperations.toTypedDocument<T>(doc)),
|
|
70
|
+
count: result.count,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create a new resource with type safety
|
|
76
|
+
*/
|
|
77
|
+
async createNewResourceTyped<T>(
|
|
78
|
+
request: CreateAndUpdateRequest
|
|
79
|
+
): Promise<TypedDocumentStructure<T>> {
|
|
80
|
+
const result = await this.client.createNewResource(request);
|
|
81
|
+
return TypedOperations.toTypedDocument<T>(result);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Update a resource with type safety
|
|
86
|
+
*/
|
|
87
|
+
async updateResourceTyped<T>(
|
|
88
|
+
request: CreateAndUpdateRequest
|
|
89
|
+
): Promise<TypedDocumentStructure<T>> {
|
|
90
|
+
const result = await this.client.updateResource(request);
|
|
91
|
+
return TypedOperations.toTypedDocument<T>(result);
|
|
92
|
+
}
|
|
93
|
+
}
|