@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.
- package/dist/__tests__/postgres-test-migrations/postgres-test-schema.js +27 -2
- package/dist/databases/operations/__tests__/models/agent.model.d.ts +25 -0
- package/dist/databases/operations/__tests__/models/agent.model.js +8 -0
- package/dist/databases/operations/__tests__/models/client-report.model.d.ts +22 -2
- package/dist/databases/operations/__tests__/models/client-report.model.js +3 -1
- package/dist/databases/postgres/utils/build-join-clauses.js +10 -3
- package/dist/databases/postgres/utils/transform-join-results.js +18 -1
- package/package.json +1 -1
|
@@ -123,7 +123,30 @@ export const getPostgresTestSchema = (config) => {
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
migrations.push({
|
|
126
|
-
name: '
|
|
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
|
-
|
|
5
|
+
client_person: IPersonModel;
|
|
6
|
+
agent?: IAgentModel;
|
|
5
7
|
}
|
|
6
8
|
export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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];
|