@oneuptime/common 7.0.4358 → 7.0.4372

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/Models/AnalyticsModels/ExceptionInstance.ts +2 -2
  2. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.ts +2 -2
  3. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.ts +2 -2
  4. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.ts +2 -2
  5. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +2 -2
  6. package/Models/DatabaseModels/Probe.ts +7 -1
  7. package/Models/DatabaseModels/ServiceCatalog.ts +2 -2
  8. package/Models/DatabaseModels/ServiceCopilotCodeRepository.ts +2 -2
  9. package/Server/Utils/OpenAPI.ts +564 -2
  10. package/Utils/Schema/AnalyticsModelSchema.ts +764 -0
  11. package/Utils/Schema/BaseSchema.ts +450 -0
  12. package/Utils/Schema/ModelSchema.ts +176 -407
  13. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +2 -2
  14. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  15. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js +2 -2
  16. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js.map +1 -1
  17. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js +2 -2
  18. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js.map +1 -1
  19. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js +2 -2
  20. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js.map +1 -1
  21. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +2 -2
  22. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  23. package/build/dist/Models/DatabaseModels/Probe.js +7 -1
  24. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  25. package/build/dist/Models/DatabaseModels/ServiceCatalog.js +2 -2
  26. package/build/dist/Models/DatabaseModels/ServiceCatalog.js.map +1 -1
  27. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js +2 -2
  28. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js.map +1 -1
  29. package/build/dist/Server/Utils/OpenAPI.js +445 -2
  30. package/build/dist/Server/Utils/OpenAPI.js.map +1 -1
  31. package/build/dist/Utils/Schema/AnalyticsModelSchema.js +636 -0
  32. package/build/dist/Utils/Schema/AnalyticsModelSchema.js.map +1 -0
  33. package/build/dist/Utils/Schema/BaseSchema.js +295 -0
  34. package/build/dist/Utils/Schema/BaseSchema.js.map +1 -0
  35. package/build/dist/Utils/Schema/ModelSchema.js +155 -337
  36. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  37. package/package.json +1 -1
@@ -6,42 +6,22 @@ import {
6
6
  } from "../../Types/Database/TableColumn";
7
7
  import Dictionary from "../../Types/Dictionary";
8
8
  import DatabaseBaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
9
- import SortOrder from "../../Types/BaseDatabase/SortOrder";
10
9
  import logger from "../../Server/Utils/Logger";
11
10
  import Color from "../../Types/Color";
12
11
  import { z as ZodTypes } from "zod";
13
12
  import BadDataException from "../../Types/Exception/BadDataException";
14
13
  import Permission, { PermissionHelper } from "../../Types/Permission";
15
14
  import { ColumnAccessControl } from "../../Types/BaseDatabase/AccessControl";
15
+ import { BaseSchema, SchemaExample, ShapeRecord } from "./BaseSchema";
16
16
 
17
17
  export type ModelSchemaType = ZodSchema;
18
18
 
19
- // Type for schema examples
20
- type SchemaExample = Record<string, unknown>;
21
-
22
- // Type for operator examples in OpenAPI format
23
- type OperatorExample = {
24
- properties: Record<
25
- string,
26
- {
27
- type: string;
28
- enum?: string[];
29
- items?: { type: string };
30
- }
31
- >;
32
- required: string[];
33
- example: Record<string, unknown>;
34
- };
35
-
36
- // Type for shape objects using Zod's type inference
37
- type ShapeRecord = Record<string, ZodTypes.ZodTypeAny>;
38
-
39
19
  // Type for schema method functions
40
20
  type SchemaMethodFunction = (data: {
41
21
  modelType: new () => DatabaseBaseModel;
42
22
  }) => ModelSchemaType;
43
23
 
44
- export class ModelSchema {
24
+ export class ModelSchema extends BaseSchema {
45
25
  /**
46
26
  * Format permissions array into a human-readable string for OpenAPI documentation
47
27
  */
@@ -49,7 +29,7 @@ export class ModelSchema {
49
29
  permissions: Array<Permission> | undefined,
50
30
  ): string {
51
31
  if (!permissions || permissions.length === 0) {
52
- return "No permissions required";
32
+ return "No access - you don't have permission for this operation";
53
33
  }
54
34
 
55
35
  return PermissionHelper.getPermissionTitles(permissions).join(", ");
@@ -92,11 +72,29 @@ export class ModelSchema {
92
72
 
93
73
  const shape: ShapeRecord = {};
94
74
 
75
+ // Get column access control for permission filtering
76
+ const columnAccessControl: Dictionary<ColumnAccessControl> =
77
+ model.getColumnAccessControlForAllColumns();
78
+
95
79
  for (const key in columns) {
96
80
  const column: TableColumnMetadata | undefined = columns[key];
97
81
  if (!column) {
98
82
  continue;
99
83
  }
84
+
85
+ // Filter out columns with no permissions (root-only access)
86
+ const accessControl: ColumnAccessControl | undefined =
87
+ columnAccessControl[key];
88
+ if (accessControl) {
89
+ // Check if column has any permissions defined for read operation (general schema assumes read access)
90
+ const hasReadPermissions: boolean =
91
+ accessControl.read && accessControl.read.length > 0;
92
+
93
+ // If no read permissions are defined, exclude the column from general schema
94
+ if (!hasReadPermissions) {
95
+ continue;
96
+ }
97
+ }
100
98
  let zodType: ZodTypes.ZodTypeAny;
101
99
 
102
100
  if (column.type === TableColumnType.ObjectID) {
@@ -380,72 +378,36 @@ export class ModelSchema {
380
378
  const modelType: new () => DatabaseBaseModel = data.modelType;
381
379
  const model: DatabaseBaseModel = new modelType();
382
380
 
383
- const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
384
-
385
- const shape: ShapeRecord = {};
386
-
387
- for (const key in columns) {
388
- const column: TableColumnMetadata | undefined = columns[key];
389
- if (!column) {
390
- continue;
391
- }
392
-
393
- // Get valid operators for this column type
394
- const validOperators: Array<string> = this.getValidOperatorsForColumnType(
395
- column.type,
396
- );
397
-
398
- if (validOperators.length === 0) {
399
- continue;
400
- }
401
-
402
- // Create a union type of all valid operators for this column
403
- const operatorSchemas: Array<ZodTypes.ZodTypeAny> = validOperators.map(
404
- (operatorType: string) => {
405
- return this.getOperatorSchema(operatorType, column.type);
406
- },
407
- );
408
-
409
- let columnSchema: ZodTypes.ZodTypeAny;
410
- if (operatorSchemas.length === 1 && operatorSchemas[0]) {
411
- columnSchema = operatorSchemas[0].optional();
412
- } else if (operatorSchemas.length > 1) {
413
- columnSchema = z
414
- .union(
415
- operatorSchemas as [
416
- ZodTypes.ZodTypeAny,
417
- ZodTypes.ZodTypeAny,
418
- ...ZodTypes.ZodTypeAny[],
419
- ],
420
- )
421
- .optional();
422
- } else {
423
- // Fallback for empty operators array
424
- columnSchema = z.any().optional();
425
- }
426
-
427
- // Add OpenAPI documentation for query operators
428
- const operatorExamples: Array<OperatorExample> =
429
- this.getQueryOperatorExamples(column.type, validOperators);
430
- columnSchema = columnSchema.openapi({
431
- type: "object",
432
- description: `Query operators for ${key} field of type ${column.type}. Supported operators: ${validOperators.join(", ")}`,
433
- example:
434
- operatorExamples.length > 0 && operatorExamples[0]
435
- ? operatorExamples[0].example
436
- : {},
437
- });
438
-
439
- shape[key] = columnSchema;
440
- }
441
-
442
- const schema: ModelSchemaType = z.object(shape).openapi({
443
- type: "object",
444
- description: `Query schema for ${model.tableName || "model"} model. Each field can use various operators based on its data type.`,
445
- example: this.getQuerySchemaExample(modelType),
381
+ return this.generateQuerySchema({
382
+ model,
383
+ tableName: model.tableName || "model",
384
+ getColumns: (model: DatabaseBaseModel) => {
385
+ const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
386
+ return Object.keys(columns)
387
+ .map((key: string) => {
388
+ const column: TableColumnMetadata | undefined = columns[key];
389
+ return column ? { key, type: column.type } : null;
390
+ })
391
+ .filter((col: { key: string; type: any } | null) => {
392
+ return col !== null;
393
+ }) as Array<{ key: string; type: any }>;
394
+ },
395
+ getValidOperatorsForColumnType: (columnType: TableColumnType) => {
396
+ return this.getValidOperatorsForColumnType(columnType);
397
+ },
398
+ getOperatorSchema: (
399
+ operatorType: string,
400
+ columnType: TableColumnType,
401
+ ) => {
402
+ return this.getOperatorSchema(operatorType, columnType);
403
+ },
404
+ getQuerySchemaExample: () => {
405
+ return this.getQuerySchemaExample(modelType);
406
+ },
407
+ getExampleValueForColumn: (columnType: TableColumnType) => {
408
+ return this.getExampleValueForColumn(columnType);
409
+ },
446
410
  });
447
-
448
- return schema;
449
411
  }
450
412
 
451
413
  private static getValidOperatorsForColumnType(
@@ -658,40 +620,23 @@ export class ModelSchema {
658
620
  const modelType: new () => DatabaseBaseModel = data.modelType;
659
621
  const model: DatabaseBaseModel = new modelType();
660
622
 
661
- const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
662
-
663
- const shape: ShapeRecord = {};
664
-
665
- for (const key in columns) {
666
- const column: TableColumnMetadata | undefined = columns[key];
667
- if (!column) {
668
- continue;
669
- }
670
-
671
- const isSortable: boolean = ModelSchema.getSortableTypes().includes(
672
- column.type,
673
- );
674
-
675
- if (!isSortable) {
676
- continue;
677
- }
678
-
679
- shape[key] = z
680
- .enum([SortOrder.Ascending, SortOrder.Descending])
681
- .optional()
682
- .openapi({
683
- type: "string",
684
- enum: [SortOrder.Ascending, SortOrder.Descending],
685
- description: `Sort order for ${key} field`,
686
- example: SortOrder.Ascending,
687
- });
688
- }
689
-
690
- return z.object(shape).openapi({
691
- type: "object",
692
- description: `Sort schema for ${model.tableName || "model"} model. Only sortable fields are included.`,
693
- example: this.getSortSchemaExample(),
694
- additionalProperties: false,
623
+ return this.generateSortSchema({
624
+ model,
625
+ tableName: model.tableName || "model",
626
+ getSortableTypes: () => {
627
+ return this.getSortableTypes();
628
+ },
629
+ getColumnsForSorting: (model: DatabaseBaseModel) => {
630
+ const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
631
+ return Object.keys(columns)
632
+ .map((key: string) => {
633
+ const column: TableColumnMetadata | undefined = columns[key];
634
+ return column ? { key, type: column.type } : null;
635
+ })
636
+ .filter((col: { key: string; type: any } | null) => {
637
+ return col !== null;
638
+ }) as Array<{ key: string; type: any }>;
639
+ },
695
640
  });
696
641
  }
697
642
 
@@ -702,50 +647,40 @@ export class ModelSchema {
702
647
  const modelType: new () => DatabaseBaseModel = data.modelType;
703
648
  const model: DatabaseBaseModel = new modelType();
704
649
 
705
- const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
706
-
707
- const shape: ShapeRecord = {};
708
-
709
- for (const key in columns) {
710
- const column: TableColumnMetadata | undefined = columns[key];
711
- if (!column) {
712
- continue;
713
- }
714
-
715
- // if its entity array or entity then you can select nested properties
716
- if (
717
- !data.isNested &&
718
- column.modelType &&
719
- (column.type === TableColumnType.EntityArray ||
720
- column.type === TableColumnType.Entity)
721
- ) {
722
- // can only do one level of nesting
723
- shape[key] = this.getSelectModelSchema({
724
- modelType: column.modelType as new () => DatabaseBaseModel,
725
- isNested: true,
726
- }).openapi({
727
- type: "object",
728
- description: `Select fields for nested ${key} entity`,
729
- example: { id: true, name: true },
730
- });
731
- continue;
732
- }
733
-
734
- shape[key] = z
735
- .boolean()
736
- .optional()
737
- .openapi({
738
- type: "boolean",
739
- description: `Select ${key} field in the response`,
740
- example: true,
741
- });
742
- }
743
-
744
- return z.object(shape).openapi({
745
- type: "object",
746
- description: `Select schema for ${model.tableName || "model"} model. Set fields to true to include them in the response.`,
747
- example: this.getSelectSchemaExample(modelType),
748
- additionalProperties: false,
650
+ return this.generateSelectSchema({
651
+ model,
652
+ tableName: model.tableName || "model",
653
+ getColumns: (model: DatabaseBaseModel) => {
654
+ const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
655
+ return Object.keys(columns)
656
+ .map((key: string) => {
657
+ const column: TableColumnMetadata | undefined = columns[key];
658
+ return column ? { key, type: column.type } : null;
659
+ })
660
+ .filter((col: { key: string; type: any } | null) => {
661
+ return col !== null;
662
+ }) as Array<{ key: string; type?: any }>;
663
+ },
664
+ getSelectSchemaExample: () => {
665
+ return this.getSelectSchemaExample(modelType);
666
+ },
667
+ allowNested: !data.isNested,
668
+ getNestedSchema: (key: string, model: DatabaseBaseModel) => {
669
+ const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
670
+ const column: TableColumnMetadata | undefined = columns[key];
671
+ if (
672
+ column &&
673
+ column.modelType &&
674
+ (column.type === TableColumnType.EntityArray ||
675
+ column.type === TableColumnType.Entity)
676
+ ) {
677
+ return this.getSelectModelSchema({
678
+ modelType: column.modelType as new () => DatabaseBaseModel,
679
+ isNested: true,
680
+ });
681
+ }
682
+ return null;
683
+ },
749
684
  });
750
685
  }
751
686
 
@@ -755,244 +690,44 @@ export class ModelSchema {
755
690
  const modelType: new () => DatabaseBaseModel = data.modelType;
756
691
  const model: DatabaseBaseModel = new modelType();
757
692
 
758
- const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
759
-
760
- const shape: ShapeRecord = {};
761
-
762
- for (const key in columns) {
763
- const column: TableColumnMetadata | undefined = columns[key];
764
- if (!column) {
765
- continue;
766
- }
767
-
768
- // Only allow grouping by certain field types that make sense for aggregation
769
- const isGroupable: boolean = [
770
- TableColumnType.ShortText,
771
- TableColumnType.LongText,
772
- TableColumnType.Name,
773
- TableColumnType.Email,
774
- TableColumnType.Slug,
775
- TableColumnType.ObjectID,
776
- TableColumnType.Boolean,
777
- TableColumnType.Date,
778
- TableColumnType.Number,
779
- TableColumnType.PositiveNumber,
780
- TableColumnType.SmallNumber,
781
- TableColumnType.SmallPositiveNumber,
782
- TableColumnType.BigNumber,
783
- TableColumnType.BigPositiveNumber,
784
- ].includes(column.type);
785
-
786
- if (!isGroupable) {
787
- continue;
788
- }
789
-
790
- shape[key] = z
791
- .literal(true)
792
- .optional()
793
- .openapi({
794
- type: "boolean",
795
- description: `Group by ${key} field. Only one field can be selected for grouping.`,
796
- example: true,
797
- });
798
- }
799
-
800
- return z.object(shape).openapi({
801
- type: "object",
802
- description: `Group by schema for ${model.tableName || "model"} model. Only one field can be set to true for grouping.`,
803
- example: this.getGroupBySchemaExample(modelType),
804
- additionalProperties: false,
693
+ return this.generateGroupBySchema({
694
+ model,
695
+ tableName: model.tableName || "model",
696
+ getColumns: (model: DatabaseBaseModel) => {
697
+ const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
698
+ return Object.keys(columns)
699
+ .map((key: string) => {
700
+ const column: TableColumnMetadata | undefined = columns[key];
701
+ return column ? { key, type: column.type } : null;
702
+ })
703
+ .filter((col: { key: string; type: any } | null) => {
704
+ return col !== null;
705
+ }) as Array<{ key: string; type: any }>;
706
+ },
707
+ getGroupableTypes: () => {
708
+ return [
709
+ TableColumnType.ShortText,
710
+ TableColumnType.LongText,
711
+ TableColumnType.Name,
712
+ TableColumnType.Email,
713
+ TableColumnType.Slug,
714
+ TableColumnType.ObjectID,
715
+ TableColumnType.Boolean,
716
+ TableColumnType.Date,
717
+ TableColumnType.Number,
718
+ TableColumnType.PositiveNumber,
719
+ TableColumnType.SmallNumber,
720
+ TableColumnType.SmallPositiveNumber,
721
+ TableColumnType.BigNumber,
722
+ TableColumnType.BigPositiveNumber,
723
+ ];
724
+ },
725
+ getGroupBySchemaExample: () => {
726
+ return this.getGroupBySchemaExample(modelType);
727
+ },
805
728
  });
806
729
  }
807
730
 
808
- private static getQueryOperatorExamples(
809
- columnType: TableColumnType,
810
- validOperators: Array<string>,
811
- ): Array<OperatorExample> {
812
- const examples: Array<OperatorExample> = [];
813
-
814
- for (const operator of validOperators) {
815
- switch (operator) {
816
- case "EqualTo":
817
- examples.push({
818
- properties: {
819
- _type: { type: "string", enum: ["EqualTo"] },
820
- value: { type: this.getOpenAPITypeForColumn(columnType) },
821
- },
822
- required: ["_type", "value"],
823
- example: {
824
- _type: "EqualTo",
825
- value: this.getExampleValueForColumn(columnType),
826
- },
827
- });
828
- break;
829
- case "NotEqual":
830
- examples.push({
831
- properties: {
832
- _type: { type: "string", enum: ["NotEqual"] },
833
- value: { type: this.getOpenAPITypeForColumn(columnType) },
834
- },
835
- required: ["_type", "value"],
836
- example: {
837
- _type: "NotEqual",
838
- value: this.getExampleValueForColumn(columnType),
839
- },
840
- });
841
- break;
842
- case "Search":
843
- examples.push({
844
- properties: {
845
- _type: { type: "string", enum: ["Search"] },
846
- value: { type: "string" },
847
- },
848
- required: ["_type", "value"],
849
- example: { _type: "Search", value: "search term" },
850
- });
851
- break;
852
- case "GreaterThan":
853
- examples.push({
854
- properties: {
855
- _type: { type: "string", enum: ["GreaterThan"] },
856
- value: { type: this.getOpenAPITypeForColumn(columnType) },
857
- },
858
- required: ["_type", "value"],
859
- example: {
860
- _type: "GreaterThan",
861
- value: this.getExampleValueForColumn(columnType),
862
- },
863
- });
864
- break;
865
- case "LessThan":
866
- examples.push({
867
- properties: {
868
- _type: { type: "string", enum: ["LessThan"] },
869
- value: { type: this.getOpenAPITypeForColumn(columnType) },
870
- },
871
- required: ["_type", "value"],
872
- example: {
873
- _type: "LessThan",
874
- value: this.getExampleValueForColumn(columnType),
875
- },
876
- });
877
- break;
878
- case "GreaterThanOrEqual":
879
- examples.push({
880
- properties: {
881
- _type: { type: "string", enum: ["GreaterThanOrEqual"] },
882
- value: { type: this.getOpenAPITypeForColumn(columnType) },
883
- },
884
- required: ["_type", "value"],
885
- example: {
886
- _type: "GreaterThanOrEqual",
887
- value: this.getExampleValueForColumn(columnType),
888
- },
889
- });
890
- break;
891
- case "LessThanOrEqual":
892
- examples.push({
893
- properties: {
894
- _type: { type: "string", enum: ["LessThanOrEqual"] },
895
- value: { type: this.getOpenAPITypeForColumn(columnType) },
896
- },
897
- required: ["_type", "value"],
898
- example: {
899
- _type: "LessThanOrEqual",
900
- value: this.getExampleValueForColumn(columnType),
901
- },
902
- });
903
- break;
904
- case "EqualToOrNull":
905
- examples.push({
906
- properties: {
907
- _type: { type: "string", enum: ["EqualToOrNull"] },
908
- value: { type: this.getOpenAPITypeForColumn(columnType) },
909
- },
910
- required: ["_type", "value"],
911
- example: {
912
- _type: "EqualToOrNull",
913
- value: this.getExampleValueForColumn(columnType),
914
- },
915
- });
916
- break;
917
- case "InBetween":
918
- examples.push({
919
- properties: {
920
- _type: { type: "string", enum: ["InBetween"] },
921
- startValue: { type: this.getOpenAPITypeForColumn(columnType) },
922
- endValue: { type: this.getOpenAPITypeForColumn(columnType) },
923
- },
924
- required: ["_type", "startValue", "endValue"],
925
- example: {
926
- _type: "InBetween",
927
- startValue: this.getExampleValueForColumn(columnType),
928
- endValue: this.getExampleValueForColumn(columnType, true),
929
- },
930
- });
931
- break;
932
- case "IsNull":
933
- examples.push({
934
- properties: {
935
- _type: { type: "string", enum: ["IsNull"] },
936
- },
937
- required: ["_type"],
938
- example: { _type: "IsNull" },
939
- });
940
- break;
941
- case "NotNull":
942
- examples.push({
943
- properties: {
944
- _type: { type: "string", enum: ["NotNull"] },
945
- },
946
- required: ["_type"],
947
- example: { _type: "NotNull" },
948
- });
949
- break;
950
- case "Includes":
951
- examples.push({
952
- properties: {
953
- _type: { type: "string", enum: ["Includes"] },
954
- value: {
955
- type: "array",
956
- items: { type: this.getOpenAPITypeForColumn(columnType) },
957
- },
958
- },
959
- required: ["_type", "value"],
960
- example: {
961
- _type: "Includes",
962
- value: [
963
- this.getExampleValueForColumn(columnType),
964
- this.getExampleValueForColumn(columnType, true),
965
- ],
966
- },
967
- });
968
- break;
969
- }
970
- }
971
-
972
- return examples;
973
- }
974
-
975
- private static getOpenAPITypeForColumn(columnType: TableColumnType): string {
976
- switch (columnType) {
977
- case TableColumnType.Number:
978
- case TableColumnType.PositiveNumber:
979
- case TableColumnType.SmallNumber:
980
- case TableColumnType.SmallPositiveNumber:
981
- case TableColumnType.BigNumber:
982
- case TableColumnType.BigPositiveNumber:
983
- return "number";
984
- case TableColumnType.Boolean:
985
- return "boolean";
986
- case TableColumnType.Date:
987
- return "string";
988
- case TableColumnType.JSON:
989
- case TableColumnType.Array:
990
- return "object";
991
- default:
992
- return "string";
993
- }
994
- }
995
-
996
731
  private static getExampleValueForColumn(
997
732
  columnType: TableColumnType,
998
733
  isSecondValue: boolean = false,
@@ -1124,12 +859,6 @@ export class ModelSchema {
1124
859
  return example;
1125
860
  }
1126
861
 
1127
- private static getSortSchemaExample(): SchemaExample {
1128
- return {
1129
- createdAt: "Descending",
1130
- };
1131
- }
1132
-
1133
862
  private static getSelectSchemaExample(
1134
863
  modelType: new () => DatabaseBaseModel,
1135
864
  ): SchemaExample {
@@ -1257,6 +986,10 @@ export class ModelSchema {
1257
986
  const columns: Dictionary<TableColumnMetadata> = getTableColumns(model);
1258
987
  const shape: ShapeRecord = {};
1259
988
 
989
+ // Get column access control for permission filtering
990
+ const columnAccessControl: Dictionary<ColumnAccessControl> =
991
+ model.getColumnAccessControlForAllColumns();
992
+
1260
993
  for (const key in columns) {
1261
994
  const column: TableColumnMetadata | undefined = columns[key];
1262
995
  if (!column) {
@@ -1273,6 +1006,42 @@ export class ModelSchema {
1273
1006
  continue;
1274
1007
  }
1275
1008
 
1009
+ // Filter out columns with no permissions (root-only access)
1010
+ const accessControl: ColumnAccessControl | undefined =
1011
+ columnAccessControl[key];
1012
+ if (accessControl) {
1013
+ let hasPermissions: boolean = false;
1014
+
1015
+ // Check if column has any permissions defined for the current operation
1016
+ if (
1017
+ data.schemaType === "create" &&
1018
+ accessControl.create &&
1019
+ accessControl.create.length > 0
1020
+ ) {
1021
+ hasPermissions = true;
1022
+ } else if (
1023
+ data.schemaType === "read" &&
1024
+ accessControl.read &&
1025
+ accessControl.read.length > 0
1026
+ ) {
1027
+ hasPermissions = true;
1028
+ } else if (
1029
+ data.schemaType === "update" &&
1030
+ accessControl.update &&
1031
+ accessControl.update.length > 0
1032
+ ) {
1033
+ hasPermissions = true;
1034
+ } else if (data.schemaType === "delete") {
1035
+ // For delete operations, we don't filter by column permissions
1036
+ hasPermissions = true;
1037
+ }
1038
+
1039
+ // If no permissions are defined for this operation, exclude the column
1040
+ if (!hasPermissions) {
1041
+ continue;
1042
+ }
1043
+ }
1044
+
1276
1045
  let zodType: ZodTypes.ZodTypeAny = this.getZodTypeForColumn(
1277
1046
  column,
1278
1047
  key,
@@ -9,8 +9,8 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
9
9
  super({
10
10
  tableName: "ExceptionItem",
11
11
  tableEngine: AnalyticsTableEngine.MergeTree,
12
- singularName: "Exception",
13
- pluralName: "Exceptions",
12
+ singularName: "Exception Instance",
13
+ pluralName: "Exception Instances",
14
14
  enableRealtimeEventsOn: {
15
15
  create: true,
16
16
  },