@oneuptime/common 7.0.4358 → 7.0.4395

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 (83) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +0 -7
  2. package/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts +0 -13
  3. package/Models/AnalyticsModels/ExceptionInstance.ts +2 -2
  4. package/Models/DatabaseModels/Monitor.ts +1 -1
  5. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.ts +2 -2
  6. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.ts +2 -2
  7. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.ts +2 -2
  8. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +2 -2
  9. package/Models/DatabaseModels/Probe.ts +7 -1
  10. package/Models/DatabaseModels/ServiceCatalog.ts +2 -2
  11. package/Models/DatabaseModels/ServiceCopilotCodeRepository.ts +2 -2
  12. package/Server/Middleware/ProjectAuthorization.ts +11 -3
  13. package/Server/Services/OpenTelemetryIngestService.ts +13 -9
  14. package/Server/Utils/AnalyticsDatabase/Statement.ts +0 -1
  15. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +28 -81
  16. package/Server/Utils/OpenAPI.ts +605 -16
  17. package/Server/Utils/StartServer.ts +2 -2
  18. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +0 -49
  19. package/Types/AnalyticsDatabase/TableColumn.ts +0 -26
  20. package/Types/AnalyticsDatabase/TableColumnType.ts +2 -1
  21. package/Types/Database/TableColumnType.ts +3 -0
  22. package/Types/GenericFunction.ts +1 -1
  23. package/Types/GenericObject.ts +1 -1
  24. package/Types/Object.ts +1 -1
  25. package/UI/esbuild-config.js +214 -0
  26. package/Utils/Schema/AnalyticsModelSchema.ts +741 -0
  27. package/Utils/Schema/BaseSchema.ts +450 -0
  28. package/Utils/Schema/ModelSchema.ts +227 -460
  29. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +0 -6
  30. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
  31. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js +0 -9
  32. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js.map +1 -1
  33. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +2 -2
  34. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  35. package/build/dist/Models/DatabaseModels/Monitor.js +1 -1
  36. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  37. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js +2 -2
  38. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js.map +1 -1
  39. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js +2 -2
  40. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js.map +1 -1
  41. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js +2 -2
  42. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js.map +1 -1
  43. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +2 -2
  44. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  45. package/build/dist/Models/DatabaseModels/Probe.js +7 -1
  46. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  47. package/build/dist/Models/DatabaseModels/ServiceCatalog.js +2 -2
  48. package/build/dist/Models/DatabaseModels/ServiceCatalog.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js +2 -2
  50. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js.map +1 -1
  51. package/build/dist/Server/Middleware/ProjectAuthorization.js +7 -3
  52. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  53. package/build/dist/Server/Services/OpenTelemetryIngestService.js +8 -4
  54. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  55. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +0 -1
  56. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  57. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +15 -55
  58. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  59. package/build/dist/Server/Utils/OpenAPI.js +467 -12
  60. package/build/dist/Server/Utils/OpenAPI.js.map +1 -1
  61. package/build/dist/Server/Utils/StartServer.js +2 -2
  62. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  63. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +0 -43
  64. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +1 -1
  65. package/build/dist/Types/AnalyticsDatabase/TableColumn.js +0 -19
  66. package/build/dist/Types/AnalyticsDatabase/TableColumn.js.map +1 -1
  67. package/build/dist/Types/AnalyticsDatabase/TableColumnType.js +2 -1
  68. package/build/dist/Types/AnalyticsDatabase/TableColumnType.js.map +1 -1
  69. package/build/dist/Types/Database/TableColumnType.js +3 -0
  70. package/build/dist/Types/Database/TableColumnType.js.map +1 -1
  71. package/build/dist/Utils/Schema/AnalyticsModelSchema.js +619 -0
  72. package/build/dist/Utils/Schema/AnalyticsModelSchema.js.map +1 -0
  73. package/build/dist/Utils/Schema/BaseSchema.js +295 -0
  74. package/build/dist/Utils/Schema/BaseSchema.js.map +1 -0
  75. package/build/dist/Utils/Schema/ModelSchema.js +207 -390
  76. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  77. package/package.json +3 -1
  78. package/Models/AnalyticsModels/AnalyticsBaseModel/NestedModel.ts +0 -8
  79. package/Models/AnalyticsModels/NestedModels/KeyValueNestedModel.ts +0 -59
  80. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/NestedModel.js +0 -7
  81. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/NestedModel.js.map +0 -1
  82. package/build/dist/Models/AnalyticsModels/NestedModels/KeyValueNestedModel.js +0 -51
  83. package/build/dist/Models/AnalyticsModels/NestedModels/KeyValueNestedModel.js.map +0 -1
@@ -0,0 +1,741 @@
1
+ import z, { ZodSchema } from "./Zod";
2
+ import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
3
+ import AnalyticsTableColumn from "../../Types/AnalyticsDatabase/TableColumn";
4
+ import AnalyticsBaseModel from "../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
5
+ import logger from "../../Server/Utils/Logger";
6
+ import { z as ZodTypes } from "zod";
7
+ import { BaseSchema, SchemaExample, ShapeRecord } from "./BaseSchema";
8
+ import IP from "../../Types/IP/IP";
9
+ import Port from "../../Types/Port";
10
+
11
+ export type AnalyticsModelSchemaType = ZodSchema;
12
+
13
+ export class AnalyticsModelSchema extends BaseSchema {
14
+ public static getModelSchema(data: {
15
+ modelType: new () => AnalyticsBaseModel;
16
+ }): AnalyticsModelSchemaType {
17
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
18
+ const model: AnalyticsBaseModel = new modelType();
19
+
20
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
21
+
22
+ // Filter out columns with no read permissions
23
+ const filteredColumns: Array<AnalyticsTableColumn> = columns.filter(
24
+ (column: AnalyticsTableColumn) => {
25
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
26
+ if (!accessControl) {
27
+ return false;
28
+ }
29
+ const readPermissions: Array<string> = accessControl.read;
30
+ return readPermissions && readPermissions.length > 0;
31
+ },
32
+ );
33
+
34
+ const shape: ShapeRecord = {};
35
+
36
+ for (const column of filteredColumns) {
37
+ const key: string = column.key;
38
+ let zodType: ZodTypes.ZodTypeAny;
39
+
40
+ if (column.type === TableColumnType.ObjectID) {
41
+ zodType = z.string().openapi({
42
+ type: "string",
43
+ example: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
44
+ });
45
+ } else if (column.type === TableColumnType.Date) {
46
+ zodType = z.date().openapi({
47
+ type: "string",
48
+ format: "date-time",
49
+ example: "2023-01-15T12:30:00.000Z",
50
+ });
51
+ } else if (column.type === TableColumnType.Text) {
52
+ zodType = z.string().openapi({
53
+ type: "string",
54
+ example: "Example text value",
55
+ });
56
+ } else if (column.type === TableColumnType.Number) {
57
+ zodType = z.number().openapi({ type: "number", example: 42 });
58
+ } else if (column.type === TableColumnType.LongNumber) {
59
+ zodType = z.number().openapi({
60
+ type: "number",
61
+ example: 1000000,
62
+ });
63
+ } else if (column.type === TableColumnType.Boolean) {
64
+ zodType = z.boolean().openapi({ type: "boolean", example: true });
65
+ } else if (column.type === TableColumnType.JSON) {
66
+ zodType = z.any().openapi({
67
+ type: "object",
68
+ example: { key: "value", nested: { data: 123 } },
69
+ });
70
+ } else if (column.type === TableColumnType.JSONArray) {
71
+ zodType = z.array(z.any()).openapi({
72
+ type: "array",
73
+ items: {
74
+ type: "object",
75
+ },
76
+ example: [{ key: "value" }, { key2: "value2" }],
77
+ });
78
+ } else if (column.type === TableColumnType.Decimal) {
79
+ zodType = z.number().openapi({
80
+ type: "number",
81
+ example: 123.45,
82
+ });
83
+ } else if (column.type === TableColumnType.ArrayNumber) {
84
+ zodType = z.array(z.number()).openapi({
85
+ type: "array",
86
+ items: {
87
+ type: "number",
88
+ },
89
+ example: [1, 2, 3, 4, 5],
90
+ });
91
+ } else if (column.type === TableColumnType.ArrayText) {
92
+ zodType = z.array(z.string()).openapi({
93
+ type: "array",
94
+ items: {
95
+ type: "string",
96
+ },
97
+ example: ["item1", "item2", "item3"],
98
+ });
99
+ } else if (column.type === TableColumnType.IP) {
100
+ zodType = IP.getSchema();
101
+ } else if (column.type === TableColumnType.Port) {
102
+ zodType = Port.getSchema();
103
+ } else {
104
+ // Default fallback
105
+ zodType = z.any().openapi({
106
+ type: "string",
107
+ example: "example_value",
108
+ });
109
+ }
110
+
111
+ if (column.required) {
112
+ // leave as is
113
+ } else {
114
+ zodType = zodType.optional();
115
+ }
116
+
117
+ // Add title and description to the schema
118
+ if (column.title) {
119
+ zodType = zodType.describe(column.title);
120
+ }
121
+
122
+ shape[key] = zodType;
123
+ }
124
+
125
+ const schema: AnalyticsModelSchemaType = z.object(shape);
126
+
127
+ logger.debug(
128
+ `Analytics model schema for ${model.tableName} created with shape keys: ${Object.keys(shape).join(", ")} (filtered ${columns.length - filteredColumns.length} columns without read permissions)`,
129
+ );
130
+
131
+ return schema;
132
+ }
133
+
134
+ private static getZodTypeForColumn(
135
+ column: AnalyticsTableColumn,
136
+ ): ZodTypes.ZodTypeAny {
137
+ switch (column.type) {
138
+ case TableColumnType.ObjectID:
139
+ return z.string().openapi({
140
+ type: "string",
141
+ example: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
142
+ });
143
+ case TableColumnType.Date:
144
+ return z.date().openapi({
145
+ type: "string",
146
+ format: "date-time",
147
+ example: "2023-01-15T12:30:00.000Z",
148
+ });
149
+ case TableColumnType.Text:
150
+ return z.string().openapi({
151
+ type: "string",
152
+ example: "Example text",
153
+ });
154
+ case TableColumnType.Number:
155
+ return z.number().openapi({ type: "number", example: 42 });
156
+ case TableColumnType.LongNumber:
157
+ return z.number().openapi({
158
+ type: "number",
159
+ example: 1000000,
160
+ });
161
+ case TableColumnType.Boolean:
162
+ return z.boolean().openapi({ type: "boolean", example: true });
163
+ case TableColumnType.JSON:
164
+ return z.any().openapi({
165
+ type: "object",
166
+ example: { key: "value" },
167
+ });
168
+ case TableColumnType.JSONArray:
169
+ return z.array(z.any()).openapi({
170
+ type: "array",
171
+ items: { type: "object" },
172
+ example: [{ key: "value" }],
173
+ });
174
+ case TableColumnType.Decimal:
175
+ return z.number().openapi({
176
+ type: "number",
177
+ example: 123.45,
178
+ });
179
+ case TableColumnType.ArrayNumber:
180
+ return z.array(z.number()).openapi({
181
+ type: "array",
182
+ items: { type: "number" },
183
+ example: [1, 2, 3],
184
+ });
185
+ case TableColumnType.ArrayText:
186
+ return z.array(z.string()).openapi({
187
+ type: "array",
188
+ items: { type: "string" },
189
+ example: ["item1", "item2"],
190
+ });
191
+ case TableColumnType.IP:
192
+ return IP.getSchema();
193
+ case TableColumnType.Port:
194
+ return Port.getSchema();
195
+ default:
196
+ return z.any().openapi({
197
+ type: "string",
198
+ example: "example_value",
199
+ });
200
+ }
201
+ }
202
+
203
+ public static getCreateModelSchema(data: {
204
+ modelType: new () => AnalyticsBaseModel;
205
+ }): AnalyticsModelSchemaType {
206
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
207
+ const model: AnalyticsBaseModel = new modelType();
208
+
209
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
210
+ const shape: ShapeRecord = {};
211
+
212
+ // Exclude system fields from create schema
213
+ const excludedFields: Array<string> = ["_id", "createdAt", "updatedAt"];
214
+
215
+ for (const column of columns) {
216
+ const key: string = column.key;
217
+
218
+ if (excludedFields.includes(key)) {
219
+ continue;
220
+ }
221
+
222
+ // Skip default value columns in create schema
223
+ if (column.isDefaultValueColumn) {
224
+ continue;
225
+ }
226
+
227
+ // Filter out columns with no create permissions
228
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
229
+ if (!accessControl) {
230
+ continue;
231
+ }
232
+ const createPermissions: Array<string> = accessControl.create;
233
+ if (!createPermissions || createPermissions.length === 0) {
234
+ continue;
235
+ }
236
+
237
+ const zodType: ZodTypes.ZodTypeAny = this.getZodTypeForColumn(column);
238
+
239
+ if (column.required) {
240
+ shape[key] = zodType;
241
+ } else {
242
+ shape[key] = zodType.optional();
243
+ }
244
+ }
245
+
246
+ return z.object(shape).openapi({
247
+ type: "object",
248
+ description: `Create schema for ${model.tableName || "analytics model"}`,
249
+ example: this.getCreateSchemaExample(modelType),
250
+ additionalProperties: false,
251
+ });
252
+ }
253
+
254
+ public static getQueryModelSchema(data: {
255
+ modelType: new () => AnalyticsBaseModel;
256
+ }): AnalyticsModelSchemaType {
257
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
258
+ const model: AnalyticsBaseModel = new modelType();
259
+
260
+ return this.generateQuerySchema({
261
+ model,
262
+ tableName: model.tableName || "analytics_model",
263
+ getColumns: (model: AnalyticsBaseModel) => {
264
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
265
+ return columns.map((column: AnalyticsTableColumn) => {
266
+ return { key: column.key, type: column.type };
267
+ });
268
+ },
269
+ getValidOperatorsForColumnType: (columnType: TableColumnType) => {
270
+ return this.getValidOperatorsForColumnType(columnType);
271
+ },
272
+ getOperatorSchema: (
273
+ operatorType: string,
274
+ columnType: TableColumnType,
275
+ ) => {
276
+ return this.getOperatorSchema(operatorType, columnType);
277
+ },
278
+ getQuerySchemaExample: () => {
279
+ return this.getQuerySchemaExample(modelType);
280
+ },
281
+ getExampleValueForColumn: (columnType: TableColumnType) => {
282
+ return this.getExampleValueForColumn(columnType);
283
+ },
284
+ });
285
+ }
286
+
287
+ public static getSelectModelSchema(data: {
288
+ modelType: new () => AnalyticsBaseModel;
289
+ }): AnalyticsModelSchemaType {
290
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
291
+ const model: AnalyticsBaseModel = new modelType();
292
+
293
+ return this.generateSelectSchema({
294
+ model,
295
+ tableName: model.tableName || "analytics_model",
296
+ getColumns: (model: AnalyticsBaseModel) => {
297
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
298
+ return columns.map((column: AnalyticsTableColumn) => {
299
+ return { key: column.key, type: column.type };
300
+ });
301
+ },
302
+ getSelectSchemaExample: () => {
303
+ return this.getSelectSchemaExample(modelType);
304
+ },
305
+ });
306
+ }
307
+
308
+ public static getSortModelSchema(data: {
309
+ modelType: new () => AnalyticsBaseModel;
310
+ }): AnalyticsModelSchemaType {
311
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
312
+ const model: AnalyticsBaseModel = new modelType();
313
+
314
+ return this.generateSortSchema({
315
+ model,
316
+ tableName: model.tableName || "analytics_model",
317
+ getSortableTypes: () => {
318
+ return this.getSortableTypes();
319
+ },
320
+ getColumnsForSorting: (model: AnalyticsBaseModel) => {
321
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
322
+ return columns.map((column: AnalyticsTableColumn) => {
323
+ return { key: column.key, type: column.type };
324
+ });
325
+ },
326
+ });
327
+ }
328
+
329
+ public static getGroupByModelSchema(data: {
330
+ modelType: new () => AnalyticsBaseModel;
331
+ }): AnalyticsModelSchemaType {
332
+ const modelType: new () => AnalyticsBaseModel = data.modelType;
333
+ const model: AnalyticsBaseModel = new modelType();
334
+
335
+ return this.generateGroupBySchema({
336
+ model,
337
+ tableName: model.tableName || "analytics_model",
338
+ getColumns: (model: AnalyticsBaseModel) => {
339
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
340
+ return columns.map((column: AnalyticsTableColumn) => {
341
+ return { key: column.key, type: column.type };
342
+ });
343
+ },
344
+ getGroupableTypes: () => {
345
+ return [
346
+ TableColumnType.Text,
347
+ TableColumnType.ObjectID,
348
+ TableColumnType.Boolean,
349
+ TableColumnType.Date,
350
+ TableColumnType.Number,
351
+ TableColumnType.IP,
352
+ TableColumnType.Port,
353
+ ];
354
+ },
355
+ getGroupBySchemaExample: () => {
356
+ return this.getGroupBySchemaExample(modelType);
357
+ },
358
+ });
359
+ }
360
+
361
+ private static getSortableTypes(): Array<TableColumnType> {
362
+ return [
363
+ TableColumnType.Text,
364
+ TableColumnType.Number,
365
+ TableColumnType.LongNumber,
366
+ TableColumnType.Date,
367
+ TableColumnType.Boolean,
368
+ TableColumnType.ObjectID,
369
+ TableColumnType.Decimal,
370
+ TableColumnType.IP,
371
+ TableColumnType.Port,
372
+ ];
373
+ }
374
+
375
+ private static getValidOperatorsForColumnType(
376
+ columnType: TableColumnType,
377
+ ): Array<string> {
378
+ switch (columnType) {
379
+ case TableColumnType.Text:
380
+ return ["EqualTo", "NotEqual", "Search", "IsNull", "NotNull"];
381
+ case TableColumnType.Number:
382
+ case TableColumnType.LongNumber:
383
+ case TableColumnType.Decimal:
384
+ return [
385
+ "EqualTo",
386
+ "NotEqual",
387
+ "GreaterThan",
388
+ "LessThan",
389
+ "GreaterThanOrEqual",
390
+ "LessThanOrEqual",
391
+ "IsNull",
392
+ "NotNull",
393
+ ];
394
+ case TableColumnType.Date:
395
+ return [
396
+ "EqualTo",
397
+ "NotEqual",
398
+ "GreaterThan",
399
+ "LessThan",
400
+ "GreaterThanOrEqual",
401
+ "LessThanOrEqual",
402
+ "IsNull",
403
+ "NotNull",
404
+ ];
405
+ case TableColumnType.Boolean:
406
+ return ["EqualTo", "NotEqual", "IsNull", "NotNull"];
407
+ case TableColumnType.ObjectID:
408
+ return ["EqualTo", "NotEqual", "IsNull", "NotNull"];
409
+ case TableColumnType.JSON:
410
+ case TableColumnType.JSONArray:
411
+ return ["IsNull", "NotNull"];
412
+ case TableColumnType.ArrayText:
413
+ case TableColumnType.ArrayNumber:
414
+ return ["IsNull", "NotNull"];
415
+ case TableColumnType.IP:
416
+ return ["EqualTo", "NotEqual", "IsNull", "NotNull"];
417
+ case TableColumnType.Port:
418
+ return [
419
+ "EqualTo",
420
+ "NotEqual",
421
+ "GreaterThan",
422
+ "LessThan",
423
+ "GreaterThanOrEqual",
424
+ "LessThanOrEqual",
425
+ "IsNull",
426
+ "NotNull",
427
+ ];
428
+ default:
429
+ return ["EqualTo", "NotEqual", "IsNull", "NotNull"];
430
+ }
431
+ }
432
+
433
+ private static getExampleValueForColumn(
434
+ columnType: TableColumnType,
435
+ ): unknown {
436
+ switch (columnType) {
437
+ case TableColumnType.ObjectID:
438
+ return "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
439
+ case TableColumnType.Text:
440
+ return "example text";
441
+ case TableColumnType.Number:
442
+ case TableColumnType.LongNumber:
443
+ return 42;
444
+ case TableColumnType.Decimal:
445
+ return 123.45;
446
+ case TableColumnType.Date:
447
+ return "2023-01-15T12:30:00.000Z";
448
+ case TableColumnType.Boolean:
449
+ return true;
450
+ case TableColumnType.JSON:
451
+ return { key: "value" };
452
+ case TableColumnType.JSONArray:
453
+ return [{ key: "value" }];
454
+ case TableColumnType.ArrayText:
455
+ return ["item1", "item2"];
456
+ case TableColumnType.ArrayNumber:
457
+ return [1, 2, 3];
458
+ case TableColumnType.IP:
459
+ return "192.168.1.1";
460
+ case TableColumnType.Port:
461
+ return 8080;
462
+ default:
463
+ return "example_value";
464
+ }
465
+ }
466
+
467
+ private static getCreateSchemaExample(
468
+ modelType: new () => AnalyticsBaseModel,
469
+ ): SchemaExample {
470
+ const model: AnalyticsBaseModel = new modelType();
471
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
472
+ const example: SchemaExample = {};
473
+
474
+ let exampleCount: number = 0;
475
+ const maxExamples: number = 3;
476
+
477
+ for (const column of columns) {
478
+ if (exampleCount >= maxExamples) {
479
+ break;
480
+ }
481
+
482
+ // Skip system fields and default value columns
483
+ if (
484
+ ["_id", "createdAt", "updatedAt"].includes(column.key) ||
485
+ column.isDefaultValueColumn
486
+ ) {
487
+ continue;
488
+ }
489
+
490
+ // Skip columns with no create permissions
491
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
492
+ if (!accessControl) {
493
+ continue;
494
+ }
495
+ const createPermissions: Array<string> = accessControl.create;
496
+ if (!createPermissions || createPermissions.length === 0) {
497
+ continue;
498
+ }
499
+
500
+ example[column.key] = this.getExampleValueForColumn(column.type);
501
+ exampleCount++;
502
+ }
503
+
504
+ return example;
505
+ }
506
+
507
+ private static getQuerySchemaExample(
508
+ modelType: new () => AnalyticsBaseModel,
509
+ ): SchemaExample {
510
+ const model: AnalyticsBaseModel = new modelType();
511
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
512
+ const example: SchemaExample = {};
513
+
514
+ let exampleCount: number = 0;
515
+ const maxExamples: number = 2;
516
+
517
+ for (const column of columns) {
518
+ if (exampleCount >= maxExamples) {
519
+ break;
520
+ }
521
+
522
+ // Check read permissions for query operations
523
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
524
+ if (
525
+ !accessControl ||
526
+ !accessControl.read ||
527
+ accessControl.read.length === 0
528
+ ) {
529
+ continue;
530
+ }
531
+
532
+ const validOperators: Array<string> = this.getValidOperatorsForColumnType(
533
+ column.type,
534
+ );
535
+ if (validOperators.length === 0) {
536
+ continue;
537
+ }
538
+
539
+ if (column.type === TableColumnType.Text) {
540
+ example[column.key] = {
541
+ _type: "EqualTo",
542
+ value: "example text",
543
+ };
544
+ exampleCount++;
545
+ } else if (column.type === TableColumnType.Date) {
546
+ example[column.key] = {
547
+ _type: "GreaterThan",
548
+ value: "2023-01-01T00:00:00.000Z",
549
+ };
550
+ exampleCount++;
551
+ }
552
+ }
553
+
554
+ return example;
555
+ }
556
+
557
+ private static getSelectSchemaExample(
558
+ modelType: new () => AnalyticsBaseModel,
559
+ ): SchemaExample {
560
+ const model: AnalyticsBaseModel = new modelType();
561
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
562
+
563
+ // Add common fields (only if they have read permissions)
564
+ const example: SchemaExample = {};
565
+
566
+ // Check if _id has read permissions
567
+ const idAccessControl: any = model.getColumnAccessControlFor("_id");
568
+ if (
569
+ idAccessControl &&
570
+ idAccessControl.read &&
571
+ idAccessControl.read.length > 0
572
+ ) {
573
+ example["_id"] = true;
574
+ }
575
+
576
+ // Check if createdAt has read permissions
577
+ const createdAtAccessControl: any =
578
+ model.getColumnAccessControlFor("createdAt");
579
+ if (
580
+ createdAtAccessControl &&
581
+ createdAtAccessControl.read &&
582
+ createdAtAccessControl.read.length > 0
583
+ ) {
584
+ example["createdAt"] = true;
585
+ }
586
+
587
+ // Add first few non-system fields with read permissions
588
+ let fieldCount: number = 0;
589
+ const maxFields: number = 3;
590
+
591
+ for (const column of columns) {
592
+ if (fieldCount >= maxFields) {
593
+ break;
594
+ }
595
+
596
+ if (!["_id", "createdAt", "updatedAt"].includes(column.key)) {
597
+ // Check read permissions
598
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
599
+ if (
600
+ accessControl &&
601
+ accessControl.read &&
602
+ accessControl.read.length > 0
603
+ ) {
604
+ example[column.key] = true;
605
+ fieldCount++;
606
+ }
607
+ }
608
+ }
609
+
610
+ return example;
611
+ }
612
+
613
+ private static getGroupBySchemaExample(
614
+ modelType: new () => AnalyticsBaseModel,
615
+ ): SchemaExample {
616
+ const model: AnalyticsBaseModel = new modelType();
617
+ const columns: Array<AnalyticsTableColumn> = model.getTableColumns();
618
+
619
+ // Find first suitable field for grouping with read permissions
620
+ for (const column of columns) {
621
+ const isGroupable: boolean = [
622
+ TableColumnType.Text,
623
+ TableColumnType.ObjectID,
624
+ TableColumnType.Boolean,
625
+ TableColumnType.Date,
626
+ TableColumnType.Number,
627
+ TableColumnType.IP,
628
+ TableColumnType.Port,
629
+ ].includes(column.type);
630
+
631
+ if (
632
+ isGroupable &&
633
+ !["_id", "createdAt", "updatedAt"].includes(column.key)
634
+ ) {
635
+ // Check read permissions
636
+ const accessControl: any = model.getColumnAccessControlFor(column.key);
637
+ if (
638
+ accessControl &&
639
+ accessControl.read &&
640
+ accessControl.read.length > 0
641
+ ) {
642
+ return { [column.key]: true };
643
+ }
644
+ }
645
+ }
646
+
647
+ // Fallback to createdAt if it has read permissions
648
+ const createdAtAccessControl: any =
649
+ model.getColumnAccessControlFor("createdAt");
650
+ if (
651
+ createdAtAccessControl &&
652
+ createdAtAccessControl.read &&
653
+ createdAtAccessControl.read.length > 0
654
+ ) {
655
+ return { ["createdAt"]: true };
656
+ }
657
+
658
+ // Final fallback - return empty object if no columns have read permissions
659
+ return {};
660
+ }
661
+
662
+ private static getOperatorSchema(
663
+ operatorType: string,
664
+ columnType: TableColumnType,
665
+ ): ZodTypes.ZodTypeAny {
666
+ const baseValue: ZodTypes.ZodTypeAny =
667
+ this.getBaseValueSchemaForColumnType(columnType);
668
+
669
+ switch (operatorType) {
670
+ case "EqualTo":
671
+ case "NotEqual":
672
+ return z.object({
673
+ _type: z.literal(operatorType),
674
+ value: baseValue,
675
+ });
676
+
677
+ case "GreaterThan":
678
+ case "LessThan":
679
+ case "GreaterThanOrEqual":
680
+ case "LessThanOrEqual":
681
+ return z.object({
682
+ _type: z.literal(operatorType),
683
+ value: baseValue,
684
+ });
685
+
686
+ case "Search":
687
+ return z.object({
688
+ _type: z.literal("Search"),
689
+ value: z.string(),
690
+ });
691
+
692
+ case "IsNull":
693
+ case "NotNull":
694
+ return z.object({
695
+ _type: z.literal(operatorType),
696
+ });
697
+
698
+ default:
699
+ return z.object({
700
+ _type: z.literal(operatorType),
701
+ value: baseValue.optional(),
702
+ });
703
+ }
704
+ }
705
+
706
+ private static getBaseValueSchemaForColumnType(
707
+ columnType: TableColumnType,
708
+ ): ZodTypes.ZodTypeAny {
709
+ switch (columnType) {
710
+ case TableColumnType.ObjectID:
711
+ case TableColumnType.Text:
712
+ return z.string();
713
+
714
+ case TableColumnType.Number:
715
+ case TableColumnType.LongNumber:
716
+ case TableColumnType.Decimal:
717
+ return z.number();
718
+
719
+ case TableColumnType.Date:
720
+ return z.date();
721
+
722
+ case TableColumnType.Boolean:
723
+ return z.boolean();
724
+
725
+ case TableColumnType.JSON:
726
+ case TableColumnType.JSONArray:
727
+ case TableColumnType.ArrayText:
728
+ case TableColumnType.ArrayNumber:
729
+ return z.any();
730
+
731
+ case TableColumnType.IP:
732
+ return IP.getSchema();
733
+
734
+ case TableColumnType.Port:
735
+ return Port.getSchema();
736
+
737
+ default:
738
+ return z.string();
739
+ }
740
+ }
741
+ }