@forgebase/sdk 0.0.1
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 +390 -0
- package/dist/cjs/database/client/client.d.ts +470 -0
- package/dist/cjs/database/client/client.d.ts.map +1 -0
- package/dist/cjs/database/client/client.js +812 -0
- package/dist/cjs/database/client/client.js.map +1 -0
- package/dist/cjs/database/client/index.d.ts +2 -0
- package/dist/cjs/database/client/index.d.ts.map +1 -0
- package/dist/cjs/database/client/index.js +18 -0
- package/dist/cjs/database/client/index.js.map +1 -0
- package/dist/cjs/database/examples.d.ts +70 -0
- package/dist/cjs/database/examples.d.ts.map +1 -0
- package/dist/cjs/database/examples.js +239 -0
- package/dist/cjs/database/examples.js.map +1 -0
- package/dist/cjs/database/server/index.d.ts +2 -0
- package/dist/cjs/database/server/index.d.ts.map +1 -0
- package/dist/cjs/database/server/index.js +18 -0
- package/dist/cjs/database/server/index.js.map +1 -0
- package/dist/cjs/database/server/server.d.ts +2 -0
- package/dist/cjs/database/server/server.d.ts.map +1 -0
- package/dist/cjs/database/server/server.js +6 -0
- package/dist/cjs/database/server/server.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/database/client/client.d.ts +470 -0
- package/dist/esm/database/client/client.d.ts.map +1 -0
- package/dist/esm/database/client/client.js +805 -0
- package/dist/esm/database/client/client.js.map +1 -0
- package/dist/esm/database/client/index.d.ts +2 -0
- package/dist/esm/database/client/index.d.ts.map +1 -0
- package/dist/esm/database/client/index.js +2 -0
- package/dist/esm/database/client/index.js.map +1 -0
- package/dist/esm/database/examples.d.ts +70 -0
- package/dist/esm/database/examples.d.ts.map +1 -0
- package/dist/esm/database/examples.js +236 -0
- package/dist/esm/database/examples.js.map +1 -0
- package/dist/esm/database/server/index.d.ts +2 -0
- package/dist/esm/database/server/index.d.ts.map +1 -0
- package/dist/esm/database/server/index.js +2 -0
- package/dist/esm/database/server/index.js.map +1 -0
- package/dist/esm/database/server/server.d.ts +2 -0
- package/dist/esm/database/server/server.d.ts.map +1 -0
- package/dist/esm/database/server/server.js +2 -0
- package/dist/esm/database/server/server.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DatabaseSDK = void 0;
|
|
7
|
+
/* eslint-disable prefer-const */
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
class DatabaseSDK {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new DatabaseSDK instance
|
|
12
|
+
* @param baseUrl The base URL for API requests
|
|
13
|
+
* @param axiosInstance Optional custom axios instance (e.g., from ForgebaseAuth)
|
|
14
|
+
* @param axiosConfig Optional axios configuration
|
|
15
|
+
* @param authInterceptors Optional auth interceptors to apply to the axios instance
|
|
16
|
+
*/
|
|
17
|
+
constructor(options) {
|
|
18
|
+
let { baseUrl, axiosInstance, axiosConfig, authInterceptors } = options;
|
|
19
|
+
this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash if present
|
|
20
|
+
if (!axiosConfig) {
|
|
21
|
+
axiosConfig = {};
|
|
22
|
+
}
|
|
23
|
+
// Use the provided axios instance or create a new one
|
|
24
|
+
if (axiosInstance) {
|
|
25
|
+
this.axiosInstance = axiosInstance;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.axiosInstance = axios_1.default.create({
|
|
29
|
+
baseURL: this.baseUrl,
|
|
30
|
+
withCredentials: true,
|
|
31
|
+
...axiosConfig,
|
|
32
|
+
});
|
|
33
|
+
// Apply auth interceptors if provided
|
|
34
|
+
if (authInterceptors) {
|
|
35
|
+
this.applyAuthInterceptors(authInterceptors);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the base URL used for API requests
|
|
41
|
+
* @returns The base URL string
|
|
42
|
+
*/
|
|
43
|
+
getBaseUrl() {
|
|
44
|
+
return this.baseUrl;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Set a new base URL for API requests
|
|
48
|
+
* @param baseUrl The new base URL to use
|
|
49
|
+
*/
|
|
50
|
+
setBaseUrl(baseUrl) {
|
|
51
|
+
this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash if present
|
|
52
|
+
// Update the axios instance baseURL if it was created by this class
|
|
53
|
+
if (this.axiosInstance.defaults.baseURL) {
|
|
54
|
+
this.axiosInstance.defaults.baseURL = this.baseUrl;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the axios instance used for API requests
|
|
59
|
+
* @returns The axios instance
|
|
60
|
+
*/
|
|
61
|
+
getAxiosInstance() {
|
|
62
|
+
return this.axiosInstance;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Set a new axios instance for API requests
|
|
66
|
+
* @param axiosInstance The new axios instance to use
|
|
67
|
+
*/
|
|
68
|
+
setAxiosInstance(axiosInstance) {
|
|
69
|
+
this.axiosInstance = axiosInstance;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Apply auth interceptors to the axios instance
|
|
73
|
+
* @param authInterceptors The auth interceptors to apply
|
|
74
|
+
*/
|
|
75
|
+
applyAuthInterceptors(authInterceptors) {
|
|
76
|
+
// Add request interceptor
|
|
77
|
+
this.axiosInstance.interceptors.request.use(authInterceptors.request);
|
|
78
|
+
// Add response interceptors
|
|
79
|
+
this.axiosInstance.interceptors.response.use(authInterceptors.response.onFulfilled, authInterceptors.response.onRejected);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Fetches records from a specified table with filtering and pagination
|
|
83
|
+
* @param tableName The name of the table to query
|
|
84
|
+
* @param params Query parameters including filters and pagination
|
|
85
|
+
* @param options Query options
|
|
86
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
87
|
+
* @returns Promise containing the fetched records
|
|
88
|
+
*/
|
|
89
|
+
async getRecords(tableName, params = {}, options = { execute: true }, axiosConfig = {}) {
|
|
90
|
+
// If execute is false, return only the parameters
|
|
91
|
+
if (!options.execute) {
|
|
92
|
+
return { params: params };
|
|
93
|
+
}
|
|
94
|
+
const url = `/query/${tableName}`;
|
|
95
|
+
try {
|
|
96
|
+
const response = await this.axiosInstance.post(url, { query: params }, axiosConfig);
|
|
97
|
+
return {
|
|
98
|
+
records: response.data,
|
|
99
|
+
params: params,
|
|
100
|
+
message: 'Records fetched successfully',
|
|
101
|
+
error: undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
106
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// private serializeQueryParams<T extends Record<string, any>>(
|
|
112
|
+
// params: QueryParams<T>
|
|
113
|
+
// ): Record<string, string> {
|
|
114
|
+
// const serialized: Record<string, string> = {};
|
|
115
|
+
// // any param that is type of object should be serialized to JSON
|
|
116
|
+
// Object.entries(params).forEach(([key, value]) => {
|
|
117
|
+
// if (typeof value === 'object') {
|
|
118
|
+
// serialized[key] = JSON.stringify(value);
|
|
119
|
+
// } else {
|
|
120
|
+
// serialized[key] = value.toString();
|
|
121
|
+
// }
|
|
122
|
+
// });
|
|
123
|
+
// return serialized;
|
|
124
|
+
// }
|
|
125
|
+
/**
|
|
126
|
+
* Creates a new record in the specified table
|
|
127
|
+
* @param tableName The name of the table to create the record in
|
|
128
|
+
* @param data The data to create the record with
|
|
129
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
130
|
+
* @returns Promise containing the created record
|
|
131
|
+
*/
|
|
132
|
+
async createRecord(tableName, data, axiosConfig = {}) {
|
|
133
|
+
this.validateData(data);
|
|
134
|
+
try {
|
|
135
|
+
const response = await this.axiosInstance.post(`/create/${tableName}`, { data }, axiosConfig);
|
|
136
|
+
return {
|
|
137
|
+
records: [response.data],
|
|
138
|
+
message: 'Record created successfully',
|
|
139
|
+
error: undefined,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
144
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Updates a record by ID in the specified table
|
|
151
|
+
* @param tableName The name of the table containing the record to update
|
|
152
|
+
* @param id The ID of the record to update
|
|
153
|
+
* @param data The data to update the record with
|
|
154
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
155
|
+
* @returns Promise containing the updated record
|
|
156
|
+
*/
|
|
157
|
+
async updateRecord(tableName, id, data, axiosConfig = {}) {
|
|
158
|
+
this.validateData(data);
|
|
159
|
+
try {
|
|
160
|
+
const response = await this.axiosInstance.put(`/update/${tableName}/${id}`, { data }, axiosConfig);
|
|
161
|
+
return {
|
|
162
|
+
records: [response.data],
|
|
163
|
+
message: 'Record updated successfully',
|
|
164
|
+
error: undefined,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
169
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Updates records by Complex Query from the specified table
|
|
176
|
+
* @param tableName The name of the table containing the record to delete
|
|
177
|
+
* @param params Query parameters including filters and pagination
|
|
178
|
+
* @param options Query options
|
|
179
|
+
* @param data The data to update the record with
|
|
180
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
181
|
+
* @returns Promise containing the result of the deletion
|
|
182
|
+
*/
|
|
183
|
+
async advanceUpdateRecord(tableName, data, params = {}, options = { execute: true }, axiosConfig = {}) {
|
|
184
|
+
try {
|
|
185
|
+
if (!options.execute) {
|
|
186
|
+
return { params: params };
|
|
187
|
+
}
|
|
188
|
+
const response = await this.axiosInstance.post(`/update/${tableName}`, { query: params, data }, axiosConfig);
|
|
189
|
+
return {
|
|
190
|
+
message: 'Records updated successfully',
|
|
191
|
+
error: undefined,
|
|
192
|
+
records: response.data,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
197
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Deletes a record by ID from the specified table
|
|
204
|
+
* @param tableName The name of the table containing the record to delete
|
|
205
|
+
* @param id The ID of the record to delete
|
|
206
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
207
|
+
* @returns Promise containing the result of the deletion
|
|
208
|
+
*/
|
|
209
|
+
async deleteRecord(tableName, id, axiosConfig = {}) {
|
|
210
|
+
try {
|
|
211
|
+
const response = await this.axiosInstance.post(`/del/${tableName}/${id}`, {}, axiosConfig);
|
|
212
|
+
return {
|
|
213
|
+
message: 'Record deleted successfully',
|
|
214
|
+
error: undefined,
|
|
215
|
+
records: response.data,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
220
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Deletes records by Complex Query from the specified table
|
|
227
|
+
* @param tableName The name of the table containing the record to delete
|
|
228
|
+
* @param params Query parameters including filters and pagination
|
|
229
|
+
* @param options Query options
|
|
230
|
+
* @param axiosConfig Custom axios config for this specific request
|
|
231
|
+
* @returns Promise containing the result of the deletion
|
|
232
|
+
*/
|
|
233
|
+
async advanceDeleteRecord(tableName, params = {}, options = { execute: true }, axiosConfig = {}) {
|
|
234
|
+
try {
|
|
235
|
+
if (!options.execute) {
|
|
236
|
+
return { params: params };
|
|
237
|
+
}
|
|
238
|
+
const response = await this.axiosInstance.post(`/del/${tableName}`, { query: params }, axiosConfig);
|
|
239
|
+
return {
|
|
240
|
+
message: 'Record deleted successfully',
|
|
241
|
+
error: undefined,
|
|
242
|
+
records: response.data,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
247
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
248
|
+
}
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Helper method to create a query builder for fluent API usage
|
|
254
|
+
* @param tableName The name of the table to query
|
|
255
|
+
*/
|
|
256
|
+
table(tableName) {
|
|
257
|
+
return new QueryBuilder(this, tableName);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Validates data object
|
|
261
|
+
*/
|
|
262
|
+
validateData(data) {
|
|
263
|
+
if (typeof data !== 'object' || Object.keys(data).length === 0) {
|
|
264
|
+
throw new Error('Invalid data: must be a non-empty object');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
exports.DatabaseSDK = DatabaseSDK;
|
|
269
|
+
/**
|
|
270
|
+
* Query builder class for more fluent API usage
|
|
271
|
+
*/
|
|
272
|
+
class QueryBuilder {
|
|
273
|
+
constructor(sdk, tableName) {
|
|
274
|
+
this.sdk = sdk;
|
|
275
|
+
this.tableName = tableName;
|
|
276
|
+
this.params = {};
|
|
277
|
+
this.ctes = new Map();
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Add a recursive CTE
|
|
281
|
+
*/
|
|
282
|
+
withRecursive(name, initialQuery, recursiveQuery, options = {}) {
|
|
283
|
+
if (!this.params.recursiveCtes) {
|
|
284
|
+
this.params.recursiveCtes = [];
|
|
285
|
+
}
|
|
286
|
+
this.params.recursiveCtes.push({
|
|
287
|
+
name,
|
|
288
|
+
isRecursive: true,
|
|
289
|
+
initialQuery,
|
|
290
|
+
recursiveQuery,
|
|
291
|
+
unionAll: options.unionAll,
|
|
292
|
+
columns: options.columns,
|
|
293
|
+
query: initialQuery, // for compatibility with non-recursive CTEs
|
|
294
|
+
});
|
|
295
|
+
return this;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Advanced window function
|
|
299
|
+
*/
|
|
300
|
+
windowAdvanced(type, alias, config) {
|
|
301
|
+
if (!this.params.advancedWindows) {
|
|
302
|
+
this.params.advancedWindows = [];
|
|
303
|
+
}
|
|
304
|
+
this.params.advancedWindows.push({
|
|
305
|
+
type,
|
|
306
|
+
alias,
|
|
307
|
+
...config,
|
|
308
|
+
});
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Add a window function
|
|
313
|
+
*/
|
|
314
|
+
window(type, alias, config = {}) {
|
|
315
|
+
if (!this.params.windowFunctions) {
|
|
316
|
+
this.params.windowFunctions = [];
|
|
317
|
+
}
|
|
318
|
+
this.params.windowFunctions.push({
|
|
319
|
+
type,
|
|
320
|
+
alias,
|
|
321
|
+
field: config.field,
|
|
322
|
+
partitionBy: config.partitionBy,
|
|
323
|
+
orderBy: config.orderBy,
|
|
324
|
+
frameClause: config.frameClause,
|
|
325
|
+
});
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Add common window functions
|
|
330
|
+
*/
|
|
331
|
+
rowNumber(alias, partitionBy, orderBy) {
|
|
332
|
+
return this.window('row_number', alias, { partitionBy, orderBy });
|
|
333
|
+
}
|
|
334
|
+
rank(alias, partitionBy, orderBy) {
|
|
335
|
+
return this.window('rank', alias, { partitionBy, orderBy });
|
|
336
|
+
}
|
|
337
|
+
lag(field, alias, partitionBy, orderBy) {
|
|
338
|
+
return this.window('lag', alias, { field, partitionBy, orderBy });
|
|
339
|
+
}
|
|
340
|
+
lead(field, alias, partitionBy, orderBy) {
|
|
341
|
+
return this.window('lead', alias, { field, partitionBy, orderBy });
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Add a CTE (WITH clause)
|
|
345
|
+
*/
|
|
346
|
+
with(name, queryOrCallback, columns) {
|
|
347
|
+
let query;
|
|
348
|
+
if (typeof queryOrCallback === 'function') {
|
|
349
|
+
query = new QueryBuilder(this.sdk, this.tableName);
|
|
350
|
+
queryOrCallback(query);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
query = queryOrCallback;
|
|
354
|
+
}
|
|
355
|
+
this.ctes.set(name, {
|
|
356
|
+
name,
|
|
357
|
+
query,
|
|
358
|
+
columns: columns || [],
|
|
359
|
+
});
|
|
360
|
+
if (!this.params.ctes) {
|
|
361
|
+
this.params.ctes = [];
|
|
362
|
+
}
|
|
363
|
+
this.params.ctes.push({ name, query, columns: columns || [] });
|
|
364
|
+
return this;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Transform the result set
|
|
368
|
+
*/
|
|
369
|
+
transform(config) {
|
|
370
|
+
this.params.transforms = {
|
|
371
|
+
...this.params.transforms,
|
|
372
|
+
...config,
|
|
373
|
+
};
|
|
374
|
+
return this;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Pivot the result set
|
|
378
|
+
*/
|
|
379
|
+
pivot(column, values, aggregate) {
|
|
380
|
+
return this.transform({
|
|
381
|
+
pivot: {
|
|
382
|
+
column,
|
|
383
|
+
values,
|
|
384
|
+
aggregate,
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Compute new fields from existing ones
|
|
390
|
+
*/
|
|
391
|
+
compute(computations) {
|
|
392
|
+
return this.transform({
|
|
393
|
+
compute: computations,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
where(fieldOrConditions, operatorOrValue, value) {
|
|
397
|
+
if (typeof fieldOrConditions === 'object') {
|
|
398
|
+
this.params.filter = {
|
|
399
|
+
...this.params.filter,
|
|
400
|
+
...fieldOrConditions,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
if (arguments.length === 2) {
|
|
405
|
+
this.params.filter = {
|
|
406
|
+
...this.params.filter,
|
|
407
|
+
[fieldOrConditions]: operatorOrValue,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
if (!this.params.whereRaw) {
|
|
412
|
+
this.params.whereRaw = [];
|
|
413
|
+
}
|
|
414
|
+
this.params.whereRaw.push({
|
|
415
|
+
field: fieldOrConditions,
|
|
416
|
+
operator: operatorOrValue,
|
|
417
|
+
value,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return this;
|
|
422
|
+
}
|
|
423
|
+
// Where between
|
|
424
|
+
whereBetween(field, range) {
|
|
425
|
+
if (!this.params.whereBetween) {
|
|
426
|
+
this.params.whereBetween = [];
|
|
427
|
+
}
|
|
428
|
+
this.params.whereBetween.push({
|
|
429
|
+
field,
|
|
430
|
+
operator: 'between',
|
|
431
|
+
value: range,
|
|
432
|
+
});
|
|
433
|
+
return this;
|
|
434
|
+
}
|
|
435
|
+
// Where in
|
|
436
|
+
whereIn(field, values) {
|
|
437
|
+
if (!this.params.whereIn) {
|
|
438
|
+
this.params.whereIn = {};
|
|
439
|
+
}
|
|
440
|
+
this.params.whereIn[field] = values;
|
|
441
|
+
return this;
|
|
442
|
+
}
|
|
443
|
+
// Where not in
|
|
444
|
+
whereNotIn(field, values) {
|
|
445
|
+
if (!this.params.whereNotIn) {
|
|
446
|
+
this.params.whereNotIn = {};
|
|
447
|
+
}
|
|
448
|
+
this.params.whereNotIn[field] = values;
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
// Where null
|
|
452
|
+
whereNull(field) {
|
|
453
|
+
if (!this.params.whereNull) {
|
|
454
|
+
this.params.whereNull = [];
|
|
455
|
+
}
|
|
456
|
+
this.params.whereNull.push(field);
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
459
|
+
// Where not null
|
|
460
|
+
whereNotNull(field) {
|
|
461
|
+
if (!this.params.whereNotNull) {
|
|
462
|
+
this.params.whereNotNull = [];
|
|
463
|
+
}
|
|
464
|
+
this.params.whereNotNull.push(field);
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
467
|
+
orderBy(fieldOrOptions, direction, nulls) {
|
|
468
|
+
if (!this.params.orderBy) {
|
|
469
|
+
this.params.orderBy = [];
|
|
470
|
+
}
|
|
471
|
+
if (typeof fieldOrOptions === 'string') {
|
|
472
|
+
direction = direction || 'asc';
|
|
473
|
+
this.params.orderBy.push({
|
|
474
|
+
field: fieldOrOptions,
|
|
475
|
+
direction,
|
|
476
|
+
nulls,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
this.params.orderBy.push(fieldOrOptions);
|
|
481
|
+
}
|
|
482
|
+
return this;
|
|
483
|
+
}
|
|
484
|
+
limit(limit) {
|
|
485
|
+
this.params.limit = limit;
|
|
486
|
+
return this;
|
|
487
|
+
}
|
|
488
|
+
offset(offset) {
|
|
489
|
+
this.params.offset = offset;
|
|
490
|
+
return this;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Start an OR where group
|
|
494
|
+
*/
|
|
495
|
+
orWhere(callback) {
|
|
496
|
+
return this.whereGroup('OR', callback);
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Start an AND where group
|
|
500
|
+
*/
|
|
501
|
+
andWhere(callback) {
|
|
502
|
+
return this.whereGroup('AND', callback);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Create a where group with the specified operator
|
|
506
|
+
*/
|
|
507
|
+
whereGroup(operator, callback) {
|
|
508
|
+
// Create a new builder for the group to collect clauses
|
|
509
|
+
const groupBuilder = new QueryBuilder(this.sdk, this.tableName);
|
|
510
|
+
// Execute the callback with the group builder to collect clauses
|
|
511
|
+
callback(groupBuilder);
|
|
512
|
+
// Create the where group with the collected clauses
|
|
513
|
+
const group = {
|
|
514
|
+
type: operator,
|
|
515
|
+
clauses: [],
|
|
516
|
+
};
|
|
517
|
+
// Add all whereRaw clauses to the group
|
|
518
|
+
if (groupBuilder.params.whereRaw &&
|
|
519
|
+
groupBuilder.params.whereRaw.length > 0) {
|
|
520
|
+
group.clauses.push(...groupBuilder.params.whereRaw);
|
|
521
|
+
}
|
|
522
|
+
// Add all where groups from the builder to our group
|
|
523
|
+
if (groupBuilder.params.whereGroups &&
|
|
524
|
+
groupBuilder.params.whereGroups.length > 0) {
|
|
525
|
+
group.clauses.push(...groupBuilder.params.whereGroups);
|
|
526
|
+
}
|
|
527
|
+
// Initialize the whereGroups array if it doesn't exist
|
|
528
|
+
if (!this.params.whereGroups) {
|
|
529
|
+
this.params.whereGroups = [];
|
|
530
|
+
}
|
|
531
|
+
// Add the group to whereGroups array
|
|
532
|
+
this.params.whereGroups.push(group);
|
|
533
|
+
return this;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Add a where exists clause using a subquery
|
|
537
|
+
* @param subqueryBuilder A function that returns a configured query builder for the subquery
|
|
538
|
+
* @returns The query builder instance
|
|
539
|
+
* @example
|
|
540
|
+
* db.table<User>("users")
|
|
541
|
+
* .whereExists((subquery) =>
|
|
542
|
+
* subquery.table("orders")
|
|
543
|
+
* .where("orders.user_id", "=", "users.id")
|
|
544
|
+
* .where("total", ">", 1000)
|
|
545
|
+
* )
|
|
546
|
+
* .execute();
|
|
547
|
+
*/
|
|
548
|
+
whereExists(subqueryBuilder) {
|
|
549
|
+
if (!this.params.whereExists) {
|
|
550
|
+
this.params.whereExists = [];
|
|
551
|
+
}
|
|
552
|
+
// Create a new SDK instance for the subquery
|
|
553
|
+
const subquerySdk = new DatabaseSDK({ baseUrl: this.sdk.getBaseUrl() });
|
|
554
|
+
// Get the subquery builder
|
|
555
|
+
const subquery = subqueryBuilder(subquerySdk);
|
|
556
|
+
// Extract the table name and parameters
|
|
557
|
+
this.params.whereExists.push({
|
|
558
|
+
tableName: subquery.getTableName(),
|
|
559
|
+
params: subquery.getParams(),
|
|
560
|
+
});
|
|
561
|
+
return this;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Add a where exists clause with join conditions
|
|
565
|
+
* @param tableName The table to check for existence
|
|
566
|
+
* @param leftField The field from the main table
|
|
567
|
+
* @param rightField The field from the subquery table
|
|
568
|
+
* @param additionalConditions Additional conditions for the subquery
|
|
569
|
+
* @returns The query builder instance
|
|
570
|
+
* @example
|
|
571
|
+
* db.table<User>("users")
|
|
572
|
+
* .whereExistsJoin("orders", "id", "user_id", (qb) =>
|
|
573
|
+
* qb.where("total", ">", 1000)
|
|
574
|
+
* )
|
|
575
|
+
* .execute();
|
|
576
|
+
*/
|
|
577
|
+
whereExistsJoin(tableName, leftField, rightField, additionalConditions) {
|
|
578
|
+
if (!this.params.whereExists) {
|
|
579
|
+
this.params.whereExists = [];
|
|
580
|
+
}
|
|
581
|
+
// Create a new SDK instance for the subquery
|
|
582
|
+
const subquerySdk = new DatabaseSDK({ baseUrl: this.sdk.getBaseUrl() });
|
|
583
|
+
// Build the subquery
|
|
584
|
+
const subQueryBuilder = subquerySdk.table(tableName);
|
|
585
|
+
// Apply additional conditions if provided
|
|
586
|
+
if (additionalConditions) {
|
|
587
|
+
additionalConditions(subQueryBuilder);
|
|
588
|
+
}
|
|
589
|
+
// Add the join condition
|
|
590
|
+
this.params.whereExists.push({
|
|
591
|
+
tableName,
|
|
592
|
+
params: subQueryBuilder.getParams(),
|
|
593
|
+
joinCondition: {
|
|
594
|
+
leftField: leftField,
|
|
595
|
+
operator: '=',
|
|
596
|
+
rightField,
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
601
|
+
// Helper methods for the whereExists functions
|
|
602
|
+
getTableName() {
|
|
603
|
+
return this.tableName;
|
|
604
|
+
}
|
|
605
|
+
getParams() {
|
|
606
|
+
return this.params;
|
|
607
|
+
}
|
|
608
|
+
// rawExpression method removed for security reasons
|
|
609
|
+
/**
|
|
610
|
+
* Group by clause
|
|
611
|
+
*/
|
|
612
|
+
groupBy(...fields) {
|
|
613
|
+
if (!this.params.groupBy) {
|
|
614
|
+
this.params.groupBy = [];
|
|
615
|
+
}
|
|
616
|
+
this.params.groupBy.push(...fields);
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Having clause for grouped queries
|
|
621
|
+
*/
|
|
622
|
+
having(field, operator, value) {
|
|
623
|
+
if (!this.params.having) {
|
|
624
|
+
this.params.having = [];
|
|
625
|
+
}
|
|
626
|
+
this.params.having.push({ field, operator, value });
|
|
627
|
+
return this;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Add an aggregate function
|
|
631
|
+
*/
|
|
632
|
+
aggregate(type, field, alias) {
|
|
633
|
+
if (!this.params.aggregates) {
|
|
634
|
+
this.params.aggregates = [];
|
|
635
|
+
}
|
|
636
|
+
this.params.aggregates.push({ type, field, alias });
|
|
637
|
+
return this;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Shorthand for count aggregate
|
|
641
|
+
*/
|
|
642
|
+
count(field = '*', alias) {
|
|
643
|
+
return this.aggregate('count', field, alias);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Shorthand for sum aggregate
|
|
647
|
+
*/
|
|
648
|
+
sum(field, alias) {
|
|
649
|
+
return this.aggregate('sum', field, alias);
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Shorthand for average aggregate
|
|
653
|
+
*/
|
|
654
|
+
avg(field, alias) {
|
|
655
|
+
return this.aggregate('avg', field, alias);
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Shorthand for minimum aggregate
|
|
659
|
+
*/
|
|
660
|
+
min(field, alias) {
|
|
661
|
+
return this.aggregate('min', field, alias);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Shorthand for maximum aggregate
|
|
665
|
+
*/
|
|
666
|
+
max(field, alias) {
|
|
667
|
+
return this.aggregate('max', field, alias);
|
|
668
|
+
}
|
|
669
|
+
// Get query parameters without executing
|
|
670
|
+
async toParams() {
|
|
671
|
+
const response = await this.sdk.getRecords(this.tableName, this.params, {
|
|
672
|
+
execute: false,
|
|
673
|
+
});
|
|
674
|
+
return response.params;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Execute with transformations
|
|
678
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
679
|
+
* @returns Promise with the query results
|
|
680
|
+
*/
|
|
681
|
+
async query(axiosConfig = {}) {
|
|
682
|
+
const response = await this.sdk.getRecords(this.tableName, this.params, { execute: true }, axiosConfig);
|
|
683
|
+
if (this.params.transforms && response.records) {
|
|
684
|
+
return this.applyTransformations(response);
|
|
685
|
+
}
|
|
686
|
+
return response;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Create a record in the table
|
|
690
|
+
* @param data The data to create
|
|
691
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
692
|
+
* @returns Promise with the created record
|
|
693
|
+
*/
|
|
694
|
+
async create(data, axiosConfig = {}) {
|
|
695
|
+
return this.sdk.createRecord(this.tableName, data, axiosConfig);
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Update a record by ID
|
|
699
|
+
* @param id The ID of the record to update
|
|
700
|
+
* @param data The data to update
|
|
701
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
702
|
+
* @returns Promise with the updated record
|
|
703
|
+
*/
|
|
704
|
+
async update(id, data, axiosConfig = {}) {
|
|
705
|
+
return this.sdk.updateRecord(this.tableName, id, data, axiosConfig);
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Update records by Complex query
|
|
709
|
+
* @param data The data to update
|
|
710
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
711
|
+
* @returns Promise with the deletion result
|
|
712
|
+
*/
|
|
713
|
+
async advanceUpdate(data, axiosConfig = {}) {
|
|
714
|
+
return this.sdk.advanceUpdateRecord(this.tableName, data, this.params, { execute: true }, axiosConfig);
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Delete a record by ID
|
|
718
|
+
* @param id The ID of the record to delete
|
|
719
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
720
|
+
* @returns Promise with the deletion result
|
|
721
|
+
*/
|
|
722
|
+
async delete(id, axiosConfig = {}) {
|
|
723
|
+
return this.sdk.deleteRecord(this.tableName, id, axiosConfig);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Delete records by Complex query
|
|
727
|
+
* @param axiosConfig Optional axios config to be used for this request
|
|
728
|
+
* @returns Promise with the deletion result
|
|
729
|
+
*/
|
|
730
|
+
async advanceDelete(axiosConfig = {}) {
|
|
731
|
+
return this.sdk.advanceDeleteRecord(this.tableName, this.params, { execute: true }, axiosConfig);
|
|
732
|
+
}
|
|
733
|
+
applyTransformations(response) {
|
|
734
|
+
let transformed = [...(response.records || [])];
|
|
735
|
+
const transforms = this.params.transforms;
|
|
736
|
+
// Apply computations
|
|
737
|
+
if (transforms.compute) {
|
|
738
|
+
transformed = transformed.map((row) => ({
|
|
739
|
+
...row,
|
|
740
|
+
...Object.entries(transforms.compute).reduce((acc, [key, fn]) => ({
|
|
741
|
+
...acc,
|
|
742
|
+
[key]: fn(row),
|
|
743
|
+
}), {}),
|
|
744
|
+
}));
|
|
745
|
+
}
|
|
746
|
+
// Apply grouping
|
|
747
|
+
if (transforms.groupBy) {
|
|
748
|
+
transformed = this.groupResults(transformed, transforms.groupBy);
|
|
749
|
+
}
|
|
750
|
+
// Apply pivoting
|
|
751
|
+
if (transforms.pivot) {
|
|
752
|
+
transformed = this.pivotResults(transformed, transforms.pivot);
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
...response,
|
|
756
|
+
records: transformed,
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
groupResults(records, groupBy) {
|
|
760
|
+
// Implementation of grouping logic
|
|
761
|
+
return records;
|
|
762
|
+
}
|
|
763
|
+
pivotResults(records, pivot) {
|
|
764
|
+
// Implementation of pivot logic
|
|
765
|
+
return records;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Select specific fields from the table
|
|
769
|
+
* @param fields Fields to select
|
|
770
|
+
* @example
|
|
771
|
+
* db.table("users")
|
|
772
|
+
* .select("id", "name", "email")
|
|
773
|
+
* .execute();
|
|
774
|
+
*/
|
|
775
|
+
select(...fields) {
|
|
776
|
+
if (!this.params.select) {
|
|
777
|
+
this.params.select = [];
|
|
778
|
+
}
|
|
779
|
+
this.params.select.push(...fields);
|
|
780
|
+
return this;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
// Example usage functions
|
|
784
|
+
// function demonstrateComplexQueries() {
|
|
785
|
+
// const db = new DatabaseSDK("https://api.example.com");
|
|
786
|
+
// // Complex grouped conditions
|
|
787
|
+
// db.table<User>("users")
|
|
788
|
+
// .where("status", "active")
|
|
789
|
+
// .andWhere((query) => {
|
|
790
|
+
// query.where("role", "admin").orWhere((subQuery) => {
|
|
791
|
+
// subQuery.where("role", "manager").where("department", "IT");
|
|
792
|
+
// });
|
|
793
|
+
// })
|
|
794
|
+
// .query();
|
|
795
|
+
// // Using exists with raw SQL
|
|
796
|
+
// db.table<Order>("orders")
|
|
797
|
+
// .whereExists(
|
|
798
|
+
// "SELECT 1 FROM order_items WHERE order_items.order_id = orders.id AND quantity > ?",
|
|
799
|
+
// [10]
|
|
800
|
+
// )
|
|
801
|
+
// .query();
|
|
802
|
+
// // Aggregations with grouping
|
|
803
|
+
// db.table<Order>("orders")
|
|
804
|
+
// .groupBy("customer_id", "status")
|
|
805
|
+
// .having("total_amount", ">", 1000)
|
|
806
|
+
// .sum("amount", "total_amount")
|
|
807
|
+
// .count("id", "order_count")
|
|
808
|
+
// .avg("amount", "average_amount")
|
|
809
|
+
// .query();
|
|
810
|
+
// // Raw expressions removed for security reasons
|
|
811
|
+
// }
|
|
812
|
+
//# sourceMappingURL=client.js.map
|