@loomcore/api 0.1.70 → 0.1.71

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.
@@ -123,7 +123,30 @@ export const getPostgresTestSchema = (config) => {
123
123
  }
124
124
  });
125
125
  migrations.push({
126
- name: '00000000000104_schema-clients',
126
+ name: '00000000000105_5_schema-agents',
127
+ up: async ({ context: pool }) => {
128
+ const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
129
+ await pool.query(`
130
+ CREATE TABLE IF NOT EXISTS "agents" (
131
+ "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
132
+ ${orgColumnDef}
133
+ "person_id" INTEGER NOT NULL UNIQUE,
134
+ "_created" TIMESTAMPTZ NOT NULL,
135
+ "_createdBy" INTEGER NOT NULL,
136
+ "_updated" TIMESTAMPTZ NOT NULL,
137
+ "_updatedBy" INTEGER NOT NULL,
138
+ "_deleted" TIMESTAMPTZ,
139
+ "_deletedBy" INTEGER,
140
+ CONSTRAINT fk_agents_person_id FOREIGN KEY ("person_id") REFERENCES persons("_id") ON DELETE CASCADE
141
+ )
142
+ `);
143
+ },
144
+ down: async ({ context: pool }) => {
145
+ await pool.query('DROP TABLE IF EXISTS "agents"');
146
+ }
147
+ });
148
+ migrations.push({
149
+ name: '00000000000105_6_schema-clients',
127
150
  up: async ({ context: pool }) => {
128
151
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
129
152
  await pool.query(`
@@ -132,13 +155,15 @@ export const getPostgresTestSchema = (config) => {
132
155
  ${orgColumnDef}
133
156
  "external_id" VARCHAR UNIQUE,
134
157
  "person_id" INTEGER NOT NULL UNIQUE,
158
+ "agent_id" INTEGER,
135
159
  "_created" TIMESTAMPTZ NOT NULL,
136
160
  "_createdBy" INTEGER NOT NULL,
137
161
  "_updated" TIMESTAMPTZ NOT NULL,
138
162
  "_updatedBy" INTEGER NOT NULL,
139
163
  "_deleted" TIMESTAMPTZ,
140
164
  "_deletedBy" INTEGER,
141
- CONSTRAINT fk_clients_person_id FOREIGN KEY ("person_id") REFERENCES persons("_id") ON DELETE CASCADE
165
+ CONSTRAINT fk_clients_person_id FOREIGN KEY ("person_id") REFERENCES persons("_id") ON DELETE CASCADE,
166
+ CONSTRAINT fk_clients_agent_id FOREIGN KEY ("agent_id") REFERENCES agents("_id") ON DELETE SET NULL
142
167
  )
143
168
  `);
144
169
  },
@@ -0,0 +1,25 @@
1
+ import { IAuditable, IEntity } from "@loomcore/common/models";
2
+ import { IPersonModel } from "./person.model.js";
3
+ export interface IAgentModel extends IEntity, IAuditable {
4
+ person_id: number;
5
+ agent_person?: IPersonModel;
6
+ }
7
+ export declare const agentSchema: 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
+ 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;
17
+ }>>;
18
+ 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;
22
+ }>>;
23
+ }>>;
24
+ }>;
25
+ export declare const agentModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,8 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { personSchema } from "./person.model.js";
4
+ export const agentSchema = Type.Object({
5
+ person_id: Type.Number(),
6
+ agent_person: Type.Optional(personSchema),
7
+ });
8
+ export const agentModelSpec = entityUtils.getModelSpec(agentSchema, { isAuditable: true });
@@ -1,10 +1,12 @@
1
1
  import { IPersonModel } from "./person.model.js";
2
+ import { IAgentModel } from "./agent.model.js";
2
3
  import type { IAuditable, IEntity } from "@loomcore/common/models";
3
4
  export interface IClientReportsModel extends IEntity, IAuditable {
4
- person: IPersonModel;
5
+ client_person: IPersonModel;
6
+ agent?: IAgentModel;
5
7
  }
6
8
  export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
7
- person: import("@sinclair/typebox").TObject<{
9
+ client_person: import("@sinclair/typebox").TObject<{
8
10
  first_name: import("@sinclair/typebox").TString;
9
11
  middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
12
  last_name: import("@sinclair/typebox").TString;
@@ -19,5 +21,23 @@ export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
19
21
  is_default: import("@sinclair/typebox").TBoolean;
20
22
  }>>;
21
23
  }>;
24
+ agent: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
25
+ person_id: import("@sinclair/typebox").TNumber;
26
+ agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
27
+ first_name: import("@sinclair/typebox").TString;
28
+ middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
29
+ last_name: import("@sinclair/typebox").TString;
30
+ phone_numbers: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
31
+ phone_number: import("@sinclair/typebox").TString;
32
+ phone_number_type: import("@sinclair/typebox").TString;
33
+ is_default: import("@sinclair/typebox").TBoolean;
34
+ }>>;
35
+ email_addresses: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
36
+ person_id: import("@sinclair/typebox").TNumber;
37
+ email_address: import("@sinclair/typebox").TString;
38
+ is_default: import("@sinclair/typebox").TBoolean;
39
+ }>>;
40
+ }>>;
41
+ }>>;
22
42
  }>;
23
43
  export declare const clientReportsModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,7 +1,9 @@
1
1
  import { personSchema } from "./person.model.js";
2
+ import { agentSchema } from "./agent.model.js";
2
3
  import { entityUtils } from "@loomcore/common/utils";
3
4
  import { Type } from "@sinclair/typebox";
4
5
  export const clientReportsSchema = Type.Object({
5
- person: personSchema
6
+ client_person: personSchema,
7
+ agent: Type.Optional(agentSchema)
6
8
  });
7
9
  export const clientReportsModelSpec = entityUtils.getModelSpec(clientReportsSchema, { isAuditable: true });
@@ -7,9 +7,16 @@ export function buildJoinClauses(operations, mainTableName) {
7
7
  const joinManyOperations = operations.filter(op => op instanceof JoinMany);
8
8
  const joinThroughOperations = operations.filter(op => op instanceof JoinThrough);
9
9
  for (const operation of joinOperations) {
10
- const localFieldRef = mainTableName
11
- ? `"${mainTableName}"."${operation.localField}"`
12
- : `"${operation.localField}"`;
10
+ let localFieldRef;
11
+ if (operation.localField.includes('.')) {
12
+ const [tableAlias, columnName] = operation.localField.split('.');
13
+ localFieldRef = `${tableAlias}."${columnName}"`;
14
+ }
15
+ else {
16
+ localFieldRef = mainTableName
17
+ ? `"${mainTableName}"."${operation.localField}"`
18
+ : `"${operation.localField}"`;
19
+ }
13
20
  joinClauses += ` LEFT JOIN "${operation.from}" AS ${operation.as} ON ${localFieldRef} = "${operation.as}"."${operation.foreignField}"`;
14
21
  }
15
22
  for (const joinMany of joinManyOperations) {
@@ -36,7 +36,24 @@ export function transformJoinResults(rows, operations) {
36
36
  }
37
37
  }
38
38
  }
39
- transformed[join.as] = hasAnyData ? joinedData : null;
39
+ if (join.localField.includes('.')) {
40
+ const [tableAlias] = join.localField.split('.');
41
+ const relatedJoin = joinOperations.find(j => j.as === tableAlias);
42
+ if (relatedJoin && transformed[relatedJoin.as] !== undefined && transformed[relatedJoin.as] !== null) {
43
+ if (hasAnyData) {
44
+ transformed[relatedJoin.as][join.as] = joinedData;
45
+ }
46
+ else {
47
+ transformed[relatedJoin.as][join.as] = null;
48
+ }
49
+ }
50
+ else {
51
+ transformed[join.as] = hasAnyData ? joinedData : null;
52
+ }
53
+ }
54
+ else {
55
+ transformed[join.as] = hasAnyData ? joinedData : null;
56
+ }
40
57
  }
41
58
  for (const joinMany of joinManyOperations) {
42
59
  const jsonValue = row[joinMany.as];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomcore/api",
3
- "version": "0.1.70",
3
+ "version": "0.1.71",
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": {