eggi-ai-db-schema-2 0.1.1
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/CHANGELOG.md +750 -0
- package/README.md +660 -0
- package/dist/config/database.d.ts +28 -0
- package/dist/config/database.d.ts.map +1 -0
- package/dist/config/database.js +72 -0
- package/dist/config/database.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +199 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/database-service.d.ts +714 -0
- package/dist/lib/database-service.d.ts.map +1 -0
- package/dist/lib/database-service.js +1394 -0
- package/dist/lib/database-service.js.map +1 -0
- package/dist/lib/db-types.d.ts +167 -0
- package/dist/lib/db-types.d.ts.map +1 -0
- package/dist/lib/db-types.js +28 -0
- package/dist/lib/db-types.js.map +1 -0
- package/dist/lib/db.d.ts +58 -0
- package/dist/lib/db.d.ts.map +1 -0
- package/dist/lib/db.js +292 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +26 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/pg-client.d.ts +50 -0
- package/dist/lib/pg-client.d.ts.map +1 -0
- package/dist/lib/pg-client.js +106 -0
- package/dist/lib/pg-client.js.map +1 -0
- package/dist/lib/schema.d.ts +298 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +12 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/migration-manager.d.ts +49 -0
- package/dist/migration-manager.d.ts.map +1 -0
- package/dist/migration-manager.js +282 -0
- package/dist/migration-manager.js.map +1 -0
- package/dist/queries/minimal-connections.d.ts +31 -0
- package/dist/queries/minimal-connections.d.ts.map +1 -0
- package/dist/queries/minimal-connections.js +143 -0
- package/dist/queries/minimal-connections.js.map +1 -0
- package/dist/schema.ts +340 -0
- package/dist/seed.d.ts +8 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +40 -0
- package/dist/seed.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/types.d.ts +77 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +3 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/authenticated-user-operations.d.ts +110 -0
- package/dist/utils/authenticated-user-operations.d.ts.map +1 -0
- package/dist/utils/authenticated-user-operations.js +292 -0
- package/dist/utils/authenticated-user-operations.js.map +1 -0
- package/dist/utils/authentication-operations.d.ts +48 -0
- package/dist/utils/authentication-operations.d.ts.map +1 -0
- package/dist/utils/authentication-operations.js +172 -0
- package/dist/utils/authentication-operations.js.map +1 -0
- package/dist/utils/company-mapping-job-operations.d.ts +103 -0
- package/dist/utils/company-mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/company-mapping-job-operations.js +413 -0
- package/dist/utils/company-mapping-job-operations.js.map +1 -0
- package/dist/utils/company-sheet-upload-operations.d.ts +53 -0
- package/dist/utils/company-sheet-upload-operations.d.ts.map +1 -0
- package/dist/utils/company-sheet-upload-operations.js +135 -0
- package/dist/utils/company-sheet-upload-operations.js.map +1 -0
- package/dist/utils/contact-operations.d.ts +70 -0
- package/dist/utils/contact-operations.d.ts.map +1 -0
- package/dist/utils/contact-operations.js +294 -0
- package/dist/utils/contact-operations.js.map +1 -0
- package/dist/utils/forager-linkedin-operations.d.ts +74 -0
- package/dist/utils/forager-linkedin-operations.d.ts.map +1 -0
- package/dist/utils/forager-linkedin-operations.js +778 -0
- package/dist/utils/forager-linkedin-operations.js.map +1 -0
- package/dist/utils/ghost-genius-linkedin-operations.d.ts +23 -0
- package/dist/utils/ghost-genius-linkedin-operations.d.ts.map +1 -0
- package/dist/utils/ghost-genius-linkedin-operations.js +282 -0
- package/dist/utils/ghost-genius-linkedin-operations.js.map +1 -0
- package/dist/utils/index.d.ts +29 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +77 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/introduction-request-operations.d.ts +160 -0
- package/dist/utils/introduction-request-operations.d.ts.map +1 -0
- package/dist/utils/introduction-request-operations.js +492 -0
- package/dist/utils/introduction-request-operations.js.map +1 -0
- package/dist/utils/invitation-operations.d.ts +141 -0
- package/dist/utils/invitation-operations.d.ts.map +1 -0
- package/dist/utils/invitation-operations.js +749 -0
- package/dist/utils/invitation-operations.js.map +1 -0
- package/dist/utils/linkedin-account-operations.d.ts +45 -0
- package/dist/utils/linkedin-account-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-account-operations.js +279 -0
- package/dist/utils/linkedin-account-operations.js.map +1 -0
- package/dist/utils/linkedin-account-relationship-operations.d.ts +77 -0
- package/dist/utils/linkedin-account-relationship-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-account-relationship-operations.js +274 -0
- package/dist/utils/linkedin-account-relationship-operations.js.map +1 -0
- package/dist/utils/linkedin-data-operations.d.ts +102 -0
- package/dist/utils/linkedin-data-operations.d.ts.map +1 -0
- package/dist/utils/linkedin-data-operations.js +613 -0
- package/dist/utils/linkedin-data-operations.js.map +1 -0
- package/dist/utils/linkedin-identifier-utils.d.ts +31 -0
- package/dist/utils/linkedin-identifier-utils.d.ts.map +1 -0
- package/dist/utils/linkedin-identifier-utils.js +63 -0
- package/dist/utils/linkedin-identifier-utils.js.map +1 -0
- package/dist/utils/linkedin-profile-cache.d.ts +131 -0
- package/dist/utils/linkedin-profile-cache.d.ts.map +1 -0
- package/dist/utils/linkedin-profile-cache.js +418 -0
- package/dist/utils/linkedin-profile-cache.js.map +1 -0
- package/dist/utils/llm-inference-job-operations.d.ts +116 -0
- package/dist/utils/llm-inference-job-operations.d.ts.map +1 -0
- package/dist/utils/llm-inference-job-operations.js +267 -0
- package/dist/utils/llm-inference-job-operations.js.map +1 -0
- package/dist/utils/mapping-job-operations.d.ts +272 -0
- package/dist/utils/mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/mapping-job-operations.js +833 -0
- package/dist/utils/mapping-job-operations.js.map +1 -0
- package/dist/utils/mapping-operations.d.ts +80 -0
- package/dist/utils/mapping-operations.d.ts.map +1 -0
- package/dist/utils/mapping-operations.js +318 -0
- package/dist/utils/mapping-operations.js.map +1 -0
- package/dist/utils/on-demand-mapping-operations.d.ts +199 -0
- package/dist/utils/on-demand-mapping-operations.d.ts.map +1 -0
- package/dist/utils/on-demand-mapping-operations.js +728 -0
- package/dist/utils/on-demand-mapping-operations.js.map +1 -0
- package/dist/utils/onboarding-operations.d.ts +53 -0
- package/dist/utils/onboarding-operations.d.ts.map +1 -0
- package/dist/utils/onboarding-operations.js +223 -0
- package/dist/utils/onboarding-operations.js.map +1 -0
- package/dist/utils/organization-assignment-job-operations.d.ts +258 -0
- package/dist/utils/organization-assignment-job-operations.d.ts.map +1 -0
- package/dist/utils/organization-assignment-job-operations.js +881 -0
- package/dist/utils/organization-assignment-job-operations.js.map +1 -0
- package/dist/utils/organization-assignment-operations.d.ts +59 -0
- package/dist/utils/organization-assignment-operations.d.ts.map +1 -0
- package/dist/utils/organization-assignment-operations.js +130 -0
- package/dist/utils/organization-assignment-operations.js.map +1 -0
- package/dist/utils/organization-operations.d.ts +284 -0
- package/dist/utils/organization-operations.d.ts.map +1 -0
- package/dist/utils/organization-operations.js +1030 -0
- package/dist/utils/organization-operations.js.map +1 -0
- package/dist/utils/organization-relationship-operations.d.ts +79 -0
- package/dist/utils/organization-relationship-operations.d.ts.map +1 -0
- package/dist/utils/organization-relationship-operations.js +294 -0
- package/dist/utils/organization-relationship-operations.js.map +1 -0
- package/dist/utils/quota-operations.d.ts +107 -0
- package/dist/utils/quota-operations.d.ts.map +1 -0
- package/dist/utils/quota-operations.js +692 -0
- package/dist/utils/quota-operations.js.map +1 -0
- package/dist/utils/recursive-mapping-job-operations.d.ts +42 -0
- package/dist/utils/recursive-mapping-job-operations.d.ts.map +1 -0
- package/dist/utils/recursive-mapping-job-operations.js +169 -0
- package/dist/utils/recursive-mapping-job-operations.js.map +1 -0
- package/dist/utils/relationship-operations.d.ts +130 -0
- package/dist/utils/relationship-operations.d.ts.map +1 -0
- package/dist/utils/relationship-operations.js +329 -0
- package/dist/utils/relationship-operations.js.map +1 -0
- package/dist/utils/sales-pipeline-operations.d.ts +163 -0
- package/dist/utils/sales-pipeline-operations.d.ts.map +1 -0
- package/dist/utils/sales-pipeline-operations.js +725 -0
- package/dist/utils/sales-pipeline-operations.js.map +1 -0
- package/dist/utils/skills-operations.d.ts +117 -0
- package/dist/utils/skills-operations.d.ts.map +1 -0
- package/dist/utils/skills-operations.js +487 -0
- package/dist/utils/skills-operations.js.map +1 -0
- package/dist/utils/subscription-operations.d.ts +123 -0
- package/dist/utils/subscription-operations.d.ts.map +1 -0
- package/dist/utils/subscription-operations.js +391 -0
- package/dist/utils/subscription-operations.js.map +1 -0
- package/dist/utils/unipile-account-operations.d.ts +96 -0
- package/dist/utils/unipile-account-operations.d.ts.map +1 -0
- package/dist/utils/unipile-account-operations.js +255 -0
- package/dist/utils/unipile-account-operations.js.map +1 -0
- package/dist/utils/user-industry-operations.d.ts +80 -0
- package/dist/utils/user-industry-operations.d.ts.map +1 -0
- package/dist/utils/user-industry-operations.js +237 -0
- package/dist/utils/user-industry-operations.js.map +1 -0
- package/dist/utils/user-operations.d.ts +87 -0
- package/dist/utils/user-operations.d.ts.map +1 -0
- package/dist/utils/user-operations.js +212 -0
- package/dist/utils/user-operations.js.map +1 -0
- package/package.json +98 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* =============================================================================
|
|
4
|
+
* UNIPILE ACCOUNT OPERATIONS UTILITIES
|
|
5
|
+
* =============================================================================
|
|
6
|
+
* Utility functions for creating and managing Unipile social media accounts
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.createUnipileAccount = createUnipileAccount;
|
|
10
|
+
exports.upsertUnipileAccount = upsertUnipileAccount;
|
|
11
|
+
exports.getUserLinkedAccountStatus = getUserLinkedAccountStatus;
|
|
12
|
+
exports.checkAcoaAlreadyConnectedToDifferentUser = checkAcoaAlreadyConnectedToDifferentUser;
|
|
13
|
+
exports.batchMarkAccountsAsSynced = batchMarkAccountsAsSynced;
|
|
14
|
+
const pg_client_1 = require("../lib/pg-client");
|
|
15
|
+
const db_1 = require("../lib/db");
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// UNIPILE ACCOUNT OPERATIONS
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new Unipile account record
|
|
21
|
+
*
|
|
22
|
+
* @param data - Unipile account creation data
|
|
23
|
+
* @returns Promise resolving to the created account
|
|
24
|
+
*/
|
|
25
|
+
async function createUnipileAccount(db, data) {
|
|
26
|
+
if (!data.linkedinAccountId || !data.unipileAccountId) {
|
|
27
|
+
throw new Error("Missing required fields: linkedinAccountId and unipileAccountId are required");
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const sql = `
|
|
31
|
+
INSERT INTO public.unipile_accounts (
|
|
32
|
+
linkedin_account_id,
|
|
33
|
+
unipile_account_id,
|
|
34
|
+
is_active,
|
|
35
|
+
connected_at,
|
|
36
|
+
last_synced_at,
|
|
37
|
+
metadata,
|
|
38
|
+
created_at,
|
|
39
|
+
updated_at
|
|
40
|
+
)
|
|
41
|
+
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
|
42
|
+
RETURNING
|
|
43
|
+
id,
|
|
44
|
+
linkedin_account_id,
|
|
45
|
+
unipile_account_id,
|
|
46
|
+
is_active,
|
|
47
|
+
connected_at,
|
|
48
|
+
last_synced_at,
|
|
49
|
+
metadata,
|
|
50
|
+
created_at,
|
|
51
|
+
updated_at
|
|
52
|
+
`;
|
|
53
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [
|
|
54
|
+
data.linkedinAccountId,
|
|
55
|
+
data.unipileAccountId,
|
|
56
|
+
data.isActive ?? true,
|
|
57
|
+
data.connectedAt || new Date(),
|
|
58
|
+
data.lastSyncedAt || null,
|
|
59
|
+
JSON.stringify(data.metadata || {}),
|
|
60
|
+
]);
|
|
61
|
+
if (!result) {
|
|
62
|
+
throw new Error("Failed to create Unipile account");
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof Error && error.message.includes("unique constraint")) {
|
|
68
|
+
throw new Error(`Social account already has a Unipile account linked`);
|
|
69
|
+
}
|
|
70
|
+
throw new Error(`Failed to create Unipile account: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates or updates a Unipile account (upsert)
|
|
75
|
+
*
|
|
76
|
+
* @param data - Unipile account data
|
|
77
|
+
* @returns Promise resolving to the created or updated account
|
|
78
|
+
*/
|
|
79
|
+
async function upsertUnipileAccount(db, data) {
|
|
80
|
+
if (!data.linkedinAccountId || !data.unipileAccountId) {
|
|
81
|
+
throw new Error("Missing required fields: linkedinAccountId and unipileAccountId are required");
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const sql = `
|
|
85
|
+
INSERT INTO public.unipile_accounts (
|
|
86
|
+
linkedin_account_id,
|
|
87
|
+
unipile_account_id,
|
|
88
|
+
is_active,
|
|
89
|
+
connected_at,
|
|
90
|
+
last_synced_at,
|
|
91
|
+
metadata,
|
|
92
|
+
created_at,
|
|
93
|
+
updated_at
|
|
94
|
+
)
|
|
95
|
+
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
|
96
|
+
ON CONFLICT (linkedin_account_id)
|
|
97
|
+
DO UPDATE SET
|
|
98
|
+
unipile_account_id = EXCLUDED.unipile_account_id,
|
|
99
|
+
is_active = EXCLUDED.is_active,
|
|
100
|
+
connected_at = EXCLUDED.connected_at,
|
|
101
|
+
last_synced_at = EXCLUDED.last_synced_at,
|
|
102
|
+
metadata = EXCLUDED.metadata,
|
|
103
|
+
updated_at = NOW()
|
|
104
|
+
RETURNING
|
|
105
|
+
id,
|
|
106
|
+
linkedin_account_id,
|
|
107
|
+
unipile_account_id,
|
|
108
|
+
is_active,
|
|
109
|
+
connected_at,
|
|
110
|
+
last_synced_at,
|
|
111
|
+
metadata,
|
|
112
|
+
created_at,
|
|
113
|
+
updated_at
|
|
114
|
+
`;
|
|
115
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [
|
|
116
|
+
data.linkedinAccountId,
|
|
117
|
+
data.unipileAccountId,
|
|
118
|
+
data.isActive ?? true,
|
|
119
|
+
data.connectedAt || new Date(),
|
|
120
|
+
data.lastSyncedAt || null,
|
|
121
|
+
JSON.stringify(data.metadata || {}),
|
|
122
|
+
]);
|
|
123
|
+
if (!result) {
|
|
124
|
+
throw new Error("Failed to upsert Unipile account");
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw new Error(`Failed to upsert Unipile account: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Gets a simple boolean map of which social accounts are linked for a user
|
|
134
|
+
* Optimized for frontend UI to show connection status without sensitive data
|
|
135
|
+
*
|
|
136
|
+
* @param cognitoUserId - The Cognito user ID
|
|
137
|
+
* @param activeOnly - Whether to only consider active accounts (default: true)
|
|
138
|
+
* @returns Promise resolving to a simple boolean map of linked platforms
|
|
139
|
+
*/
|
|
140
|
+
async function getUserLinkedAccountStatus(db, cognitoUserId, activeOnly = true) {
|
|
141
|
+
try {
|
|
142
|
+
// First get the user ID from authenticated_users table
|
|
143
|
+
const userSql = `
|
|
144
|
+
SELECT user_id
|
|
145
|
+
FROM authentication.users
|
|
146
|
+
WHERE cognito_user_id = $1
|
|
147
|
+
LIMIT 1
|
|
148
|
+
`;
|
|
149
|
+
const authUser = await (0, pg_client_1.queryOne)(db, userSql, [cognitoUserId]);
|
|
150
|
+
if (!authUser || !authUser.user_id) {
|
|
151
|
+
// User not found - return all false
|
|
152
|
+
return {
|
|
153
|
+
linkedin: false,
|
|
154
|
+
whatsapp: false,
|
|
155
|
+
twitter: false,
|
|
156
|
+
instagram: false,
|
|
157
|
+
facebook: false,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Get LinkedIn accounts that have active Unipile connections
|
|
161
|
+
const linkedAccountsSql = `
|
|
162
|
+
SELECT la.id
|
|
163
|
+
FROM linkedin.accounts la
|
|
164
|
+
INNER JOIN public.unipile_accounts ua ON la.id = ua.linkedin_account_id
|
|
165
|
+
WHERE la.user_id = $1
|
|
166
|
+
${activeOnly ? 'AND ua.is_active = true' : ''}
|
|
167
|
+
LIMIT 1
|
|
168
|
+
`;
|
|
169
|
+
const linkedAccounts = await (0, pg_client_1.query)(db, linkedAccountsSql, [authUser.user_id]);
|
|
170
|
+
// Since linkedinAccounts is LinkedIn-only, any result means LinkedIn is connected
|
|
171
|
+
const hasLinkedIn = linkedAccounts.length > 0;
|
|
172
|
+
return {
|
|
173
|
+
linkedin: hasLinkedIn,
|
|
174
|
+
whatsapp: false, // Only LinkedIn is supported in new schema
|
|
175
|
+
twitter: false,
|
|
176
|
+
instagram: false,
|
|
177
|
+
facebook: false,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
throw new Error(`Failed to get social account status: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Checks if a LinkedIn account with the given ACoA identifier is already connected
|
|
186
|
+
* to a different user via an active Unipile account
|
|
187
|
+
*
|
|
188
|
+
* @param db - Database connection
|
|
189
|
+
* @param linkedinIdentifierAcoa - The ACoA identifier to check
|
|
190
|
+
* @param currentUserId - The current user ID (to exclude from the check)
|
|
191
|
+
* @returns Promise resolving to the existing account's user ID if found, null otherwise
|
|
192
|
+
*/
|
|
193
|
+
async function checkAcoaAlreadyConnectedToDifferentUser(db, linkedinIdentifierAcoa, currentUserId) {
|
|
194
|
+
if (!linkedinIdentifierAcoa || !linkedinIdentifierAcoa.startsWith("ACoA")) {
|
|
195
|
+
throw new Error("Invalid ACoA identifier - must start with 'ACoA'");
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const sql = `
|
|
199
|
+
SELECT la.user_id
|
|
200
|
+
FROM linkedin.accounts la
|
|
201
|
+
INNER JOIN public.unipile_accounts ua ON la.id = ua.linkedin_account_id
|
|
202
|
+
WHERE la.linkedin_identifier_acoa = $1
|
|
203
|
+
AND la.user_id != $2
|
|
204
|
+
AND ua.is_active = true
|
|
205
|
+
LIMIT 1
|
|
206
|
+
`;
|
|
207
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [linkedinIdentifierAcoa, currentUserId]);
|
|
208
|
+
return result?.user_id || null;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
throw new Error(`Failed to check ACoA connection: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Batch updates last synced time for multiple accounts
|
|
216
|
+
*
|
|
217
|
+
* @param accountIds - Array of account IDs to update
|
|
218
|
+
* @param syncTime - Optional: specific sync time (defaults to now)
|
|
219
|
+
* @returns Promise resolving to number of updated accounts
|
|
220
|
+
*/
|
|
221
|
+
async function batchMarkAccountsAsSynced(db, accountIds, syncTime) {
|
|
222
|
+
if (accountIds.length === 0) {
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const updateTime = syncTime || new Date();
|
|
227
|
+
(0, db_1.debugLogDbOperation)("update", "unipile_accounts", { lastSyncedAt: updateTime }, undefined, {
|
|
228
|
+
operation: "updateUnipileAccountSyncTime",
|
|
229
|
+
account_ids: accountIds,
|
|
230
|
+
count: accountIds.length,
|
|
231
|
+
});
|
|
232
|
+
// Create placeholders for the IN clause: $2, $3, $4, ...
|
|
233
|
+
const placeholders = accountIds.map((_, i) => `$${i + 2}`).join(', ');
|
|
234
|
+
const sql = `
|
|
235
|
+
UPDATE public.unipile_accounts
|
|
236
|
+
SET
|
|
237
|
+
last_synced_at = $1,
|
|
238
|
+
updated_at = NOW()
|
|
239
|
+
WHERE id IN (${placeholders})
|
|
240
|
+
RETURNING id
|
|
241
|
+
`;
|
|
242
|
+
const updatedAccounts = await (0, pg_client_1.query)(db, sql, [updateTime, ...accountIds]);
|
|
243
|
+
(0, db_1.debugLogDbOperation)("update", "unipile_accounts", { lastSyncedAt: updateTime }, updatedAccounts, {
|
|
244
|
+
operation: "updateUnipileAccountSyncTime",
|
|
245
|
+
account_ids: accountIds,
|
|
246
|
+
count: accountIds.length,
|
|
247
|
+
updated_count: updatedAccounts.length,
|
|
248
|
+
});
|
|
249
|
+
return updatedAccounts.length;
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
throw new Error(`Failed to batch update sync time: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=unipile-account-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unipile-account-operations.js","sourceRoot":"","sources":["../../src/utils/unipile-account-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* USER INDUSTRY OPERATIONS
|
|
4
|
+
* =============================================================================
|
|
5
|
+
* Helper functions for managing user-industry assignments
|
|
6
|
+
*/
|
|
7
|
+
import { Pool, PoolClient } from 'pg';
|
|
8
|
+
import type { Database } from "../lib/db";
|
|
9
|
+
/**
|
|
10
|
+
* Get all industries for a user
|
|
11
|
+
* @param db - Database connection
|
|
12
|
+
* @param userId - User ID
|
|
13
|
+
* @returns Array of industry names (lowercase)
|
|
14
|
+
*/
|
|
15
|
+
export declare function getUserIndustries(db: Database | Pool | PoolClient, userId: number): Promise<string[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Get industries for multiple users (optimized batch query)
|
|
18
|
+
* @param db - Database connection
|
|
19
|
+
* @param userIds - Array of user IDs
|
|
20
|
+
* @returns Map of userId -> industry names array
|
|
21
|
+
*/
|
|
22
|
+
export declare function getBatchUserIndustries(db: Database | Pool | PoolClient, userIds: number[]): Promise<Map<number, string[]>>;
|
|
23
|
+
/**
|
|
24
|
+
* Find or create an industry by name (always lowercase)
|
|
25
|
+
* @param db - Database connection
|
|
26
|
+
* @param industryName - Industry name (will be converted to lowercase)
|
|
27
|
+
* @returns Industry ID
|
|
28
|
+
*/
|
|
29
|
+
export declare function findOrCreateIndustry(db: Database | Pool | PoolClient, industryName: string): Promise<number>;
|
|
30
|
+
/**
|
|
31
|
+
* Assign industries to a user (replaces existing assignments)
|
|
32
|
+
* @param db - Database connection
|
|
33
|
+
* @param userId - User ID
|
|
34
|
+
* @param industryNames - Array of industry names
|
|
35
|
+
*/
|
|
36
|
+
export declare function setUserIndustries(db: Database | Pool | PoolClient, userId: number, industryNames: string[]): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Add industries to a user (keeps existing assignments)
|
|
39
|
+
* @param db - Database connection
|
|
40
|
+
* @param userId - User ID
|
|
41
|
+
* @param industryNames - Array of industry names to add
|
|
42
|
+
*/
|
|
43
|
+
export declare function addUserIndustries(db: Database | Pool | PoolClient, userId: number, industryNames: string[]): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove specific industries from a user
|
|
46
|
+
* @param db - Database connection
|
|
47
|
+
* @param userId - User ID
|
|
48
|
+
* @param industryNames - Array of industry names to remove
|
|
49
|
+
*/
|
|
50
|
+
export declare function removeUserIndustries(db: Database | Pool | PoolClient, userId: number, industryNames: string[]): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Remove all industries from a user
|
|
53
|
+
* @param db - Database connection
|
|
54
|
+
* @param userId - User ID
|
|
55
|
+
*/
|
|
56
|
+
export declare function clearUserIndustries(db: Database | Pool | PoolClient, userId: number): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Check if a user has a specific industry
|
|
59
|
+
* @param db - Database connection
|
|
60
|
+
* @param userId - User ID
|
|
61
|
+
* @param industryName - Industry name to check
|
|
62
|
+
* @returns True if user has the industry
|
|
63
|
+
*/
|
|
64
|
+
export declare function userHasIndustry(db: Database | Pool | PoolClient, userId: number, industryName: string): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Get all unique industries in the system
|
|
67
|
+
* @param db - Database connection
|
|
68
|
+
* @param limit - Optional limit (default: 1000)
|
|
69
|
+
* @returns Array of industry names
|
|
70
|
+
*/
|
|
71
|
+
export declare function getAllIndustries(db: Database | Pool | PoolClient, limit?: number): Promise<string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Search industries by partial name match
|
|
74
|
+
* @param db - Database connection
|
|
75
|
+
* @param searchTerm - Search term (case-insensitive)
|
|
76
|
+
* @param limit - Optional limit (default: 20)
|
|
77
|
+
* @returns Array of matching industry names
|
|
78
|
+
*/
|
|
79
|
+
export declare function searchIndustries(db: Database | Pool | PoolClient, searchTerm: string, limit?: number): Promise<string[]>;
|
|
80
|
+
//# sourceMappingURL=user-industry-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-industry-operations.d.ts","sourceRoot":"","sources":["../../src/utils/user-industry-operations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAU3G;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAmChC;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoClH;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzG;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAAE,KAAK,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUhH;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,EAChC,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBnB"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* =============================================================================
|
|
4
|
+
* USER INDUSTRY OPERATIONS
|
|
5
|
+
* =============================================================================
|
|
6
|
+
* Helper functions for managing user-industry assignments
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.getUserIndustries = getUserIndustries;
|
|
10
|
+
exports.getBatchUserIndustries = getBatchUserIndustries;
|
|
11
|
+
exports.findOrCreateIndustry = findOrCreateIndustry;
|
|
12
|
+
exports.setUserIndustries = setUserIndustries;
|
|
13
|
+
exports.addUserIndustries = addUserIndustries;
|
|
14
|
+
exports.removeUserIndustries = removeUserIndustries;
|
|
15
|
+
exports.clearUserIndustries = clearUserIndustries;
|
|
16
|
+
exports.userHasIndustry = userHasIndustry;
|
|
17
|
+
exports.getAllIndustries = getAllIndustries;
|
|
18
|
+
exports.searchIndustries = searchIndustries;
|
|
19
|
+
const pg_client_1 = require("../lib/pg-client");
|
|
20
|
+
/**
|
|
21
|
+
* Get all industries for a user
|
|
22
|
+
* @param db - Database connection
|
|
23
|
+
* @param userId - User ID
|
|
24
|
+
* @returns Array of industry names (lowercase)
|
|
25
|
+
*/
|
|
26
|
+
async function getUserIndustries(db, userId) {
|
|
27
|
+
const sql = `
|
|
28
|
+
SELECT i.name
|
|
29
|
+
FROM public.user_industry_assignments uia
|
|
30
|
+
INNER JOIN public.industries i ON uia.industry_id = i.id
|
|
31
|
+
WHERE uia.user_id = $1
|
|
32
|
+
`;
|
|
33
|
+
const results = await (0, pg_client_1.query)(db, sql, [userId]);
|
|
34
|
+
return results.map(r => r.name);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get industries for multiple users (optimized batch query)
|
|
38
|
+
* @param db - Database connection
|
|
39
|
+
* @param userIds - Array of user IDs
|
|
40
|
+
* @returns Map of userId -> industry names array
|
|
41
|
+
*/
|
|
42
|
+
async function getBatchUserIndustries(db, userIds) {
|
|
43
|
+
if (userIds.length === 0) {
|
|
44
|
+
return new Map();
|
|
45
|
+
}
|
|
46
|
+
const placeholders = userIds.map((_, i) => `$${i + 1}`).join(', ');
|
|
47
|
+
const sql = `
|
|
48
|
+
SELECT uia.user_id, i.name as industry_name
|
|
49
|
+
FROM public.user_industry_assignments uia
|
|
50
|
+
INNER JOIN public.industries i ON uia.industry_id = i.id
|
|
51
|
+
WHERE uia.user_id IN (${placeholders})
|
|
52
|
+
`;
|
|
53
|
+
const results = await (0, pg_client_1.query)(db, sql, userIds);
|
|
54
|
+
// Group by user ID
|
|
55
|
+
const industryMap = new Map();
|
|
56
|
+
for (const result of results) {
|
|
57
|
+
const existing = industryMap.get(result.user_id) || [];
|
|
58
|
+
existing.push(result.industry_name);
|
|
59
|
+
industryMap.set(result.user_id, existing);
|
|
60
|
+
}
|
|
61
|
+
// Ensure all users have an entry (even if empty array)
|
|
62
|
+
for (const userId of userIds) {
|
|
63
|
+
if (!industryMap.has(userId)) {
|
|
64
|
+
industryMap.set(userId, []);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return industryMap;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Find or create an industry by name (always lowercase)
|
|
71
|
+
* @param db - Database connection
|
|
72
|
+
* @param industryName - Industry name (will be converted to lowercase)
|
|
73
|
+
* @returns Industry ID
|
|
74
|
+
*/
|
|
75
|
+
async function findOrCreateIndustry(db, industryName) {
|
|
76
|
+
const normalizedName = industryName.trim().toLowerCase();
|
|
77
|
+
if (!normalizedName) {
|
|
78
|
+
throw new Error("Industry name cannot be empty");
|
|
79
|
+
}
|
|
80
|
+
// Try to find existing
|
|
81
|
+
const existingSql = `SELECT id FROM public.industries WHERE name = $1 LIMIT 1`;
|
|
82
|
+
const existing = await (0, pg_client_1.queryOne)(db, existingSql, [normalizedName]);
|
|
83
|
+
if (existing) {
|
|
84
|
+
return existing.id;
|
|
85
|
+
}
|
|
86
|
+
// Create new with ON CONFLICT DO NOTHING
|
|
87
|
+
const insertSql = `
|
|
88
|
+
INSERT INTO public.industries (name, created_at)
|
|
89
|
+
VALUES ($1, NOW())
|
|
90
|
+
ON CONFLICT (name) DO NOTHING
|
|
91
|
+
RETURNING id
|
|
92
|
+
`;
|
|
93
|
+
const newIndustry = await (0, pg_client_1.queryOne)(db, insertSql, [normalizedName]);
|
|
94
|
+
if (newIndustry) {
|
|
95
|
+
return newIndustry.id;
|
|
96
|
+
}
|
|
97
|
+
// If conflict happened, fetch again
|
|
98
|
+
const retryExisting = await (0, pg_client_1.queryOne)(db, existingSql, [normalizedName]);
|
|
99
|
+
if (!retryExisting) {
|
|
100
|
+
throw new Error(`Failed to find or create industry: ${normalizedName}`);
|
|
101
|
+
}
|
|
102
|
+
return retryExisting.id;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Assign industries to a user (replaces existing assignments)
|
|
106
|
+
* @param db - Database connection
|
|
107
|
+
* @param userId - User ID
|
|
108
|
+
* @param industryNames - Array of industry names
|
|
109
|
+
*/
|
|
110
|
+
async function setUserIndustries(db, userId, industryNames) {
|
|
111
|
+
// Remove existing assignments
|
|
112
|
+
const deleteSql = `DELETE FROM public.user_industry_assignments WHERE user_id = $1`;
|
|
113
|
+
await (0, pg_client_1.execute)(db, deleteSql, [userId]);
|
|
114
|
+
// Add new assignments
|
|
115
|
+
if (industryNames.length > 0) {
|
|
116
|
+
await addUserIndustries(db, userId, industryNames);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Add industries to a user (keeps existing assignments)
|
|
121
|
+
* @param db - Database connection
|
|
122
|
+
* @param userId - User ID
|
|
123
|
+
* @param industryNames - Array of industry names to add
|
|
124
|
+
*/
|
|
125
|
+
async function addUserIndustries(db, userId, industryNames) {
|
|
126
|
+
if (industryNames.length === 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// Find or create all industries
|
|
130
|
+
const industryIds = [];
|
|
131
|
+
for (const name of industryNames) {
|
|
132
|
+
const id = await findOrCreateIndustry(db, name);
|
|
133
|
+
industryIds.push(id);
|
|
134
|
+
}
|
|
135
|
+
// Create assignments (ignore conflicts if already assigned)
|
|
136
|
+
const values = industryIds.map((industryId, i) => `($1, $${i + 2})`).join(', ');
|
|
137
|
+
const sql = `
|
|
138
|
+
INSERT INTO public.user_industry_assignments (user_id, industry_id, created_at)
|
|
139
|
+
VALUES ${values}
|
|
140
|
+
ON CONFLICT (user_id, industry_id) DO NOTHING
|
|
141
|
+
`;
|
|
142
|
+
await (0, pg_client_1.execute)(db, sql, [userId, ...industryIds]);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Remove specific industries from a user
|
|
146
|
+
* @param db - Database connection
|
|
147
|
+
* @param userId - User ID
|
|
148
|
+
* @param industryNames - Array of industry names to remove
|
|
149
|
+
*/
|
|
150
|
+
async function removeUserIndustries(db, userId, industryNames) {
|
|
151
|
+
if (industryNames.length === 0) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const normalizedNames = industryNames.map(n => n.trim().toLowerCase());
|
|
155
|
+
// Get industry IDs
|
|
156
|
+
const placeholders = normalizedNames.map((_, i) => `$${i + 1}`).join(', ');
|
|
157
|
+
const selectSql = `SELECT id FROM public.industries WHERE name IN (${placeholders})`;
|
|
158
|
+
const industryRecords = await (0, pg_client_1.query)(db, selectSql, normalizedNames);
|
|
159
|
+
if (industryRecords.length === 0) {
|
|
160
|
+
return; // No industries to remove
|
|
161
|
+
}
|
|
162
|
+
const industryIds = industryRecords.map(r => r.id);
|
|
163
|
+
// Delete assignments
|
|
164
|
+
const deletePlaceholders = industryIds.map((_, i) => `$${i + 2}`).join(', ');
|
|
165
|
+
const deleteSql = `
|
|
166
|
+
DELETE FROM public.user_industry_assignments
|
|
167
|
+
WHERE user_id = $1 AND industry_id IN (${deletePlaceholders})
|
|
168
|
+
`;
|
|
169
|
+
await (0, pg_client_1.execute)(db, deleteSql, [userId, ...industryIds]);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Remove all industries from a user
|
|
173
|
+
* @param db - Database connection
|
|
174
|
+
* @param userId - User ID
|
|
175
|
+
*/
|
|
176
|
+
async function clearUserIndustries(db, userId) {
|
|
177
|
+
const sql = `DELETE FROM public.user_industry_assignments WHERE user_id = $1`;
|
|
178
|
+
await (0, pg_client_1.execute)(db, sql, [userId]);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Check if a user has a specific industry
|
|
182
|
+
* @param db - Database connection
|
|
183
|
+
* @param userId - User ID
|
|
184
|
+
* @param industryName - Industry name to check
|
|
185
|
+
* @returns True if user has the industry
|
|
186
|
+
*/
|
|
187
|
+
async function userHasIndustry(db, userId, industryName) {
|
|
188
|
+
const normalizedName = industryName.trim().toLowerCase();
|
|
189
|
+
const sql = `
|
|
190
|
+
SELECT uia.id
|
|
191
|
+
FROM public.user_industry_assignments uia
|
|
192
|
+
INNER JOIN public.industries i ON uia.industry_id = i.id
|
|
193
|
+
WHERE uia.user_id = $1 AND i.name = $2
|
|
194
|
+
LIMIT 1
|
|
195
|
+
`;
|
|
196
|
+
const result = await (0, pg_client_1.queryOne)(db, sql, [userId, normalizedName]);
|
|
197
|
+
return result !== null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get all unique industries in the system
|
|
201
|
+
* @param db - Database connection
|
|
202
|
+
* @param limit - Optional limit (default: 1000)
|
|
203
|
+
* @returns Array of industry names
|
|
204
|
+
*/
|
|
205
|
+
async function getAllIndustries(db, limit = 1000) {
|
|
206
|
+
const sql = `
|
|
207
|
+
SELECT name
|
|
208
|
+
FROM public.industries
|
|
209
|
+
ORDER BY name
|
|
210
|
+
LIMIT $1
|
|
211
|
+
`;
|
|
212
|
+
const results = await (0, pg_client_1.query)(db, sql, [limit]);
|
|
213
|
+
return results.map(r => r.name);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Search industries by partial name match
|
|
217
|
+
* @param db - Database connection
|
|
218
|
+
* @param searchTerm - Search term (case-insensitive)
|
|
219
|
+
* @param limit - Optional limit (default: 20)
|
|
220
|
+
* @returns Array of matching industry names
|
|
221
|
+
*/
|
|
222
|
+
async function searchIndustries(db, searchTerm, limit = 20) {
|
|
223
|
+
const normalizedSearch = searchTerm.trim().toLowerCase();
|
|
224
|
+
if (!normalizedSearch) {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
const sql = `
|
|
228
|
+
SELECT name
|
|
229
|
+
FROM public.industries
|
|
230
|
+
WHERE name ILIKE $1
|
|
231
|
+
ORDER BY name
|
|
232
|
+
LIMIT $2
|
|
233
|
+
`;
|
|
234
|
+
const results = await (0, pg_client_1.query)(db, sql, [`%${normalizedSearch}%`, limit]);
|
|
235
|
+
return results.map(r => r.name);
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=user-industry-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-industry-operations.js","sourceRoot":"","sources":["../../src/utils/user-industry-operations.ts"],"names":[],"mappings":"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"}
|