@loomcore/api 0.1.85 → 0.1.86

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 (32) hide show
  1. package/dist/__tests__/models/product.model.d.ts +3 -2
  2. package/dist/__tests__/models/product.model.js +1 -1
  3. package/dist/__tests__/postgres-test-migrations/postgres-test-schema.js +5 -5
  4. package/dist/databases/operations/__tests__/models/test-agent.model.d.ts +15 -15
  5. package/dist/databases/operations/__tests__/models/test-agent.model.js +2 -2
  6. package/dist/databases/operations/__tests__/models/test-client-report.model.d.ts +44 -44
  7. package/dist/databases/operations/__tests__/models/test-client-report.model.js +2 -2
  8. package/dist/databases/operations/__tests__/models/test-district.model.d.ts +2 -2
  9. package/dist/databases/operations/__tests__/models/test-district.model.js +1 -1
  10. package/dist/databases/operations/__tests__/models/test-email-address.model.d.ts +6 -6
  11. package/dist/databases/operations/__tests__/models/test-email-address.model.js +3 -3
  12. package/dist/databases/operations/__tests__/models/test-person.model.d.ts +16 -16
  13. package/dist/databases/operations/__tests__/models/test-person.model.js +5 -5
  14. package/dist/databases/operations/__tests__/models/test-phone-number.model.d.ts +6 -6
  15. package/dist/databases/operations/__tests__/models/test-phone-number.model.js +3 -3
  16. package/dist/databases/operations/__tests__/models/test-policy.model.d.ts +18 -18
  17. package/dist/databases/operations/__tests__/models/test-policy.model.js +2 -2
  18. package/dist/databases/operations/__tests__/models/test-premium.model.d.ts +2 -2
  19. package/dist/databases/operations/__tests__/models/test-premium.model.js +1 -1
  20. package/dist/databases/operations/__tests__/models/test-school.model.d.ts +2 -2
  21. package/dist/databases/operations/__tests__/models/test-school.model.js +1 -1
  22. package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +3 -0
  23. package/dist/databases/postgres/migrations/postgres-initial-schema.js +49 -49
  24. package/dist/databases/postgres/postgres.database.js +11 -9
  25. package/dist/databases/postgres/utils/build-join-clauses.js +25 -5
  26. package/dist/databases/postgres/utils/build-where-clause.js +12 -1
  27. package/dist/databases/postgres/utils/columns-and-values-from-entity.js +4 -2
  28. package/dist/databases/postgres/utils/convert-keys.util.d.ts +4 -0
  29. package/dist/databases/postgres/utils/convert-keys.util.js +85 -0
  30. package/dist/databases/postgres/utils/convert-null-to-undefined.util.js +5 -3
  31. package/dist/services/user.service.js +3 -3
  32. package/package.json +1 -1
@@ -1,17 +1,18 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  import { ICategory } from "./category.model.js";
3
+ import { AppIdType } from "@loomcore/common/types";
3
4
  export interface IProduct extends IEntity, IAuditable {
4
5
  name: string;
5
6
  description?: string;
6
7
  internalNumber?: string;
7
- categoryId: string;
8
+ categoryId: AppIdType;
8
9
  category?: ICategory;
9
10
  }
10
11
  export declare const ProductSchema: import("@sinclair/typebox").TObject<{
11
12
  name: import("@sinclair/typebox").TString;
12
13
  description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
13
14
  internalNumber: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
- categoryId: import("@sinclair/typebox").TString;
15
+ categoryId: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNumber]>;
15
16
  }>;
16
17
  export declare const ProductSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
17
18
  export declare const PublicProductSchema: import("@sinclair/typebox").TObject<{}>;
@@ -4,7 +4,7 @@ export const ProductSchema = Type.Object({
4
4
  name: Type.String(),
5
5
  description: Type.Optional(Type.String()),
6
6
  internalNumber: Type.Optional(Type.String()),
7
- categoryId: Type.String({ title: 'Category ID' }),
7
+ categoryId: Type.Union([Type.String({ title: 'Category ID' }), Type.Number({ title: 'Category ID' })]),
8
8
  });
9
9
  export const ProductSpec = entityUtils.getModelSpec(ProductSchema, { isAuditable: true });
10
10
  export const PublicProductSchema = Type.Omit(ProductSpec.fullSchema, ['internalNumber']);
@@ -11,7 +11,7 @@ export const getPostgresTestSchema = (config) => {
11
11
  ${orgColumnDef}
12
12
  "name" VARCHAR(255) NOT NULL,
13
13
  "description" TEXT,
14
- "isActive" BOOLEAN,
14
+ "is_active" BOOLEAN,
15
15
  "tags" TEXT[],
16
16
  "count" INTEGER,
17
17
  "_created" TIMESTAMPTZ NOT NULL,
@@ -53,15 +53,15 @@ export const getPostgresTestSchema = (config) => {
53
53
  ${orgColumnDef}
54
54
  "name" VARCHAR(255) NOT NULL,
55
55
  "description" TEXT,
56
- "internalNumber" VARCHAR(255),
57
- "categoryId" INTEGER NOT NULL,
56
+ "internal_number" VARCHAR(255),
57
+ "category_id" INTEGER NOT NULL,
58
58
  "_created" TIMESTAMPTZ NOT NULL,
59
59
  "_createdBy" INTEGER NOT NULL,
60
60
  "_updated" TIMESTAMPTZ NOT NULL,
61
61
  "_updatedBy" INTEGER NOT NULL,
62
62
  "_deleted" TIMESTAMPTZ,
63
63
  "_deletedBy" INTEGER,
64
- CONSTRAINT "fk_products_category" FOREIGN KEY ("categoryId") REFERENCES "categories"("_id") ON DELETE CASCADE
64
+ CONSTRAINT "fk_products_category" FOREIGN KEY ("category_id") REFERENCES "categories"("_id") ON DELETE CASCADE
65
65
  )
66
66
  `);
67
67
  },
@@ -79,7 +79,7 @@ export const getPostgresTestSchema = (config) => {
79
79
  ${orgColumnDef}
80
80
  "name" VARCHAR(255) NOT NULL,
81
81
  "value" INTEGER,
82
- "eventDate" TIMESTAMPTZ,
82
+ "event_date" TIMESTAMPTZ,
83
83
  "_created" TIMESTAMPTZ NOT NULL,
84
84
  "_createdBy" INTEGER NOT NULL,
85
85
  "_updated" TIMESTAMPTZ NOT NULL,
@@ -1,24 +1,24 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  import { ITestPersonModel } from "./test-person.model.js";
3
3
  export interface ITestAgentModel extends IEntity, IAuditable {
4
- person_id: number;
5
- agent_person?: ITestPersonModel;
4
+ personId: number;
5
+ agentPerson?: ITestPersonModel;
6
6
  }
7
7
  export declare const testAgentSchema: import("@sinclair/typebox").TObject<{
8
- person_id: import("@sinclair/typebox").TNumber;
9
- agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
10
- first_name: import("@sinclair/typebox").TString;
11
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
12
- last_name: import("@sinclair/typebox").TString;
13
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
14
- phone_number: import("@sinclair/typebox").TString;
15
- phone_number_type: import("@sinclair/typebox").TString;
16
- is_default: import("@sinclair/typebox").TBoolean;
8
+ personId: import("@sinclair/typebox").TNumber;
9
+ agentPerson: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
10
+ firstName: import("@sinclair/typebox").TString;
11
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
12
+ lastName: import("@sinclair/typebox").TString;
13
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
14
+ phoneNumber: import("@sinclair/typebox").TString;
15
+ phoneNumberType: import("@sinclair/typebox").TString;
16
+ isDefault: import("@sinclair/typebox").TBoolean;
17
17
  }>>;
18
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
19
- person_id: import("@sinclair/typebox").TNumber;
20
- email_address: import("@sinclair/typebox").TString;
21
- is_default: import("@sinclair/typebox").TBoolean;
18
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
19
+ personId: import("@sinclair/typebox").TNumber;
20
+ emailAddress: import("@sinclair/typebox").TString;
21
+ isDefault: import("@sinclair/typebox").TBoolean;
22
22
  }>>;
23
23
  }>>;
24
24
  }>;
@@ -2,7 +2,7 @@ import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  import { testPersonSchema } from "./test-person.model.js";
4
4
  export const testAgentSchema = Type.Object({
5
- person_id: Type.Number(),
6
- agent_person: Type.Optional(testPersonSchema),
5
+ personId: Type.Number(),
6
+ agentPerson: Type.Optional(testPersonSchema),
7
7
  });
8
8
  export const testAgentModelSpec = entityUtils.getModelSpec(testAgentSchema, { isAuditable: true });
@@ -3,68 +3,68 @@ import { ITestAgentModel } from "./test-agent.model.js";
3
3
  import { ITestPolicyModel } from "./test-policy.model.js";
4
4
  import type { IAuditable, IEntity } from "@loomcore/common/models";
5
5
  export interface ITestClientReportsModel extends IEntity, IAuditable {
6
- client_person: ITestPersonModel;
6
+ clientPerson: ITestPersonModel;
7
7
  agent?: ITestAgentModel;
8
- client_policies?: ITestPolicyModel[];
8
+ clientPolicies?: ITestPolicyModel[];
9
9
  }
10
10
  export declare const testClientReportsSchema: import("@sinclair/typebox").TObject<{
11
- client_person: import("@sinclair/typebox").TObject<{
12
- first_name: import("@sinclair/typebox").TString;
13
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
- last_name: import("@sinclair/typebox").TString;
15
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
16
- phone_number: import("@sinclair/typebox").TString;
17
- phone_number_type: import("@sinclair/typebox").TString;
18
- is_default: import("@sinclair/typebox").TBoolean;
11
+ clientPerson: import("@sinclair/typebox").TObject<{
12
+ firstName: import("@sinclair/typebox").TString;
13
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
+ lastName: import("@sinclair/typebox").TString;
15
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
16
+ phoneNumber: import("@sinclair/typebox").TString;
17
+ phoneNumberType: import("@sinclair/typebox").TString;
18
+ isDefault: import("@sinclair/typebox").TBoolean;
19
19
  }>>;
20
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
21
- person_id: import("@sinclair/typebox").TNumber;
22
- email_address: import("@sinclair/typebox").TString;
23
- is_default: import("@sinclair/typebox").TBoolean;
20
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
21
+ personId: import("@sinclair/typebox").TNumber;
22
+ emailAddress: import("@sinclair/typebox").TString;
23
+ isDefault: import("@sinclair/typebox").TBoolean;
24
24
  }>>;
25
25
  }>;
26
26
  agent: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
27
- person_id: import("@sinclair/typebox").TNumber;
28
- agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
29
- first_name: import("@sinclair/typebox").TString;
30
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
31
- last_name: import("@sinclair/typebox").TString;
32
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
33
- phone_number: import("@sinclair/typebox").TString;
34
- phone_number_type: import("@sinclair/typebox").TString;
35
- is_default: import("@sinclair/typebox").TBoolean;
27
+ personId: import("@sinclair/typebox").TNumber;
28
+ agentPerson: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
29
+ firstName: import("@sinclair/typebox").TString;
30
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
31
+ lastName: import("@sinclair/typebox").TString;
32
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
33
+ phoneNumber: import("@sinclair/typebox").TString;
34
+ phoneNumberType: import("@sinclair/typebox").TString;
35
+ isDefault: import("@sinclair/typebox").TBoolean;
36
36
  }>>;
37
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
38
- person_id: import("@sinclair/typebox").TNumber;
39
- email_address: import("@sinclair/typebox").TString;
40
- is_default: import("@sinclair/typebox").TBoolean;
37
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
38
+ personId: import("@sinclair/typebox").TNumber;
39
+ emailAddress: import("@sinclair/typebox").TString;
40
+ isDefault: import("@sinclair/typebox").TBoolean;
41
41
  }>>;
42
42
  }>>;
43
43
  }>>;
44
- client_policies: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
45
- client_id: import("@sinclair/typebox").TNumber;
44
+ clientPolicies: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
45
+ clientId: import("@sinclair/typebox").TNumber;
46
46
  amount: import("@sinclair/typebox").TNumber;
47
47
  frequency: import("@sinclair/typebox").TString;
48
48
  agents: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
49
- person_id: import("@sinclair/typebox").TNumber;
50
- agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
51
- first_name: import("@sinclair/typebox").TString;
52
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
53
- last_name: import("@sinclair/typebox").TString;
54
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
55
- phone_number: import("@sinclair/typebox").TString;
56
- phone_number_type: import("@sinclair/typebox").TString;
57
- is_default: import("@sinclair/typebox").TBoolean;
49
+ personId: import("@sinclair/typebox").TNumber;
50
+ agentPerson: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
51
+ firstName: import("@sinclair/typebox").TString;
52
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
53
+ lastName: import("@sinclair/typebox").TString;
54
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
55
+ phoneNumber: import("@sinclair/typebox").TString;
56
+ phoneNumberType: import("@sinclair/typebox").TString;
57
+ isDefault: import("@sinclair/typebox").TBoolean;
58
58
  }>>;
59
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
60
- person_id: import("@sinclair/typebox").TNumber;
61
- email_address: import("@sinclair/typebox").TString;
62
- is_default: import("@sinclair/typebox").TBoolean;
59
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
60
+ personId: import("@sinclair/typebox").TNumber;
61
+ emailAddress: import("@sinclair/typebox").TString;
62
+ isDefault: import("@sinclair/typebox").TBoolean;
63
63
  }>>;
64
64
  }>>;
65
65
  }>>>;
66
- policy_premiums: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
67
- policy_id: import("@sinclair/typebox").TNumber;
66
+ policyPremiums: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
67
+ policyId: import("@sinclair/typebox").TNumber;
68
68
  amount: import("@sinclair/typebox").TNumber;
69
69
  date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
70
70
  }>>>;
@@ -4,8 +4,8 @@ import { testPolicySchema } from "./test-policy.model.js";
4
4
  import { entityUtils } from "@loomcore/common/utils";
5
5
  import { Type } from "@sinclair/typebox";
6
6
  export const testClientReportsSchema = Type.Object({
7
- client_person: testPersonSchema,
7
+ clientPerson: testPersonSchema,
8
8
  agent: Type.Optional(testAgentSchema),
9
- client_policies: Type.Optional(Type.Array(testPolicySchema))
9
+ clientPolicies: Type.Optional(Type.Array(testPolicySchema))
10
10
  });
11
11
  export const testClientReportsModelSpec = entityUtils.getModelSpec(testClientReportsSchema, { isAuditable: true });
@@ -2,11 +2,11 @@ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  import { ITestStateModel } from "./test-state.model.js";
3
3
  export interface ITestDistrictModel extends IEntity, IAuditable {
4
4
  name: string;
5
- state_id: number;
5
+ stateId: number;
6
6
  state?: ITestStateModel;
7
7
  }
8
8
  export declare const testDistrictSchema: import("@sinclair/typebox").TObject<{
9
9
  name: import("@sinclair/typebox").TString;
10
- state_id: import("@sinclair/typebox").TNumber;
10
+ stateId: import("@sinclair/typebox").TNumber;
11
11
  }>;
12
12
  export declare const testDistrictModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -2,6 +2,6 @@ import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  export const testDistrictSchema = Type.Object({
4
4
  name: Type.String(),
5
- state_id: Type.Number(),
5
+ stateId: Type.Number(),
6
6
  });
7
7
  export const testDistrictModelSpec = entityUtils.getModelSpec(testDistrictSchema, { isAuditable: true });
@@ -1,12 +1,12 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  export interface ITestEmailAddressModel extends IEntity, IAuditable {
3
- person_id: number;
4
- email_address: string;
5
- is_default: boolean;
3
+ personId: number;
4
+ emailAddress: string;
5
+ isDefault: boolean;
6
6
  }
7
7
  export declare const testEmailAddressSchema: import("@sinclair/typebox").TObject<{
8
- person_id: import("@sinclair/typebox").TNumber;
9
- email_address: import("@sinclair/typebox").TString;
10
- is_default: import("@sinclair/typebox").TBoolean;
8
+ personId: import("@sinclair/typebox").TNumber;
9
+ emailAddress: import("@sinclair/typebox").TString;
10
+ isDefault: import("@sinclair/typebox").TBoolean;
11
11
  }>;
12
12
  export declare const testEmailAddressModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +1,8 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  export const testEmailAddressSchema = Type.Object({
4
- person_id: Type.Number(),
5
- email_address: Type.String(),
6
- is_default: Type.Boolean(),
4
+ personId: Type.Number(),
5
+ emailAddress: Type.String(),
6
+ isDefault: Type.Boolean(),
7
7
  });
8
8
  export const testEmailAddressModelSpec = entityUtils.getModelSpec(testEmailAddressSchema);
@@ -3,26 +3,26 @@ import { ITestEmailAddressModel } from "./test-email-address.model.js";
3
3
  import { ITestPhoneNumberModel } from "./test-phone-number.model.js";
4
4
  import { ITestSchoolModel } from "./test-school.model.js";
5
5
  export interface ITestPersonModel extends IEntity, IAuditable {
6
- first_name: string;
7
- middle_name: string | null;
8
- last_name: string;
9
- client_email_addresses: ITestEmailAddressModel[];
10
- client_phone_numbers: ITestPhoneNumberModel[];
6
+ firstName: string;
7
+ middleName: string | null;
8
+ lastName: string;
9
+ clientEmailAddresses: ITestEmailAddressModel[];
10
+ clientPhoneNumbers: ITestPhoneNumberModel[];
11
11
  school?: ITestSchoolModel;
12
12
  }
13
13
  export declare const testPersonSchema: import("@sinclair/typebox").TObject<{
14
- first_name: import("@sinclair/typebox").TString;
15
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
16
- last_name: import("@sinclair/typebox").TString;
17
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
18
- phone_number: import("@sinclair/typebox").TString;
19
- phone_number_type: import("@sinclair/typebox").TString;
20
- is_default: import("@sinclair/typebox").TBoolean;
14
+ firstName: import("@sinclair/typebox").TString;
15
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
16
+ lastName: import("@sinclair/typebox").TString;
17
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
18
+ phoneNumber: import("@sinclair/typebox").TString;
19
+ phoneNumberType: import("@sinclair/typebox").TString;
20
+ isDefault: import("@sinclair/typebox").TBoolean;
21
21
  }>>;
22
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
23
- person_id: import("@sinclair/typebox").TNumber;
24
- email_address: import("@sinclair/typebox").TString;
25
- is_default: import("@sinclair/typebox").TBoolean;
22
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
23
+ personId: import("@sinclair/typebox").TNumber;
24
+ emailAddress: import("@sinclair/typebox").TString;
25
+ isDefault: import("@sinclair/typebox").TBoolean;
26
26
  }>>;
27
27
  }>;
28
28
  export declare const testPersonModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -3,10 +3,10 @@ import { Type } from "@sinclair/typebox";
3
3
  import { testEmailAddressSchema } from "./test-email-address.model.js";
4
4
  import { testPhoneNumberSchema } from "./test-phone-number.model.js";
5
5
  export const testPersonSchema = Type.Object({
6
- first_name: Type.String(),
7
- middle_name: Type.Optional(Type.String()),
8
- last_name: Type.String(),
9
- client_phone_numbers: Type.Array(testPhoneNumberSchema),
10
- client_email_addresses: Type.Array(testEmailAddressSchema),
6
+ firstName: Type.String(),
7
+ middleName: Type.Optional(Type.String()),
8
+ lastName: Type.String(),
9
+ clientPhoneNumbers: Type.Array(testPhoneNumberSchema),
10
+ clientEmailAddresses: Type.Array(testEmailAddressSchema),
11
11
  });
12
12
  export const testPersonModelSpec = entityUtils.getModelSpec(testPersonSchema, { isAuditable: true });
@@ -1,12 +1,12 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  export interface ITestPhoneNumberModel extends IEntity, IAuditable {
3
- phone_number: string;
4
- phone_number_type: string;
5
- is_default: boolean;
3
+ phoneNumber: string;
4
+ phoneNumberType: string;
5
+ isDefault: boolean;
6
6
  }
7
7
  export declare const testPhoneNumberSchema: import("@sinclair/typebox").TObject<{
8
- phone_number: import("@sinclair/typebox").TString;
9
- phone_number_type: import("@sinclair/typebox").TString;
10
- is_default: import("@sinclair/typebox").TBoolean;
8
+ phoneNumber: import("@sinclair/typebox").TString;
9
+ phoneNumberType: import("@sinclair/typebox").TString;
10
+ isDefault: import("@sinclair/typebox").TBoolean;
11
11
  }>;
12
12
  export declare const testPhoneNumberModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +1,8 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  export const testPhoneNumberSchema = Type.Object({
4
- phone_number: Type.String(),
5
- phone_number_type: Type.String(),
6
- is_default: Type.Boolean(),
4
+ phoneNumber: Type.String(),
5
+ phoneNumberType: Type.String(),
6
+ isDefault: Type.Boolean(),
7
7
  });
8
8
  export const testPhoneNumberModelSpec = entityUtils.getModelSpec(testPhoneNumberSchema, { isAuditable: true });
@@ -2,36 +2,36 @@ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  import { ITestAgentModel } from "./test-agent.model.js";
3
3
  import { ITestPremiumModel } from "./test-premium.model.js";
4
4
  export interface ITestPolicyModel extends IEntity, IAuditable {
5
- client_id: number;
5
+ clientId: number;
6
6
  amount: number;
7
7
  frequency: string;
8
8
  agents?: ITestAgentModel[];
9
- policy_premiums?: ITestPremiumModel[];
9
+ policyPremiums?: ITestPremiumModel[];
10
10
  }
11
11
  export declare const testPolicySchema: import("@sinclair/typebox").TObject<{
12
- client_id: import("@sinclair/typebox").TNumber;
12
+ clientId: import("@sinclair/typebox").TNumber;
13
13
  amount: import("@sinclair/typebox").TNumber;
14
14
  frequency: import("@sinclair/typebox").TString;
15
15
  agents: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
16
- person_id: import("@sinclair/typebox").TNumber;
17
- agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
18
- first_name: import("@sinclair/typebox").TString;
19
- middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
20
- last_name: import("@sinclair/typebox").TString;
21
- client_phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
22
- phone_number: import("@sinclair/typebox").TString;
23
- phone_number_type: import("@sinclair/typebox").TString;
24
- is_default: import("@sinclair/typebox").TBoolean;
16
+ personId: import("@sinclair/typebox").TNumber;
17
+ agentPerson: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
18
+ firstName: import("@sinclair/typebox").TString;
19
+ middleName: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
20
+ lastName: import("@sinclair/typebox").TString;
21
+ clientPhoneNumbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
22
+ phoneNumber: import("@sinclair/typebox").TString;
23
+ phoneNumberType: import("@sinclair/typebox").TString;
24
+ isDefault: import("@sinclair/typebox").TBoolean;
25
25
  }>>;
26
- client_email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
27
- person_id: import("@sinclair/typebox").TNumber;
28
- email_address: import("@sinclair/typebox").TString;
29
- is_default: import("@sinclair/typebox").TBoolean;
26
+ clientEmailAddresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
27
+ personId: import("@sinclair/typebox").TNumber;
28
+ emailAddress: import("@sinclair/typebox").TString;
29
+ isDefault: import("@sinclair/typebox").TBoolean;
30
30
  }>>;
31
31
  }>>;
32
32
  }>>>;
33
- policy_premiums: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
34
- policy_id: import("@sinclair/typebox").TNumber;
33
+ policyPremiums: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
34
+ policyId: import("@sinclair/typebox").TNumber;
35
35
  amount: import("@sinclair/typebox").TNumber;
36
36
  date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
37
37
  }>>>;
@@ -3,10 +3,10 @@ import { Type } from "@sinclair/typebox";
3
3
  import { testAgentSchema } from "./test-agent.model.js";
4
4
  import { testPremiumSchema } from "./test-premium.model.js";
5
5
  export const testPolicySchema = Type.Object({
6
- client_id: Type.Number(),
6
+ clientId: Type.Number(),
7
7
  amount: Type.Number(),
8
8
  frequency: Type.String(),
9
9
  agents: Type.Optional(Type.Array(testAgentSchema)),
10
- policy_premiums: Type.Optional(Type.Array(testPremiumSchema))
10
+ policyPremiums: Type.Optional(Type.Array(testPremiumSchema))
11
11
  });
12
12
  export const testPolicyModelSpec = entityUtils.getModelSpec(testPolicySchema, { isAuditable: true });
@@ -1,11 +1,11 @@
1
1
  import type { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  export interface ITestPremiumModel extends IEntity, IAuditable {
3
- policy_id: number;
3
+ policyId: number;
4
4
  amount: number;
5
5
  date: Date | string;
6
6
  }
7
7
  export declare const testPremiumSchema: import("@sinclair/typebox").TObject<{
8
- policy_id: import("@sinclair/typebox").TNumber;
8
+ policyId: import("@sinclair/typebox").TNumber;
9
9
  amount: import("@sinclair/typebox").TNumber;
10
10
  date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
11
11
  }>;
@@ -1,7 +1,7 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  export const testPremiumSchema = Type.Object({
4
- policy_id: Type.Number(),
4
+ policyId: Type.Number(),
5
5
  amount: Type.Number(),
6
6
  date: Type.Union([Type.Date(), Type.String()])
7
7
  });
@@ -2,11 +2,11 @@ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
2
  import { ITestDistrictModel } from "./test-district.model.js";
3
3
  export interface ITestSchoolModel extends IEntity, IAuditable {
4
4
  name: string;
5
- district_id: number;
5
+ districtId: number;
6
6
  district?: ITestDistrictModel;
7
7
  }
8
8
  export declare const testSchoolSchema: import("@sinclair/typebox").TObject<{
9
9
  name: import("@sinclair/typebox").TString;
10
- district_id: import("@sinclair/typebox").TNumber;
10
+ districtId: import("@sinclair/typebox").TNumber;
11
11
  }>;
12
12
  export declare const testSchoolModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -2,6 +2,6 @@ import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  export const testSchoolSchema = Type.Object({
4
4
  name: Type.String(),
5
- district_id: Type.Number(),
5
+ districtId: Type.Number(),
6
6
  });
7
7
  export const testSchoolModelSpec = entityUtils.getModelSpec(testSchoolSchema, { isAuditable: true });
@@ -3,7 +3,10 @@ import { buildJoinClauses } from '../utils/build-join-clauses.js';
3
3
  import { columnsAndValuesFromEntity } from '../utils/columns-and-values-from-entity.js';
4
4
  export async function partialUpdateById(client, operations, id, entity, pluralResourceName) {
5
5
  try {
6
+ console.log('entity', JSON.stringify(entity, null, 2));
6
7
  const { columns, values } = columnsAndValuesFromEntity(entity);
8
+ console.log('columns', JSON.stringify(columns, null, 2));
9
+ console.log('values', JSON.stringify(values, null, 2));
7
10
  const updateColumns = columns.filter(col => col !== '"_id"');
8
11
  const updateValues = values.filter((_, index) => columns[index] !== '"_id"');
9
12
  if (updateColumns.length === 0) {
@@ -25,8 +25,8 @@ export const getPostgresInitialSchema = (config) => {
25
25
  "code" VARCHAR(255) NOT NULL UNIQUE,
26
26
  "description" TEXT,
27
27
  "status" INTEGER NOT NULL,
28
- "isMetaOrg" BOOLEAN NOT NULL,
29
- "authToken" TEXT,
28
+ "is_meta_org" BOOLEAN NOT NULL,
29
+ "auth_token" TEXT,
30
30
  "_created" TIMESTAMPTZ NOT NULL,
31
31
  "_createdBy" INTEGER NOT NULL,
32
32
  "_updated" TIMESTAMPTZ NOT NULL,
@@ -50,15 +50,15 @@ export const getPostgresInitialSchema = (config) => {
50
50
  CREATE TABLE IF NOT EXISTS "persons" (
51
51
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
52
52
  ${orgColumnDef}
53
- "externalId" VARCHAR(255) UNIQUE,
54
- "firstName" VARCHAR(255) NOT NULL,
55
- "middleName" VARCHAR(255),
56
- "lastName" VARCHAR(255) NOT NULL,
57
- "dateOfBirth" DATE,
58
- "isAgent" BOOLEAN NOT NULL DEFAULT FALSE,
59
- "isClient" BOOLEAN NOT NULL DEFAULT FALSE,
60
- "isEmployee" BOOLEAN NOT NULL DEFAULT FALSE,
61
- "extendedTypes" INTEGER,
53
+ "external_id" VARCHAR(255) UNIQUE,
54
+ "first_name" VARCHAR(255) NOT NULL,
55
+ "middle_name" VARCHAR(255),
56
+ "last_name" VARCHAR(255) NOT NULL,
57
+ "date_of_birth" DATE,
58
+ "is_agent" BOOLEAN NOT NULL DEFAULT FALSE,
59
+ "is_client" BOOLEAN NOT NULL DEFAULT FALSE,
60
+ "is_employee" BOOLEAN NOT NULL DEFAULT FALSE,
61
+ "extended_types" INTEGER,
62
62
  "_created" TIMESTAMPTZ NOT NULL,
63
63
  "_createdBy" INTEGER NOT NULL,
64
64
  "_updated" TIMESTAMPTZ NOT NULL,
@@ -81,16 +81,16 @@ export const getPostgresInitialSchema = (config) => {
81
81
  ? 'CONSTRAINT "uk_users_email" UNIQUE ("_orgId", "email")'
82
82
  : 'CONSTRAINT "uk_users_email" UNIQUE ("email")';
83
83
  uniqueConstraint += `,
84
- CONSTRAINT "fk_users_personId" FOREIGN KEY("personId") REFERENCES "persons"("_id") ON DELETE CASCADE`;
84
+ CONSTRAINT "fk_users_person_id" FOREIGN KEY("person_id") REFERENCES "persons"("_id") ON DELETE CASCADE`;
85
85
  await pool.query(`
86
86
  CREATE TABLE IF NOT EXISTS "users" (
87
87
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
88
88
  ${orgColumnDef}
89
- "externalId" VARCHAR(255) UNIQUE,
89
+ "external_id" VARCHAR(255) UNIQUE,
90
90
  "email" VARCHAR(255) NOT NULL,
91
- "displayName" VARCHAR(255),
91
+ "display_name" VARCHAR(255),
92
92
  "password" VARCHAR(255) NOT NULL,
93
- "personId" INTEGER UNIQUE,
93
+ "person_id" INTEGER UNIQUE,
94
94
  "_lastLoggedIn" TIMESTAMPTZ,
95
95
  "_lastPasswordChange" TIMESTAMPTZ,
96
96
  "_created" TIMESTAMPTZ NOT NULL,
@@ -117,12 +117,12 @@ export const getPostgresInitialSchema = (config) => {
117
117
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
118
118
  ${orgColumnDef}
119
119
  "token" VARCHAR(255) NOT NULL,
120
- "deviceId" VARCHAR(255) NOT NULL,
121
- "userId" INTEGER NOT NULL,
122
- "expiresOn" BIGINT NOT NULL,
120
+ "device_id" VARCHAR(255) NOT NULL,
121
+ "user_id" INTEGER NOT NULL,
122
+ "expires_on" BIGINT NOT NULL,
123
123
  "created" TIMESTAMPTZ NOT NULL,
124
- "createdBy" INTEGER NOT NULL,
125
- CONSTRAINT "fk_refresh_tokens_user" FOREIGN KEY ("userId") REFERENCES "users"("_id") ON DELETE CASCADE
124
+ "created_by" INTEGER NOT NULL,
125
+ CONSTRAINT "fk_refresh_tokens_user" FOREIGN KEY ("user_id") REFERENCES "users"("_id") ON DELETE CASCADE
126
126
  )
127
127
  `);
128
128
  },
@@ -144,7 +144,7 @@ export const getPostgresInitialSchema = (config) => {
144
144
  ${orgColumnDef}
145
145
  "email" VARCHAR(255) NOT NULL,
146
146
  "token" VARCHAR(255) NOT NULL,
147
- "expiresOn" BIGINT NOT NULL,
147
+ "expires_on" BIGINT NOT NULL,
148
148
  "_created" TIMESTAMPTZ NOT NULL,
149
149
  "_createdBy" INTEGER NOT NULL,
150
150
  "_updated" TIMESTAMPTZ NOT NULL,
@@ -156,7 +156,7 @@ export const getPostgresInitialSchema = (config) => {
156
156
  `);
157
157
  },
158
158
  down: async ({ context: pool }) => {
159
- await pool.query('DROP TABLE IF EXISTS "passwordResetTokens"');
159
+ await pool.query('DROP TABLE IF EXISTS "password_reset_tokens"');
160
160
  }
161
161
  });
162
162
  if (isAuthEnabled)
@@ -187,22 +187,22 @@ export const getPostgresInitialSchema = (config) => {
187
187
  up: async ({ context: pool }) => {
188
188
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
189
189
  const uniqueConstraint = isMultiTenant
190
- ? 'CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "userId", "roleId")'
191
- : 'CONSTRAINT "uk_user_roles" UNIQUE ("userId", "roleId")';
190
+ ? 'CONSTRAINT "uk_user_roles" UNIQUE ("_orgId", "user_id", "role_id")'
191
+ : 'CONSTRAINT "uk_user_roles" UNIQUE ("user_id", "role_id")';
192
192
  await pool.query(`
193
193
  CREATE TABLE IF NOT EXISTS "user_roles" (
194
194
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
195
195
  ${orgColumnDef}
196
- "userId" INTEGER NOT NULL,
197
- "roleId" INTEGER NOT NULL,
196
+ "user_id" INTEGER NOT NULL,
197
+ "role_id" INTEGER NOT NULL,
198
198
  "_created" TIMESTAMPTZ NOT NULL,
199
199
  "_createdBy" INTEGER NOT NULL,
200
200
  "_updated" TIMESTAMPTZ NOT NULL,
201
201
  "_updatedBy" INTEGER NOT NULL,
202
202
  "_deleted" TIMESTAMPTZ,
203
203
  "_deletedBy" INTEGER,
204
- CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("userId") REFERENCES "users"("_id") ON DELETE CASCADE,
205
- CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
204
+ CONSTRAINT "fk_user_roles_user" FOREIGN KEY ("user_id") REFERENCES "users"("_id") ON DELETE CASCADE,
205
+ CONSTRAINT "fk_user_roles_role" FOREIGN KEY ("role_id") REFERENCES "roles"("_id") ON DELETE CASCADE,
206
206
  ${uniqueConstraint}
207
207
  )
208
208
  `);
@@ -239,16 +239,16 @@ export const getPostgresInitialSchema = (config) => {
239
239
  up: async ({ context: pool }) => {
240
240
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
241
241
  const uniqueConstraint = isMultiTenant
242
- ? 'CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "roleId", "featureId")'
243
- : 'CONSTRAINT "uk_authorizations" UNIQUE ("roleId", "featureId")';
242
+ ? 'CONSTRAINT "uk_authorizations" UNIQUE ("_orgId", "role_id", "feature_id")'
243
+ : 'CONSTRAINT "uk_authorizations" UNIQUE ("role_id", "feature_id")';
244
244
  await pool.query(`
245
245
  CREATE TABLE IF NOT EXISTS "authorizations" (
246
246
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
247
247
  ${orgColumnDef}
248
- "roleId" INTEGER NOT NULL,
249
- "featureId" INTEGER NOT NULL,
250
- "startDate" TIMESTAMPTZ,
251
- "endDate" TIMESTAMPTZ,
248
+ "role_id" INTEGER NOT NULL,
249
+ "feature_id" INTEGER NOT NULL,
250
+ "start_date" TIMESTAMPTZ,
251
+ "end_date" TIMESTAMPTZ,
252
252
  "config" JSONB,
253
253
  "_created" TIMESTAMPTZ NOT NULL,
254
254
  "_createdBy" INTEGER NOT NULL,
@@ -256,8 +256,8 @@ export const getPostgresInitialSchema = (config) => {
256
256
  "_updatedBy" INTEGER NOT NULL,
257
257
  "_deleted" TIMESTAMPTZ,
258
258
  "_deletedBy" INTEGER,
259
- CONSTRAINT "fk_authorizations_role" FOREIGN KEY ("roleId") REFERENCES "roles"("_id") ON DELETE CASCADE,
260
- CONSTRAINT "fk_authorizations_feature" FOREIGN KEY ("featureId") REFERENCES "features"("_id") ON DELETE CASCADE,
259
+ CONSTRAINT "fk_authorizations_role" FOREIGN KEY ("role_id") REFERENCES "roles"("_id") ON DELETE CASCADE,
260
+ CONSTRAINT "fk_authorizations_feature" FOREIGN KEY ("feature_id") REFERENCES "features"("_id") ON DELETE CASCADE,
261
261
  ${uniqueConstraint}
262
262
  )
263
263
  `);
@@ -271,9 +271,9 @@ export const getPostgresInitialSchema = (config) => {
271
271
  name: '00000000000010_data-meta-org',
272
272
  up: async ({ context: pool }) => {
273
273
  const result = await pool.query(`
274
- INSERT INTO "organizations" ("name", "code", "status", "isMetaOrg", "_created", "_createdBy", "_updated", "_updatedBy")
274
+ INSERT INTO "organizations" ("name", "code", "status", "is_meta_org", "_created", "_createdBy", "_updated", "_updatedBy")
275
275
  VALUES ($1, $2, 1, true, NOW(), 0, NOW(), 0)
276
- RETURNING "_id", "name", "code", "status", "isMetaOrg", "_created", "_createdBy", "_updated", "_updatedBy"
276
+ RETURNING "_id", "name", "code", "status", "is_meta_org", "_created", "_createdBy", "_updated", "_updatedBy"
277
277
  `, [config.multiTenant?.metaOrgName, config.multiTenant?.metaOrgCode]);
278
278
  if (result.rowCount === 0) {
279
279
  throw new Error('Failed to create meta organization');
@@ -281,7 +281,7 @@ export const getPostgresInitialSchema = (config) => {
281
281
  initializeSystemUserContext(config.email?.systemEmailAddress || 'system@example.com', result.rows[0]);
282
282
  },
283
283
  down: async ({ context: pool }) => {
284
- await pool.query(`DELETE FROM "organizations" WHERE "isMetaOrg" = TRUE`);
284
+ await pool.query(`DELETE FROM "organizations" WHERE "is_meta_org" = TRUE`);
285
285
  }
286
286
  });
287
287
  }
@@ -367,11 +367,11 @@ export const getPostgresInitialSchema = (config) => {
367
367
  const roleId = roleResult.rows[0]._id;
368
368
  const userRoleResult = isMultiTenant
369
369
  ? await client.query(`
370
- INSERT INTO "user_roles" ("_orgId", "userId", "roleId", "_created", "_createdBy", "_updated", "_updatedBy")
370
+ INSERT INTO "user_roles" ("_orgId", "user_id", "role_id", "_created", "_createdBy", "_updated", "_updatedBy")
371
371
  VALUES ($1, $2, $3, NOW(), 0, NOW(), 0)
372
372
  `, [metaOrg._id, adminUser._id, roleId])
373
373
  : await client.query(`
374
- INSERT INTO "user_roles" ("userId", "roleId", "_created", "_createdBy", "_updated", "_updatedBy")
374
+ INSERT INTO "user_roles" ("user_id", "role_id", "_created", "_createdBy", "_updated", "_updatedBy")
375
375
  VALUES ($1, $2, NOW(), 0, NOW(), 0)
376
376
  `, [adminUser._id, roleId]);
377
377
  if (userRoleResult.rowCount === 0) {
@@ -395,14 +395,14 @@ export const getPostgresInitialSchema = (config) => {
395
395
  const authorizationResult = isMultiTenant
396
396
  ? await client.query(`
397
397
  INSERT INTO "authorizations" (
398
- "_orgId", "roleId", "featureId",
398
+ "_orgId", "role_id", "feature_id",
399
399
  "_created", "_createdBy", "_updated", "_updatedBy"
400
400
  )
401
401
  VALUES ($1, $2, $3, NOW(), 0, NOW(), 0)
402
402
  `, [metaOrg._id, roleId, featureId])
403
403
  : await client.query(`
404
404
  INSERT INTO "authorizations" (
405
- "roleId", "featureId",
405
+ "role_id", "feature_id",
406
406
  "_created", "_createdBy", "_updated", "_updatedBy"
407
407
  )
408
408
  VALUES ($1, $2, NOW(), 0, NOW(), 0)
@@ -435,11 +435,11 @@ export const getPostgresInitialSchema = (config) => {
435
435
  await client.query(`
436
436
  DELETE FROM "authorizations"
437
437
  WHERE "_orgId" = $1
438
- AND "featureId" IN (
438
+ AND "feature_id" IN (
439
439
  SELECT "_id" FROM "features"
440
440
  WHERE "_orgId" = $1 AND "name" = 'admin'
441
441
  )
442
- AND "roleId" IN (
442
+ AND "role_id" IN (
443
443
  SELECT "_id" FROM "roles"
444
444
  WHERE "_orgId" = $1 AND "name" = 'admin'
445
445
  )
@@ -451,7 +451,7 @@ export const getPostgresInitialSchema = (config) => {
451
451
  await client.query(`
452
452
  DELETE FROM "user_roles"
453
453
  WHERE "_orgId" = $1
454
- AND "roleId" IN (
454
+ AND "role_id" IN (
455
455
  SELECT "_id" FROM "roles"
456
456
  WHERE "_orgId" = $1 AND "name" = 'admin'
457
457
  )
@@ -464,11 +464,11 @@ export const getPostgresInitialSchema = (config) => {
464
464
  else {
465
465
  await client.query(`
466
466
  DELETE FROM "authorizations"
467
- WHERE "featureId" IN (
467
+ WHERE "feature_id" IN (
468
468
  SELECT "_id" FROM "features"
469
469
  WHERE "name" = 'admin'
470
470
  )
471
- AND "roleId" IN (
471
+ AND "role_id" IN (
472
472
  SELECT "_id" FROM "roles"
473
473
  WHERE "name" = 'admin'
474
474
  )
@@ -479,7 +479,7 @@ export const getPostgresInitialSchema = (config) => {
479
479
  `);
480
480
  await client.query(`
481
481
  DELETE FROM "user_roles"
482
- WHERE "roleId" IN (
482
+ WHERE "role_id" IN (
483
483
  SELECT "_id" FROM "roles"
484
484
  WHERE "name" = 'admin'
485
485
  )
@@ -13,16 +13,18 @@ import { get as getQuery } from "./queries/postgres-get.query.js";
13
13
  import { getById as getByIdQuery } from "./queries/postgres-get-by-id.query.js";
14
14
  import { getCount as getCountQuery } from "./queries/postgres-get-count.query.js";
15
15
  import { convertNullToUndefined } from "./utils/convert-null-to-undefined.util.js";
16
+ import { convertKeysToSnakeCase, convertKeysToCamelCase } from "./utils/convert-keys.util.js";
16
17
  export class PostgresDatabase {
17
18
  client;
18
19
  constructor(client) {
19
20
  this.client = client;
20
21
  }
21
22
  preProcessEntity(entity, modelSpec) {
22
- return entity;
23
+ return convertKeysToSnakeCase(entity);
23
24
  }
24
25
  postProcessEntity(entity, modelSpec) {
25
- return convertNullToUndefined(entity, modelSpec);
26
+ const withNullsConverted = convertNullToUndefined(entity, modelSpec);
27
+ return convertKeysToCamelCase(withNullsConverted);
26
28
  }
27
29
  async getAll(operations, pluralResourceName) {
28
30
  return getAllQuery(this.client, operations, pluralResourceName);
@@ -70,21 +72,21 @@ export class PostgresDatabase {
70
72
  const now = new Date();
71
73
  let query = `
72
74
  SELECT DISTINCT
73
- ur."userId" as "userId",
75
+ ur."user_id" as "userId",
74
76
  r."name" as "role",
75
77
  f."name" as "feature",
76
78
  a."config",
77
79
  a."_id",
78
80
  a."_orgId"
79
81
  FROM "user_roles" ur
80
- INNER JOIN "roles" r ON ur."roleId" = r."_id"
81
- INNER JOIN "authorizations" a ON r."_id" = a."roleId"
82
- INNER JOIN "features" f ON a."featureId" = f."_id"
83
- WHERE ur."userId" = $1
82
+ INNER JOIN "roles" r ON ur."role_id" = r."_id"
83
+ INNER JOIN "authorizations" a ON r."_id" = a."role_id"
84
+ INNER JOIN "features" f ON a."feature_id" = f."_id"
85
+ WHERE ur."user_id" = $1
84
86
  AND ur."_deleted" IS NULL
85
87
  AND a."_deleted" IS NULL
86
- AND (a."startDate" IS NULL OR a."startDate" <= $2)
87
- AND (a."endDate" IS NULL OR a."endDate" >= $2)
88
+ AND (a."start_date" IS NULL OR a."start_date" <= $2)
89
+ AND (a."end_date" IS NULL OR a."end_date" >= $2)
88
90
  `;
89
91
  const values = [userId, now];
90
92
  if (orgId) {
@@ -2,11 +2,24 @@ import { Join } from "../../operations/join.operation.js";
2
2
  import { JoinMany } from "../../operations/join-many.operation.js";
3
3
  import { JoinThrough } from "../../operations/join-through.operation.js";
4
4
  import { JoinThroughMany } from "../../operations/join-through-many.operation.js";
5
+ import { toSnakeCase } from "./convert-keys.util.js";
6
+ function convertFieldToSnakeCase(field) {
7
+ if (field.startsWith('_')) {
8
+ return field;
9
+ }
10
+ else if (field === 'id') {
11
+ return '_id';
12
+ }
13
+ else {
14
+ return toSnakeCase(field);
15
+ }
16
+ }
5
17
  function resolveLocalField(localField, mainTableName, operations) {
6
18
  if (!localField.includes('.')) {
19
+ const snakeField = convertFieldToSnakeCase(localField);
7
20
  return mainTableName
8
- ? `"${mainTableName}"."${localField}"`
9
- : `"${localField}"`;
21
+ ? `"${mainTableName}"."${snakeField}"`
22
+ : `"${snakeField}"`;
10
23
  }
11
24
  const [alias, field] = localField.split('.');
12
25
  const objectJoin = operations.find(op => op instanceof JoinThrough && op.as === alias);
@@ -17,7 +30,8 @@ function resolveLocalField(localField, mainTableName, operations) {
17
30
  if (arrayJoin) {
18
31
  return `(${alias}.aggregated->>'${field}')::integer`;
19
32
  }
20
- return `${alias}."${field}"`;
33
+ const snakeField = convertFieldToSnakeCase(field);
34
+ return `${alias}."${snakeField}"`;
21
35
  }
22
36
  function findEnrichmentTarget(operation, operations) {
23
37
  if (!operation.localField.includes('.')) {
@@ -76,7 +90,10 @@ export function buildJoinClauses(operations, mainTableName) {
76
90
  const { target, field } = enrichment;
77
91
  const targetLocalFieldRef = target.localField.includes('.')
78
92
  ? resolveLocalField(target.localField, mainTableName, operations)
79
- : (mainTableName ? `"${mainTableName}"."${target.localField}"` : `"${target.localField}"`);
93
+ : (() => {
94
+ const snakeField = convertFieldToSnakeCase(target.localField);
95
+ return mainTableName ? `"${mainTableName}"."${snakeField}"` : `"${snakeField}"`;
96
+ })();
80
97
  let enrichmentJoins = '';
81
98
  let jsonBuildObjects = '';
82
99
  for (const enrich of enrichments) {
@@ -188,7 +205,10 @@ export function buildJoinClauses(operations, mainTableName) {
188
205
  const { target, field } = enrichment;
189
206
  const targetLocalFieldRef = target.localField.includes('.')
190
207
  ? resolveLocalField(target.localField, mainTableName, operations)
191
- : (mainTableName ? `"${mainTableName}"."${target.localField}"` : `"${target.localField}"`);
208
+ : (() => {
209
+ const snakeField = convertFieldToSnakeCase(target.localField);
210
+ return mainTableName ? `"${mainTableName}"."${snakeField}"` : `"${snakeField}"`;
211
+ })();
192
212
  const isTargetJoinMany = target instanceof JoinMany;
193
213
  let enrichmentJoins = '';
194
214
  let jsonBuildObjects = '';
@@ -1,3 +1,4 @@
1
+ import { toSnakeCase } from "./convert-keys.util.js";
1
2
  export function buildWhereClause(queryObject, values = [], tablePrefix) {
2
3
  const filters = queryObject.filters || {};
3
4
  const conditions = [];
@@ -7,7 +8,17 @@ export function buildWhereClause(queryObject, values = [], tablePrefix) {
7
8
  };
8
9
  for (const [key, value] of Object.entries(filters)) {
9
10
  if (value) {
10
- const qualifiedKey = qualifyColumn(key);
11
+ let snakeKey;
12
+ if (key.startsWith('_')) {
13
+ snakeKey = key;
14
+ }
15
+ else if (key === 'id') {
16
+ snakeKey = '_id';
17
+ }
18
+ else {
19
+ snakeKey = toSnakeCase(key);
20
+ }
21
+ const qualifiedKey = qualifyColumn(snakeKey);
11
22
  if (value.eq !== undefined) {
12
23
  conditions.push(`${qualifiedKey} = $${paramIndex}`);
13
24
  values.push(value.eq);
@@ -2,8 +2,10 @@ export function columnsAndValuesFromEntity(entity) {
2
2
  const columns = [];
3
3
  const values = [];
4
4
  for (const [key, value] of Object.entries(entity)) {
5
- columns.push(`"${key}"`);
6
- values.push(value);
5
+ if (value !== undefined) {
6
+ columns.push(`"${key}"`);
7
+ values.push(value);
8
+ }
7
9
  }
8
10
  return { columns, values };
9
11
  }
@@ -0,0 +1,4 @@
1
+ export declare function toSnakeCase(str: string): string;
2
+ export declare function toCamelCase(str: string): string;
3
+ export declare function convertKeysToSnakeCase<T>(obj: T): T;
4
+ export declare function convertKeysToCamelCase<T>(obj: T): T;
@@ -0,0 +1,85 @@
1
+ import _ from 'lodash';
2
+ export function toSnakeCase(str) {
3
+ let result = str.replace(/([a-z])([A-Z])/g, '$1_$2');
4
+ result = result.toLowerCase()
5
+ .replace(/[\s-]/g, '_');
6
+ result = result.replace(/_+/g, '_')
7
+ .replace(/^_|_$/g, '');
8
+ return result;
9
+ }
10
+ export function toCamelCase(str) {
11
+ return str.split(/[-_]+/)
12
+ .map((word, index) => {
13
+ if (index === 0) {
14
+ return word.toLowerCase();
15
+ }
16
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
17
+ })
18
+ .join('');
19
+ }
20
+ export function convertKeysToSnakeCase(obj) {
21
+ if (!obj)
22
+ return obj;
23
+ if (Array.isArray(obj)) {
24
+ return obj.map(item => convertKeysToSnakeCase(item));
25
+ }
26
+ if (obj instanceof Date) {
27
+ return obj;
28
+ }
29
+ if (typeof obj !== 'object' || obj === null) {
30
+ return obj;
31
+ }
32
+ const clone = _.cloneDeep(obj);
33
+ const result = {};
34
+ for (const [key, value] of Object.entries(clone)) {
35
+ const snakeKey = key.startsWith('_') ? key : toSnakeCase(key);
36
+ if (value !== null && value !== undefined) {
37
+ if (Array.isArray(value)) {
38
+ result[snakeKey] = value.map(item => convertKeysToSnakeCase(item));
39
+ }
40
+ else if (typeof value === 'object' && !(value instanceof Date)) {
41
+ result[snakeKey] = convertKeysToSnakeCase(value);
42
+ }
43
+ else {
44
+ result[snakeKey] = value;
45
+ }
46
+ }
47
+ else {
48
+ result[snakeKey] = value;
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ export function convertKeysToCamelCase(obj) {
54
+ if (!obj)
55
+ return obj;
56
+ if (Array.isArray(obj)) {
57
+ return obj.map(item => convertKeysToCamelCase(item));
58
+ }
59
+ if (obj instanceof Date) {
60
+ return obj;
61
+ }
62
+ if (typeof obj !== 'object' || obj === null) {
63
+ return obj;
64
+ }
65
+ const clone = _.cloneDeep(obj);
66
+ const result = {};
67
+ for (const [key, value] of Object.entries(clone)) {
68
+ const camelKey = key.startsWith('_') ? key : toCamelCase(key);
69
+ if (value !== null && value !== undefined) {
70
+ if (Array.isArray(value)) {
71
+ result[camelKey] = value.map(item => convertKeysToCamelCase(item));
72
+ }
73
+ else if (typeof value === 'object' && !(value instanceof Date)) {
74
+ result[camelKey] = convertKeysToCamelCase(value);
75
+ }
76
+ else {
77
+ result[camelKey] = value;
78
+ }
79
+ }
80
+ else {
81
+ result[camelKey] = value;
82
+ }
83
+ }
84
+ return result;
85
+ }
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash';
2
+ import { toCamelCase } from './convert-keys.util.js';
2
3
  function isPropertyOptional(key, schema) {
3
4
  if (!schema || typeof schema !== 'object')
4
5
  return false;
@@ -36,12 +37,13 @@ export function convertNullToUndefined(data, schema) {
36
37
  return;
37
38
  }
38
39
  if (subSchema.type === 'object' && subSchema.properties) {
39
- for (const [key, propSchema] of Object.entries(subSchema.properties)) {
40
+ for (const [key, value] of Object.entries(obj)) {
41
+ const schemaKey = key.startsWith('_') ? key : toCamelCase(key);
42
+ const propSchema = subSchema.properties[schemaKey];
40
43
  if (!propSchema || typeof propSchema !== 'object')
41
44
  continue;
42
45
  const typedPropSchema = propSchema;
43
- const value = obj[key];
44
- if (isPropertyOptional(key, subSchema)) {
46
+ if (isPropertyOptional(schemaKey, subSchema)) {
45
47
  if (value === null) {
46
48
  delete obj[key];
47
49
  }
@@ -1,5 +1,4 @@
1
- import { Value } from '@sinclair/typebox/value';
2
- import { UserSpec, PublicUserSchema } from '@loomcore/common/models';
1
+ import { UserSpec } from '@loomcore/common/models';
3
2
  import { MultiTenantApiService } from './index.js';
4
3
  import { ServerError } from '../errors/index.js';
5
4
  export class UserService extends MultiTenantApiService {
@@ -15,7 +14,8 @@ export class UserService extends MultiTenantApiService {
15
14
  preparedEntity.email = preparedEntity.email.toLowerCase();
16
15
  }
17
16
  if (!isCreate) {
18
- return Value.Clean(PublicUserSchema, preparedEntity);
17
+ const { password, ...cleanedEntity } = preparedEntity;
18
+ return cleanedEntity;
19
19
  }
20
20
  return preparedEntity;
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomcore/api",
3
- "version": "0.1.85",
3
+ "version": "0.1.86",
4
4
  "private": false,
5
5
  "description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
6
6
  "scripts": {