eggi-ai-db-schema-2 12.54.2

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 (188) hide show
  1. package/CHANGELOG.md +750 -0
  2. package/README.md +655 -0
  3. package/dist/config/database.d.ts +28 -0
  4. package/dist/config/database.d.ts.map +1 -0
  5. package/dist/config/database.js +72 -0
  6. package/dist/config/database.js.map +1 -0
  7. package/dist/index.d.ts +28 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +199 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/lib/database-service.d.ts +689 -0
  12. package/dist/lib/database-service.d.ts.map +1 -0
  13. package/dist/lib/database-service.js +1362 -0
  14. package/dist/lib/database-service.js.map +1 -0
  15. package/dist/lib/db-types.d.ts +167 -0
  16. package/dist/lib/db-types.d.ts.map +1 -0
  17. package/dist/lib/db-types.js +28 -0
  18. package/dist/lib/db-types.js.map +1 -0
  19. package/dist/lib/db.d.ts +58 -0
  20. package/dist/lib/db.d.ts.map +1 -0
  21. package/dist/lib/db.js +292 -0
  22. package/dist/lib/db.js.map +1 -0
  23. package/dist/lib/index.d.ts +11 -0
  24. package/dist/lib/index.d.ts.map +1 -0
  25. package/dist/lib/index.js +26 -0
  26. package/dist/lib/index.js.map +1 -0
  27. package/dist/lib/pg-client.d.ts +50 -0
  28. package/dist/lib/pg-client.d.ts.map +1 -0
  29. package/dist/lib/pg-client.js +106 -0
  30. package/dist/lib/pg-client.js.map +1 -0
  31. package/dist/lib/schema.d.ts +298 -0
  32. package/dist/lib/schema.d.ts.map +1 -0
  33. package/dist/lib/schema.js +12 -0
  34. package/dist/lib/schema.js.map +1 -0
  35. package/dist/migration-manager.d.ts +49 -0
  36. package/dist/migration-manager.d.ts.map +1 -0
  37. package/dist/migration-manager.js +282 -0
  38. package/dist/migration-manager.js.map +1 -0
  39. package/dist/queries/minimal-connections.d.ts +31 -0
  40. package/dist/queries/minimal-connections.d.ts.map +1 -0
  41. package/dist/queries/minimal-connections.js +143 -0
  42. package/dist/queries/minimal-connections.js.map +1 -0
  43. package/dist/schema.ts +340 -0
  44. package/dist/seed.d.ts +8 -0
  45. package/dist/seed.d.ts.map +1 -0
  46. package/dist/seed.js +40 -0
  47. package/dist/seed.js.map +1 -0
  48. package/dist/types/index.d.ts +7 -0
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/index.js +23 -0
  51. package/dist/types/index.js.map +1 -0
  52. package/dist/types/types.d.ts +77 -0
  53. package/dist/types/types.d.ts.map +1 -0
  54. package/dist/types/types.js +3 -0
  55. package/dist/types/types.js.map +1 -0
  56. package/dist/utils/authenticated-user-operations.d.ts +110 -0
  57. package/dist/utils/authenticated-user-operations.d.ts.map +1 -0
  58. package/dist/utils/authenticated-user-operations.js +292 -0
  59. package/dist/utils/authenticated-user-operations.js.map +1 -0
  60. package/dist/utils/authentication-operations.d.ts +48 -0
  61. package/dist/utils/authentication-operations.d.ts.map +1 -0
  62. package/dist/utils/authentication-operations.js +172 -0
  63. package/dist/utils/authentication-operations.js.map +1 -0
  64. package/dist/utils/company-mapping-job-operations.d.ts +103 -0
  65. package/dist/utils/company-mapping-job-operations.d.ts.map +1 -0
  66. package/dist/utils/company-mapping-job-operations.js +413 -0
  67. package/dist/utils/company-mapping-job-operations.js.map +1 -0
  68. package/dist/utils/company-sheet-upload-operations.d.ts +53 -0
  69. package/dist/utils/company-sheet-upload-operations.d.ts.map +1 -0
  70. package/dist/utils/company-sheet-upload-operations.js +135 -0
  71. package/dist/utils/company-sheet-upload-operations.js.map +1 -0
  72. package/dist/utils/contact-operations.d.ts +70 -0
  73. package/dist/utils/contact-operations.d.ts.map +1 -0
  74. package/dist/utils/contact-operations.js +294 -0
  75. package/dist/utils/contact-operations.js.map +1 -0
  76. package/dist/utils/forager-linkedin-operations.d.ts +74 -0
  77. package/dist/utils/forager-linkedin-operations.d.ts.map +1 -0
  78. package/dist/utils/forager-linkedin-operations.js +778 -0
  79. package/dist/utils/forager-linkedin-operations.js.map +1 -0
  80. package/dist/utils/ghost-genius-linkedin-operations.d.ts +23 -0
  81. package/dist/utils/ghost-genius-linkedin-operations.d.ts.map +1 -0
  82. package/dist/utils/ghost-genius-linkedin-operations.js +282 -0
  83. package/dist/utils/ghost-genius-linkedin-operations.js.map +1 -0
  84. package/dist/utils/index.d.ts +29 -0
  85. package/dist/utils/index.d.ts.map +1 -0
  86. package/dist/utils/index.js +77 -0
  87. package/dist/utils/index.js.map +1 -0
  88. package/dist/utils/introduction-request-operations.d.ts +159 -0
  89. package/dist/utils/introduction-request-operations.d.ts.map +1 -0
  90. package/dist/utils/introduction-request-operations.js +481 -0
  91. package/dist/utils/introduction-request-operations.js.map +1 -0
  92. package/dist/utils/invitation-operations.d.ts +141 -0
  93. package/dist/utils/invitation-operations.d.ts.map +1 -0
  94. package/dist/utils/invitation-operations.js +749 -0
  95. package/dist/utils/invitation-operations.js.map +1 -0
  96. package/dist/utils/linkedin-account-operations.d.ts +45 -0
  97. package/dist/utils/linkedin-account-operations.d.ts.map +1 -0
  98. package/dist/utils/linkedin-account-operations.js +279 -0
  99. package/dist/utils/linkedin-account-operations.js.map +1 -0
  100. package/dist/utils/linkedin-account-relationship-operations.d.ts +77 -0
  101. package/dist/utils/linkedin-account-relationship-operations.d.ts.map +1 -0
  102. package/dist/utils/linkedin-account-relationship-operations.js +274 -0
  103. package/dist/utils/linkedin-account-relationship-operations.js.map +1 -0
  104. package/dist/utils/linkedin-data-operations.d.ts +102 -0
  105. package/dist/utils/linkedin-data-operations.d.ts.map +1 -0
  106. package/dist/utils/linkedin-data-operations.js +613 -0
  107. package/dist/utils/linkedin-data-operations.js.map +1 -0
  108. package/dist/utils/linkedin-identifier-utils.d.ts +31 -0
  109. package/dist/utils/linkedin-identifier-utils.d.ts.map +1 -0
  110. package/dist/utils/linkedin-identifier-utils.js +63 -0
  111. package/dist/utils/linkedin-identifier-utils.js.map +1 -0
  112. package/dist/utils/linkedin-profile-cache.d.ts +131 -0
  113. package/dist/utils/linkedin-profile-cache.d.ts.map +1 -0
  114. package/dist/utils/linkedin-profile-cache.js +418 -0
  115. package/dist/utils/linkedin-profile-cache.js.map +1 -0
  116. package/dist/utils/llm-inference-job-operations.d.ts +116 -0
  117. package/dist/utils/llm-inference-job-operations.d.ts.map +1 -0
  118. package/dist/utils/llm-inference-job-operations.js +266 -0
  119. package/dist/utils/llm-inference-job-operations.js.map +1 -0
  120. package/dist/utils/mapping-job-operations.d.ts +272 -0
  121. package/dist/utils/mapping-job-operations.d.ts.map +1 -0
  122. package/dist/utils/mapping-job-operations.js +833 -0
  123. package/dist/utils/mapping-job-operations.js.map +1 -0
  124. package/dist/utils/mapping-operations.d.ts +80 -0
  125. package/dist/utils/mapping-operations.d.ts.map +1 -0
  126. package/dist/utils/mapping-operations.js +318 -0
  127. package/dist/utils/mapping-operations.js.map +1 -0
  128. package/dist/utils/on-demand-mapping-operations.d.ts +199 -0
  129. package/dist/utils/on-demand-mapping-operations.d.ts.map +1 -0
  130. package/dist/utils/on-demand-mapping-operations.js +728 -0
  131. package/dist/utils/on-demand-mapping-operations.js.map +1 -0
  132. package/dist/utils/onboarding-operations.d.ts +53 -0
  133. package/dist/utils/onboarding-operations.d.ts.map +1 -0
  134. package/dist/utils/onboarding-operations.js +223 -0
  135. package/dist/utils/onboarding-operations.js.map +1 -0
  136. package/dist/utils/organization-assignment-job-operations.d.ts +258 -0
  137. package/dist/utils/organization-assignment-job-operations.d.ts.map +1 -0
  138. package/dist/utils/organization-assignment-job-operations.js +881 -0
  139. package/dist/utils/organization-assignment-job-operations.js.map +1 -0
  140. package/dist/utils/organization-assignment-operations.d.ts +59 -0
  141. package/dist/utils/organization-assignment-operations.d.ts.map +1 -0
  142. package/dist/utils/organization-assignment-operations.js +130 -0
  143. package/dist/utils/organization-assignment-operations.js.map +1 -0
  144. package/dist/utils/organization-operations.d.ts +275 -0
  145. package/dist/utils/organization-operations.d.ts.map +1 -0
  146. package/dist/utils/organization-operations.js +993 -0
  147. package/dist/utils/organization-operations.js.map +1 -0
  148. package/dist/utils/organization-relationship-operations.d.ts +59 -0
  149. package/dist/utils/organization-relationship-operations.d.ts.map +1 -0
  150. package/dist/utils/organization-relationship-operations.js +240 -0
  151. package/dist/utils/organization-relationship-operations.js.map +1 -0
  152. package/dist/utils/quota-operations.d.ts +107 -0
  153. package/dist/utils/quota-operations.d.ts.map +1 -0
  154. package/dist/utils/quota-operations.js +692 -0
  155. package/dist/utils/quota-operations.js.map +1 -0
  156. package/dist/utils/recursive-mapping-job-operations.d.ts +42 -0
  157. package/dist/utils/recursive-mapping-job-operations.d.ts.map +1 -0
  158. package/dist/utils/recursive-mapping-job-operations.js +169 -0
  159. package/dist/utils/recursive-mapping-job-operations.js.map +1 -0
  160. package/dist/utils/relationship-operations.d.ts +130 -0
  161. package/dist/utils/relationship-operations.d.ts.map +1 -0
  162. package/dist/utils/relationship-operations.js +329 -0
  163. package/dist/utils/relationship-operations.js.map +1 -0
  164. package/dist/utils/sales-pipeline-operations.d.ts +143 -0
  165. package/dist/utils/sales-pipeline-operations.d.ts.map +1 -0
  166. package/dist/utils/sales-pipeline-operations.js +649 -0
  167. package/dist/utils/sales-pipeline-operations.js.map +1 -0
  168. package/dist/utils/skills-operations.d.ts +117 -0
  169. package/dist/utils/skills-operations.d.ts.map +1 -0
  170. package/dist/utils/skills-operations.js +487 -0
  171. package/dist/utils/skills-operations.js.map +1 -0
  172. package/dist/utils/subscription-operations.d.ts +123 -0
  173. package/dist/utils/subscription-operations.d.ts.map +1 -0
  174. package/dist/utils/subscription-operations.js +391 -0
  175. package/dist/utils/subscription-operations.js.map +1 -0
  176. package/dist/utils/unipile-account-operations.d.ts +96 -0
  177. package/dist/utils/unipile-account-operations.d.ts.map +1 -0
  178. package/dist/utils/unipile-account-operations.js +255 -0
  179. package/dist/utils/unipile-account-operations.js.map +1 -0
  180. package/dist/utils/user-industry-operations.d.ts +80 -0
  181. package/dist/utils/user-industry-operations.d.ts.map +1 -0
  182. package/dist/utils/user-industry-operations.js +237 -0
  183. package/dist/utils/user-industry-operations.js.map +1 -0
  184. package/dist/utils/user-operations.d.ts +87 -0
  185. package/dist/utils/user-operations.d.ts.map +1 -0
  186. package/dist/utils/user-operations.js +212 -0
  187. package/dist/utils/user-operations.js.map +1 -0
  188. package/package.json +98 -0
@@ -0,0 +1,833 @@
1
+ "use strict";
2
+ /**
3
+ * =============================================================================
4
+ * MAPPING JOB OPERATIONS UTILITIES - CONSOLIDATED SCHEMA
5
+ * =============================================================================
6
+ * Utility functions for creating and managing mapping jobs with direct LinkedIn account references
7
+ *
8
+ * USAGE EXAMPLES:
9
+ *
10
+ * 1. SINGLE LINKEDIN ACCOUNT MAPPING JOB:
11
+ * ```typescript
12
+ * const result = await createMappingJobForLinkedInAccount({
13
+ * linkedinAccountId: 123,
14
+ * jobMetadata: {
15
+ * service: "feed_analyzer",
16
+ * triggered_by: "preparation_handler",
17
+ * linkedin_identifier: "ACoAABCDEFG"
18
+ * }
19
+ * });
20
+ * // Creates: 1 job with direct linkedin_account_id reference
21
+ * ```
22
+ *
23
+ * 2. BATCH PROCESSING (Multiple Jobs):
24
+ * ```typescript
25
+ * const results = await createMappingJobsForLinkedInAccounts([
26
+ * { linkedinAccountId: 123, metadata: { priority: "high" } },
27
+ * { linkedinAccountId: 456, metadata: { priority: "normal" } },
28
+ * { linkedinAccountId: 789, metadata: { priority: "low" } }
29
+ * ]);
30
+ * // Creates: 3 separate jobs, each with direct linkedin_account_id reference
31
+ * ```
32
+ *
33
+ * 3. PROCESSING LIFECYCLE:
34
+ * ```typescript
35
+ * // When processing starts
36
+ * await startMappingJob(jobId, {
37
+ * service_version: "v2.1.0",
38
+ * model_version: "gpt-4-turbo",
39
+ * started_by: "mapping_service_lambda"
40
+ * });
41
+ *
42
+ * // When processing completes
43
+ * await completeMappingJob(jobId, {
44
+ * completion_status: "success",
45
+ * processed_items: 150,
46
+ * completion_reason: "all_items_processed"
47
+ * });
48
+ * ```
49
+ */
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.createMappingJobForLinkedInAccount = createMappingJobForLinkedInAccount;
52
+ exports.createMappingJobsForLinkedInAccounts = createMappingJobsForLinkedInAccounts;
53
+ exports.startMappingJob = startMappingJob;
54
+ exports.completeMappingJob = completeMappingJob;
55
+ exports.validateMappingJobCompletion = validateMappingJobCompletion;
56
+ exports.getMappingJobById = getMappingJobById;
57
+ exports.getMappingJobWithLinkedInAccount = getMappingJobWithLinkedInAccount;
58
+ exports.getMappingJobsForLinkedInAccount = getMappingJobsForLinkedInAccount;
59
+ exports.getPendingMappingJobs = getPendingMappingJobs;
60
+ exports.getRunningMappingJobs = getRunningMappingJobs;
61
+ exports.getCompletedMappingJobs = getCompletedMappingJobs;
62
+ exports.getRelationshipScoresForMappingJob = getRelationshipScoresForMappingJob;
63
+ exports.getEnrichedRelationshipScoresForMappingJob = getEnrichedRelationshipScoresForMappingJob;
64
+ exports.deleteMappingJob = deleteMappingJob;
65
+ exports.createMappingJobWithSingleLinkedInAccount = createMappingJobWithSingleLinkedInAccount;
66
+ exports.createMappingJobWithLinkedInAccounts = createMappingJobWithLinkedInAccounts;
67
+ exports.checkMappingAvailability = checkMappingAvailability;
68
+ const pg_client_1 = require("../lib/pg-client");
69
+ const db_1 = require("../lib/db");
70
+ /**
71
+ * Creates a new mapping job for a single LinkedIn account
72
+ */
73
+ async function createMappingJobForLinkedInAccount(db, params) {
74
+ const { linkedinAccountId, jobMetadata = {}, companyMappingJobId = null, recursiveMappingJobId = null } = params;
75
+ (0, db_1.debugLogDbOperation)("insert", "monitoring.mapping_jobs", { linkedinAccountId, jobMetadata }, undefined, {
76
+ operation: "createMappingJobForLinkedInAccount",
77
+ linkedinAccountId,
78
+ });
79
+ try {
80
+ // Verify LinkedIn account exists
81
+ const accountCheckSql = `
82
+ SELECT id FROM linkedin.accounts WHERE id = $1 LIMIT 1
83
+ `;
84
+ const linkedinAccount = await (0, pg_client_1.query)(db, accountCheckSql, [
85
+ linkedinAccountId,
86
+ ]);
87
+ if (linkedinAccount.length === 0) {
88
+ throw new Error(`LinkedIn account with ID ${linkedinAccountId} not found`);
89
+ }
90
+ // Create the mapping job
91
+ const insertSql = `
92
+ INSERT INTO monitoring.mapping_jobs (linkedin_account_id, company_mapping_job_id, recursive_mapping_job_id, metadata, created_at, queued_at)
93
+ VALUES ($1, $2, $3, $4, NOW(), NOW())
94
+ RETURNING id, linkedin_account_id, company_mapping_job_id, recursive_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
95
+ `;
96
+ const mappingJob = await (0, pg_client_1.queryOne)(db, insertSql, [
97
+ linkedinAccountId,
98
+ companyMappingJobId,
99
+ recursiveMappingJobId,
100
+ JSON.stringify(jobMetadata),
101
+ ]);
102
+ if (!mappingJob) {
103
+ throw new Error("Failed to create mapping job");
104
+ }
105
+ return { mappingJob };
106
+ }
107
+ catch (error) {
108
+ console.error("Error creating mapping job for LinkedIn account:", error);
109
+ throw error;
110
+ }
111
+ }
112
+ /**
113
+ * Creates mapping jobs for multiple LinkedIn accounts
114
+ */
115
+ async function createMappingJobsForLinkedInAccounts(db, accountsData) {
116
+ if (accountsData.length === 0) {
117
+ return { mappingJobs: [] };
118
+ }
119
+ (0, db_1.debugLogDbOperation)("insert", "monitoring.mapping_jobs", { count: accountsData.length }, undefined, {
120
+ operation: "createMappingJobsForLinkedInAccounts",
121
+ accountCount: accountsData.length,
122
+ });
123
+ try {
124
+ // Verify all LinkedIn accounts exist
125
+ const linkedinAccountIds = accountsData.map(data => data.linkedinAccountId);
126
+ const placeholders = linkedinAccountIds.map((_, i) => `$${i + 1}`).join(", ");
127
+ const accountCheckSql = `
128
+ SELECT id FROM linkedin.accounts WHERE id IN (${placeholders})
129
+ `;
130
+ const existingAccounts = await (0, pg_client_1.query)(db, accountCheckSql, linkedinAccountIds);
131
+ const existingAccountIds = new Set(existingAccounts.map(acc => acc.id));
132
+ const missingAccountIds = linkedinAccountIds.filter(id => !existingAccountIds.has(id));
133
+ if (missingAccountIds.length > 0) {
134
+ throw new Error(`LinkedIn accounts not found: ${missingAccountIds.join(", ")}`);
135
+ }
136
+ // Create mapping jobs
137
+ const values = [];
138
+ const params = [];
139
+ let paramIndex = 1;
140
+ accountsData.forEach(data => {
141
+ values.push(`($${paramIndex}, NULL, NULL, $${paramIndex + 1}, NOW(), NOW())`);
142
+ params.push(data.linkedinAccountId, JSON.stringify(data.metadata || {}));
143
+ paramIndex += 2;
144
+ });
145
+ const insertSql = `
146
+ INSERT INTO monitoring.mapping_jobs (linkedin_account_id, company_mapping_job_id, recursive_mapping_job_id, metadata, created_at, queued_at)
147
+ VALUES ${values.join(", ")}
148
+ RETURNING id, linkedin_account_id, company_mapping_job_id, recursive_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
149
+ `;
150
+ const createdJobs = await (0, pg_client_1.query)(db, insertSql, params);
151
+ return { mappingJobs: createdJobs };
152
+ }
153
+ catch (error) {
154
+ console.error("Error creating mapping jobs for LinkedIn accounts:", error);
155
+ throw error;
156
+ }
157
+ }
158
+ /**
159
+ * Start a mapping job (mark as started)
160
+ */
161
+ async function startMappingJob(db, mappingJobId, startMetadata) {
162
+ (0, db_1.debugLogDbOperation)("update", "monitoring.mapping_jobs", { id: mappingJobId, startMetadata }, undefined, {
163
+ operation: "startMappingJob",
164
+ mappingJobId,
165
+ });
166
+ try {
167
+ if (startMetadata) {
168
+ // Get existing metadata and merge
169
+ const selectSql = `
170
+ SELECT metadata FROM monitoring.mapping_jobs WHERE id = $1 LIMIT 1
171
+ `;
172
+ const existingJob = await (0, pg_client_1.queryOne)(db, selectSql, [mappingJobId]);
173
+ const mergedMetadata = existingJob
174
+ ? { ...(existingJob.metadata || {}), ...startMetadata }
175
+ : startMetadata;
176
+ const updateSql = `
177
+ UPDATE monitoring.mapping_jobs
178
+ SET started_at = NOW(), metadata = $2
179
+ WHERE id = $1
180
+ RETURNING id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
181
+ `;
182
+ const updatedJob = await (0, pg_client_1.queryOne)(db, updateSql, [
183
+ mappingJobId,
184
+ JSON.stringify(mergedMetadata),
185
+ ]);
186
+ if (!updatedJob) {
187
+ throw new Error(`Mapping job with ID ${mappingJobId} not found`);
188
+ }
189
+ return updatedJob;
190
+ }
191
+ else {
192
+ const updateSql = `
193
+ UPDATE monitoring.mapping_jobs
194
+ SET started_at = NOW()
195
+ WHERE id = $1
196
+ RETURNING id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
197
+ `;
198
+ const updatedJob = await (0, pg_client_1.queryOne)(db, updateSql, [
199
+ mappingJobId,
200
+ ]);
201
+ if (!updatedJob) {
202
+ throw new Error(`Mapping job with ID ${mappingJobId} not found`);
203
+ }
204
+ return updatedJob;
205
+ }
206
+ }
207
+ catch (error) {
208
+ console.error("Error starting mapping job:", error);
209
+ throw error;
210
+ }
211
+ }
212
+ /**
213
+ * Complete a mapping job (mark as completed)
214
+ */
215
+ async function completeMappingJob(db, mappingJobId, completionMetadata) {
216
+ (0, db_1.debugLogDbOperation)("update", "monitoring.mapping_jobs", { id: mappingJobId, completionMetadata }, undefined, {
217
+ operation: "completeMappingJob",
218
+ mappingJobId,
219
+ });
220
+ try {
221
+ if (completionMetadata) {
222
+ // Get existing metadata and merge
223
+ const selectSql = `
224
+ SELECT metadata FROM monitoring.mapping_jobs WHERE id = $1 LIMIT 1
225
+ `;
226
+ const existingJob = await (0, pg_client_1.queryOne)(db, selectSql, [mappingJobId]);
227
+ const mergedMetadata = existingJob
228
+ ? { ...(existingJob.metadata || {}), ...completionMetadata }
229
+ : completionMetadata;
230
+ const updateSql = `
231
+ UPDATE monitoring.mapping_jobs
232
+ SET completed_at = NOW(), metadata = $2
233
+ WHERE id = $1
234
+ RETURNING id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
235
+ `;
236
+ const updatedJob = await (0, pg_client_1.queryOne)(db, updateSql, [
237
+ mappingJobId,
238
+ JSON.stringify(mergedMetadata),
239
+ ]);
240
+ if (!updatedJob) {
241
+ throw new Error(`Mapping job with ID ${mappingJobId} not found`);
242
+ }
243
+ return updatedJob;
244
+ }
245
+ else {
246
+ const updateSql = `
247
+ UPDATE monitoring.mapping_jobs
248
+ SET completed_at = NOW()
249
+ WHERE id = $1
250
+ RETURNING id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
251
+ `;
252
+ const updatedJob = await (0, pg_client_1.queryOne)(db, updateSql, [
253
+ mappingJobId,
254
+ ]);
255
+ if (!updatedJob) {
256
+ throw new Error(`Mapping job with ID ${mappingJobId} not found`);
257
+ }
258
+ return updatedJob;
259
+ }
260
+ }
261
+ catch (error) {
262
+ console.error("Error completing mapping job:", error);
263
+ throw error;
264
+ }
265
+ }
266
+ /**
267
+ * Validate that a mapping job exists and has been completed
268
+ */
269
+ async function validateMappingJobCompletion(db, mappingJobId) {
270
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { id: mappingJobId }, undefined, {
271
+ operation: "validateMappingJobCompletion",
272
+ mappingJobId,
273
+ });
274
+ try {
275
+ const sql = `
276
+ SELECT id, linkedin_account_id, company_mapping_job_id, recursive_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
277
+ FROM monitoring.mapping_jobs
278
+ WHERE id = $1
279
+ LIMIT 1
280
+ `;
281
+ const row = await (0, pg_client_1.queryOne)(db, sql, [mappingJobId]);
282
+ if (!row) {
283
+ return {
284
+ isValid: false,
285
+ error: `Mapping job with ID ${mappingJobId} not found`,
286
+ };
287
+ }
288
+ // Map snake_case to camelCase
289
+ const mappingJob = {
290
+ id: row.id,
291
+ linkedinAccountId: row.linkedin_account_id,
292
+ companyMappingJobId: row.company_mapping_job_id,
293
+ recursiveMappingJobId: row.recursive_mapping_job_id,
294
+ metadata: row.metadata || {},
295
+ createdAt: row.created_at,
296
+ queuedAt: row.queued_at,
297
+ startedAt: row.started_at,
298
+ completedAt: row.completed_at,
299
+ };
300
+ if (!mappingJob.completedAt) {
301
+ return {
302
+ isValid: false,
303
+ error: `Mapping job ${mappingJobId} has not been completed yet`,
304
+ };
305
+ }
306
+ return {
307
+ isValid: true,
308
+ mappingJob: mappingJob,
309
+ };
310
+ }
311
+ catch (error) {
312
+ console.error("Error validating mapping job completion:", error);
313
+ return {
314
+ isValid: false,
315
+ error: `Failed to validate mapping job: ${error instanceof Error ? error.message : String(error)}`,
316
+ };
317
+ }
318
+ }
319
+ /**
320
+ * Get mapping job by ID
321
+ * Returns basic mapping job information including completion status
322
+ *
323
+ * @param db - Database instance
324
+ * @param mappingJobId - Mapping job ID
325
+ * @returns Mapping job or null if not found
326
+ */
327
+ async function getMappingJobById(db, mappingJobId) {
328
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { mappingJobId }, undefined, {
329
+ operation: "getMappingJobById",
330
+ mappingJobId,
331
+ });
332
+ try {
333
+ const sql = `
334
+ SELECT id, linkedin_account_id, completed_at
335
+ FROM monitoring.mapping_jobs
336
+ WHERE id = $1
337
+ LIMIT 1
338
+ `;
339
+ const result = await (0, pg_client_1.queryOne)(db, sql, [mappingJobId]);
340
+ return result;
341
+ }
342
+ catch (error) {
343
+ console.error("Error getting mapping job by ID:", error);
344
+ throw error;
345
+ }
346
+ }
347
+ /**
348
+ * Get mapping job with LinkedIn account details
349
+ */
350
+ async function getMappingJobWithLinkedInAccount(db, mappingJobId) {
351
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs + linkedin.accounts + users", { mappingJobId }, undefined, {
352
+ operation: "getMappingJobWithLinkedInAccount",
353
+ mappingJobId,
354
+ });
355
+ try {
356
+ const sql = `
357
+ SELECT
358
+ -- Mapping job fields
359
+ mj.id as mj_id,
360
+ mj.linkedin_account_id as mj_linkedin_account_id,
361
+ mj.company_mapping_job_id as mj_company_mapping_job_id,
362
+ mj.recursive_mapping_job_id as mj_recursive_mapping_job_id,
363
+ mj.created_at as mj_created_at,
364
+ mj.queued_at as mj_queued_at,
365
+ mj.started_at as mj_started_at,
366
+ mj.completed_at as mj_completed_at,
367
+ mj.metadata as mj_metadata,
368
+ -- LinkedIn account fields
369
+ la.id as la_id,
370
+ la.user_id as la_user_id,
371
+ la.linkedin_identifier_acoa as la_linkedin_identifier_acoa,
372
+ la.public_identifier as la_public_identifier,
373
+ la.forager_id as la_forager_id,
374
+ la.first_name as la_first_name,
375
+ la.last_name as la_last_name,
376
+ la.headline as la_headline,
377
+ la.summary as la_summary,
378
+ la.location as la_location,
379
+ COALESCE(la.profile_image_cloudfront_url, la.profile_picture_url) as la_profile_picture_url,
380
+ NULL::text as la_profile_image_cloudfront_url,
381
+ la.follower_count as la_follower_count,
382
+ la.connections_count as la_connections_count,
383
+ la.profiles_updated_at as la_profiles_updated_at,
384
+ la.created_at as la_created_at,
385
+ -- User fields (optional)
386
+ u.id as u_id,
387
+ u.given_name as u_given_name,
388
+ u.family_name as u_family_name,
389
+ u.summary as u_summary,
390
+ u.embedding_summary as u_embedding_summary,
391
+ u.embedding as u_embedding,
392
+ u.created_at as u_created_at
393
+ FROM monitoring.mapping_jobs mj
394
+ INNER JOIN linkedin.accounts la ON mj.linkedin_account_id = la.id
395
+ LEFT JOIN public.users u ON la.user_id = u.id
396
+ WHERE mj.id = $1
397
+ LIMIT 1
398
+ `;
399
+ const result = await (0, pg_client_1.queryOne)(db, sql, [mappingJobId]);
400
+ if (!result) {
401
+ return null;
402
+ }
403
+ return {
404
+ mappingJob: {
405
+ id: result.mj_id,
406
+ linkedinAccountId: result.mj_linkedin_account_id,
407
+ companyMappingJobId: result.mj_company_mapping_job_id,
408
+ recursiveMappingJobId: result.mj_recursive_mapping_job_id,
409
+ createdAt: result.mj_created_at,
410
+ queuedAt: result.mj_queued_at,
411
+ startedAt: result.mj_started_at,
412
+ completedAt: result.mj_completed_at,
413
+ metadata: result.mj_metadata,
414
+ },
415
+ linkedinAccount: {
416
+ id: result.la_id,
417
+ user_id: result.la_user_id,
418
+ linkedin_identifier_acoa: result.la_linkedin_identifier_acoa,
419
+ public_identifier: result.la_public_identifier,
420
+ forager_id: result.la_forager_id,
421
+ first_name: result.la_first_name,
422
+ last_name: result.la_last_name,
423
+ headline: result.la_headline,
424
+ summary: result.la_summary,
425
+ location: result.la_location,
426
+ profile_picture_url: result.la_profile_picture_url,
427
+ profile_image_cloudfront_url: result.la_profile_image_cloudfront_url,
428
+ follower_count: result.la_follower_count,
429
+ connections_count: result.la_connections_count,
430
+ profiles_updated_at: result.la_profiles_updated_at,
431
+ created_at: result.la_created_at,
432
+ },
433
+ user: result.u_id
434
+ ? {
435
+ id: result.u_id,
436
+ given_name: result.u_given_name,
437
+ family_name: result.u_family_name,
438
+ summary: result.u_summary,
439
+ embedding_summary: result.u_embedding_summary,
440
+ embedding: result.u_embedding,
441
+ created_at: result.u_created_at,
442
+ }
443
+ : undefined,
444
+ };
445
+ }
446
+ catch (error) {
447
+ console.error("Error getting mapping job with LinkedIn account:", error);
448
+ throw error;
449
+ }
450
+ }
451
+ /**
452
+ * Get all mapping jobs for a LinkedIn account
453
+ */
454
+ async function getMappingJobsForLinkedInAccount(db, linkedinAccountId, options) {
455
+ const { limit = 50, includeCompleted = true } = options || {};
456
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { linkedinAccountId, limit, includeCompleted }, undefined, {
457
+ operation: "getMappingJobsForLinkedInAccount",
458
+ linkedinAccountId,
459
+ });
460
+ try {
461
+ const sql = includeCompleted
462
+ ? `
463
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
464
+ FROM monitoring.mapping_jobs
465
+ WHERE linkedin_account_id = $1
466
+ ORDER BY created_at DESC
467
+ LIMIT $2
468
+ `
469
+ : `
470
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
471
+ FROM monitoring.mapping_jobs
472
+ WHERE linkedin_account_id = $1 AND completed_at IS NULL
473
+ ORDER BY created_at DESC
474
+ LIMIT $2
475
+ `;
476
+ return await (0, pg_client_1.query)(db, sql, [linkedinAccountId, limit]);
477
+ }
478
+ catch (error) {
479
+ console.error("Error getting mapping jobs for LinkedIn account:", error);
480
+ throw error;
481
+ }
482
+ }
483
+ /**
484
+ * Get pending mapping jobs (not started yet)
485
+ */
486
+ async function getPendingMappingJobs(db, options) {
487
+ const { limit = 100, linkedinAccountId } = options || {};
488
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { limit, linkedinAccountId, status: "pending" }, undefined, {
489
+ operation: "getPendingMappingJobs",
490
+ });
491
+ try {
492
+ const sql = linkedinAccountId
493
+ ? `
494
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
495
+ FROM monitoring.mapping_jobs
496
+ WHERE started_at IS NULL AND linkedin_account_id = $1
497
+ ORDER BY queued_at ASC
498
+ LIMIT $2
499
+ `
500
+ : `
501
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
502
+ FROM monitoring.mapping_jobs
503
+ WHERE started_at IS NULL
504
+ ORDER BY queued_at ASC
505
+ LIMIT $1
506
+ `;
507
+ const params = linkedinAccountId ? [linkedinAccountId, limit] : [limit];
508
+ return await (0, pg_client_1.query)(db, sql, params);
509
+ }
510
+ catch (error) {
511
+ console.error("Error getting pending mapping jobs:", error);
512
+ throw error;
513
+ }
514
+ }
515
+ /**
516
+ * Get running mapping jobs (started but not completed)
517
+ */
518
+ async function getRunningMappingJobs(db, options) {
519
+ const { limit = 100, linkedinAccountId } = options || {};
520
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { limit, linkedinAccountId, status: "running" }, undefined, {
521
+ operation: "getRunningMappingJobs",
522
+ });
523
+ try {
524
+ const sql = linkedinAccountId
525
+ ? `
526
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
527
+ FROM monitoring.mapping_jobs
528
+ WHERE started_at IS NOT NULL AND completed_at IS NULL AND linkedin_account_id = $1
529
+ ORDER BY started_at ASC
530
+ LIMIT $2
531
+ `
532
+ : `
533
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
534
+ FROM monitoring.mapping_jobs
535
+ WHERE started_at IS NOT NULL AND completed_at IS NULL
536
+ ORDER BY started_at ASC
537
+ LIMIT $1
538
+ `;
539
+ const params = linkedinAccountId ? [linkedinAccountId, limit] : [limit];
540
+ return await (0, pg_client_1.query)(db, sql, params);
541
+ }
542
+ catch (error) {
543
+ console.error("Error getting running mapping jobs:", error);
544
+ throw error;
545
+ }
546
+ }
547
+ /**
548
+ * Get completed mapping jobs
549
+ */
550
+ async function getCompletedMappingJobs(db, options) {
551
+ const { limit = 100, linkedinAccountId, since } = options || {};
552
+ (0, db_1.debugLogDbOperation)("select", "monitoring.mapping_jobs", { limit, linkedinAccountId, since, status: "completed" }, undefined, {
553
+ operation: "getCompletedMappingJobs",
554
+ });
555
+ try {
556
+ let sql = `
557
+ SELECT id, linkedin_account_id, company_mapping_job_id, metadata, created_at, queued_at, started_at, completed_at
558
+ FROM monitoring.mapping_jobs
559
+ WHERE completed_at IS NOT NULL
560
+ `;
561
+ const params = [];
562
+ let paramIndex = 1;
563
+ if (linkedinAccountId) {
564
+ sql += ` AND linkedin_account_id = $${paramIndex}`;
565
+ params.push(linkedinAccountId);
566
+ paramIndex++;
567
+ }
568
+ if (since) {
569
+ sql += ` AND completed_at >= $${paramIndex}`;
570
+ params.push(since);
571
+ paramIndex++;
572
+ }
573
+ sql += ` ORDER BY completed_at DESC LIMIT $${paramIndex}`;
574
+ params.push(limit);
575
+ return await (0, pg_client_1.query)(db, sql, params);
576
+ }
577
+ catch (error) {
578
+ console.error("Error getting completed mapping jobs:", error);
579
+ throw error;
580
+ }
581
+ }
582
+ /**
583
+ * Get relationship scores for a mapping job
584
+ */
585
+ async function getRelationshipScoresForMappingJob(db, mappingJobId, options) {
586
+ const { limit = 50, minScore } = options || {};
587
+ (0, db_1.debugLogDbOperation)("select", "linkedin.relationships", { mappingJobId, limit, minScore }, undefined, {
588
+ operation: "getRelationshipScoresForMappingJob",
589
+ mappingJobId,
590
+ });
591
+ try {
592
+ const sql = minScore !== undefined
593
+ ? `
594
+ SELECT id, linkedin_account_id_a, linkedin_account_id_b, score, model_version, analysis_type, mapping_job_id, metadata, created_at
595
+ FROM linkedin.relationships
596
+ WHERE mapping_job_id = $1 AND score >= $2
597
+ ORDER BY score DESC
598
+ LIMIT $3
599
+ `
600
+ : `
601
+ SELECT id, linkedin_account_id_a, linkedin_account_id_b, score, model_version, analysis_type, mapping_job_id, metadata, created_at
602
+ FROM linkedin.relationships
603
+ WHERE mapping_job_id = $1
604
+ ORDER BY score DESC
605
+ LIMIT $2
606
+ `;
607
+ const params = minScore !== undefined ? [mappingJobId, minScore, limit] : [mappingJobId, limit];
608
+ return await (0, pg_client_1.query)(db, sql, params);
609
+ }
610
+ catch (error) {
611
+ console.error("Error getting relationship scores for mapping job:", error);
612
+ throw error;
613
+ }
614
+ }
615
+ /**
616
+ * Gets enriched relationship scores for a specific mapping job with LinkedIn account details
617
+ * This function properly filters by mapping job ID at the database level (avoiding the bug
618
+ * where getRelationshipScoresForAccount followed by client-side filtering would miss records)
619
+ *
620
+ * @param db - Database instance
621
+ * @param mappingJobId - The mapping job ID to filter by
622
+ * @param mainLinkedinAccountId - The main LinkedIn account ID (to determine which is the "other" account)
623
+ * @param options - Query options
624
+ * @returns Promise resolving to array of enriched relationship scores
625
+ */
626
+ async function getEnrichedRelationshipScoresForMappingJob(db, mappingJobId, mainLinkedinAccountId, options) {
627
+ const { limit = 50, minScore, sortOrder = "desc" } = options || {};
628
+ (0, db_1.debugLogDbOperation)("select", "linkedin.relationships + linkedin.accounts", { mappingJobId, mainLinkedinAccountId, limit, minScore }, undefined, {
629
+ operation: "getEnrichedRelationshipScoresForMappingJob",
630
+ mappingJobId,
631
+ mainLinkedinAccountId,
632
+ });
633
+ try {
634
+ let sql = `
635
+ SELECT
636
+ r.score,
637
+ r.model_version,
638
+ r.analysis_type,
639
+ r.mapping_job_id,
640
+ r.metadata,
641
+ r.created_at,
642
+ CASE
643
+ WHEN r.linkedin_account_id_a = $2
644
+ THEN r.linkedin_account_id_b
645
+ ELSE r.linkedin_account_id_a
646
+ END as other_account_id,
647
+ CASE
648
+ WHEN r.linkedin_account_id_a = $2
649
+ THEN account_b.linkedin_identifier_acoa
650
+ ELSE account_a.linkedin_identifier_acoa
651
+ END as other_account_linkedin_identifier_acoa,
652
+ CASE
653
+ WHEN r.linkedin_account_id_a = $2
654
+ THEN account_b.public_identifier
655
+ ELSE account_a.public_identifier
656
+ END as other_account_public_identifier,
657
+ CASE
658
+ WHEN r.linkedin_account_id_a = $2
659
+ THEN account_b.first_name
660
+ ELSE account_a.first_name
661
+ END as other_account_first_name,
662
+ CASE
663
+ WHEN r.linkedin_account_id_a = $2
664
+ THEN account_b.last_name
665
+ ELSE account_a.last_name
666
+ END as other_account_last_name,
667
+ CASE
668
+ WHEN r.linkedin_account_id_a = $2
669
+ THEN account_b.headline
670
+ ELSE account_a.headline
671
+ END as other_account_headline,
672
+ CASE
673
+ WHEN r.linkedin_account_id_a = $2
674
+ THEN account_b.profile_image_cloudfront_url
675
+ ELSE account_a.profile_image_cloudfront_url
676
+ END as other_account_profile_picture_url
677
+ FROM linkedin.relationships r
678
+ INNER JOIN linkedin.accounts account_a ON r.linkedin_account_id_a = account_a.id
679
+ INNER JOIN linkedin.accounts account_b ON r.linkedin_account_id_b = account_b.id
680
+ WHERE r.mapping_job_id = $1
681
+ `;
682
+ const params = [mappingJobId, mainLinkedinAccountId];
683
+ let paramIndex = 3;
684
+ if (minScore !== undefined) {
685
+ sql += ` AND r.score >= $${paramIndex}`;
686
+ params.push(minScore);
687
+ paramIndex++;
688
+ }
689
+ sql += ` ORDER BY r.score ${sortOrder === "desc" ? "DESC" : "ASC"} LIMIT $${paramIndex}`;
690
+ params.push(limit);
691
+ const results = await (0, pg_client_1.query)(db, sql, params);
692
+ return results.map(result => ({
693
+ score: result.score,
694
+ modelVersion: result.model_version,
695
+ analysisType: result.analysis_type,
696
+ mappingJobId: result.mapping_job_id,
697
+ metadata: result.metadata,
698
+ createdAt: result.created_at,
699
+ otherAccount: {
700
+ id: result.other_account_id,
701
+ linkedinIdentifierAcoa: result.other_account_linkedin_identifier_acoa,
702
+ publicIdentifier: result.other_account_public_identifier,
703
+ firstName: result.other_account_first_name,
704
+ lastName: result.other_account_last_name,
705
+ headline: result.other_account_headline,
706
+ profilePictureUrl: result.other_account_profile_picture_url,
707
+ },
708
+ }));
709
+ }
710
+ catch (error) {
711
+ console.error("Error getting enriched relationship scores for mapping job:", error);
712
+ throw error;
713
+ }
714
+ }
715
+ /**
716
+ * Delete a mapping job and all related data
717
+ */
718
+ async function deleteMappingJob(db, mappingJobId) {
719
+ (0, db_1.debugLogDbOperation)("delete", "monitoring.mapping_jobs", { mappingJobId }, undefined, {
720
+ operation: "deleteMappingJob",
721
+ mappingJobId,
722
+ });
723
+ try {
724
+ const sql = `
725
+ DELETE FROM monitoring.mapping_jobs
726
+ WHERE id = $1
727
+ RETURNING id
728
+ `;
729
+ const result = await (0, pg_client_1.query)(db, sql, [mappingJobId]);
730
+ return result.length > 0;
731
+ }
732
+ catch (error) {
733
+ console.error("Error deleting mapping job:", error);
734
+ throw error;
735
+ }
736
+ }
737
+ // =============================================================================
738
+ // LEGACY COMPATIBILITY (DEPRECATED)
739
+ // =============================================================================
740
+ /**
741
+ * @deprecated Use createMappingJobForLinkedInAccount instead
742
+ * This function is kept for backward compatibility but will be removed
743
+ */
744
+ async function createMappingJobWithSingleLinkedInAccount(db, params) {
745
+ console.warn("createMappingJobWithSingleLinkedInAccount is deprecated. Use createMappingJobForLinkedInAccount instead.");
746
+ return await createMappingJobForLinkedInAccount(db, {
747
+ linkedinAccountId: params.linkedinAccountId,
748
+ jobMetadata: {
749
+ ...params.jobMetadata,
750
+ ...params.linkedinAccountMetadata,
751
+ },
752
+ });
753
+ }
754
+ /**
755
+ * @deprecated Use createMappingJobsForLinkedInAccounts instead
756
+ */
757
+ async function createMappingJobWithLinkedInAccounts(db, params) {
758
+ console.warn("createMappingJobWithLinkedInAccounts is deprecated. Use createMappingJobsForLinkedInAccounts instead.");
759
+ return await createMappingJobsForLinkedInAccounts(db, params.linkedinAccounts.map(acc => ({
760
+ linkedinAccountId: acc.linkedinAccountId,
761
+ metadata: {
762
+ ...params.jobMetadata,
763
+ ...acc.metadata,
764
+ },
765
+ })));
766
+ }
767
+ /**
768
+ * Check if a target LinkedIn profile has been mapped before
769
+ * Uses UNION query to check both on-demand and regular mapping jobs
770
+ *
771
+ * @param db - Database connection
772
+ * @param targetLinkedInIdentifier - LinkedIn identifier (ACoA format) to check
773
+ * @returns Promise<MappingAvailabilityResult> - Availability information
774
+ */
775
+ async function checkMappingAvailability(db, targetLinkedInIdentifier) {
776
+ // First check if the target LinkedIn account exists
777
+ const targetCheckSql = `
778
+ SELECT id, linkedin_identifier_acoa
779
+ FROM linkedin.accounts
780
+ WHERE linkedin_identifier_acoa = $1
781
+ LIMIT 1
782
+ `;
783
+ const targetAccount = await (0, pg_client_1.query)(db, targetCheckSql, [targetLinkedInIdentifier]);
784
+ const targetExists = targetAccount.length > 0;
785
+ // Check for existing mappings using UNION of both tables
786
+ const mappingCheckSql = `
787
+ -- Check on-demand mapping jobs by internal_identifier_acoa
788
+ SELECT
789
+ 'on_demand' as source,
790
+ odmj.id as job_id,
791
+ odmj.created_at,
792
+ mj.completed_at
793
+ FROM monitoring.on_demand_mapping_jobs odmj
794
+ LEFT JOIN monitoring.mapping_jobs mj ON odmj.mapping_job_id = mj.id
795
+ WHERE odmj.internal_identifier_acoa = $1
796
+
797
+ UNION ALL
798
+
799
+ -- Check regular mapping jobs by target LinkedIn account
800
+ SELECT
801
+ 'regular' as source,
802
+ mj.id as job_id,
803
+ mj.created_at,
804
+ mj.completed_at
805
+ FROM monitoring.mapping_jobs mj
806
+ JOIN linkedin.accounts la ON mj.linkedin_account_id = la.id
807
+ WHERE la.linkedin_identifier_acoa = $1
808
+
809
+ ORDER BY created_at DESC
810
+ LIMIT 1
811
+ `;
812
+ const mappingCheck = await (0, pg_client_1.query)(db, mappingCheckSql, [
813
+ targetLinkedInIdentifier,
814
+ ]);
815
+ const hasExistingMapping = mappingCheck.length > 0;
816
+ let mappingDetails = undefined;
817
+ if (hasExistingMapping) {
818
+ const row = mappingCheck[0];
819
+ mappingDetails = {
820
+ source: row.source,
821
+ jobId: Number(row.job_id),
822
+ createdAt: new Date(row.created_at),
823
+ completedAt: row.completed_at ? new Date(row.completed_at) : null,
824
+ };
825
+ }
826
+ return {
827
+ isAvailable: targetExists && !hasExistingMapping,
828
+ targetExists,
829
+ hasExistingMapping,
830
+ mappingDetails,
831
+ };
832
+ }
833
+ //# sourceMappingURL=mapping-job-operations.js.map