@lhremote/core 0.0.0 → 0.1.0
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/LICENSE +661 -0
- package/dist/cdp/client.d.ts +100 -0
- package/dist/cdp/client.d.ts.map +1 -0
- package/dist/cdp/client.integration.test.d.ts +2 -0
- package/dist/cdp/client.integration.test.d.ts.map +1 -0
- package/dist/cdp/client.integration.test.js +70 -0
- package/dist/cdp/client.integration.test.js.map +1 -0
- package/dist/cdp/client.js +286 -0
- package/dist/cdp/client.js.map +1 -0
- package/dist/cdp/client.test.d.ts +2 -0
- package/dist/cdp/client.test.d.ts.map +1 -0
- package/dist/cdp/client.test.js +269 -0
- package/dist/cdp/client.test.js.map +1 -0
- package/dist/cdp/discovery.d.ts +14 -0
- package/dist/cdp/discovery.d.ts.map +1 -0
- package/dist/cdp/discovery.integration.test.d.ts +2 -0
- package/dist/cdp/discovery.integration.test.d.ts.map +1 -0
- package/dist/cdp/discovery.integration.test.js +25 -0
- package/dist/cdp/discovery.integration.test.js.map +1 -0
- package/dist/cdp/discovery.js +31 -0
- package/dist/cdp/discovery.js.map +1 -0
- package/dist/cdp/discovery.test.d.ts +2 -0
- package/dist/cdp/discovery.test.d.ts.map +1 -0
- package/dist/cdp/discovery.test.js +54 -0
- package/dist/cdp/discovery.test.js.map +1 -0
- package/dist/cdp/errors.d.ts +28 -0
- package/dist/cdp/errors.d.ts.map +1 -0
- package/dist/cdp/errors.js +40 -0
- package/dist/cdp/errors.js.map +1 -0
- package/dist/cdp/errors.test.d.ts +2 -0
- package/dist/cdp/errors.test.d.ts.map +1 -0
- package/dist/cdp/errors.test.js +35 -0
- package/dist/cdp/errors.test.js.map +1 -0
- package/dist/cdp/index.d.ts +5 -0
- package/dist/cdp/index.d.ts.map +1 -0
- package/dist/cdp/index.js +5 -0
- package/dist/cdp/index.js.map +1 -0
- package/dist/cdp/instance-discovery.d.ts +30 -0
- package/dist/cdp/instance-discovery.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.integration.test.d.ts +2 -0
- package/dist/cdp/instance-discovery.integration.test.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.integration.test.js +34 -0
- package/dist/cdp/instance-discovery.integration.test.js.map +1 -0
- package/dist/cdp/instance-discovery.js +130 -0
- package/dist/cdp/instance-discovery.js.map +1 -0
- package/dist/cdp/instance-discovery.test.d.ts +2 -0
- package/dist/cdp/instance-discovery.test.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.test.js +110 -0
- package/dist/cdp/instance-discovery.test.js.map +1 -0
- package/dist/cdp/testing/launch-chromium.d.ts +24 -0
- package/dist/cdp/testing/launch-chromium.d.ts.map +1 -0
- package/dist/cdp/testing/launch-chromium.js +90 -0
- package/dist/cdp/testing/launch-chromium.js.map +1 -0
- package/dist/db/client.d.ts +13 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.integration.test.d.ts +2 -0
- package/dist/db/client.integration.test.d.ts.map +1 -0
- package/dist/db/client.integration.test.js +59 -0
- package/dist/db/client.integration.test.js.map +1 -0
- package/dist/db/client.js +17 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/client.test.d.ts +2 -0
- package/dist/db/client.test.d.ts.map +1 -0
- package/dist/db/client.test.js +46 -0
- package/dist/db/client.test.js.map +1 -0
- package/dist/db/discovery.d.ts +14 -0
- package/dist/db/discovery.d.ts.map +1 -0
- package/dist/db/discovery.integration.test.d.ts +2 -0
- package/dist/db/discovery.integration.test.d.ts.map +1 -0
- package/dist/db/discovery.integration.test.js +99 -0
- package/dist/db/discovery.integration.test.js.map +1 -0
- package/dist/db/discovery.js +74 -0
- package/dist/db/discovery.js.map +1 -0
- package/dist/db/discovery.test.d.ts +2 -0
- package/dist/db/discovery.test.d.ts.map +1 -0
- package/dist/db/discovery.test.js +123 -0
- package/dist/db/discovery.test.js.map +1 -0
- package/dist/db/errors.d.ts +21 -0
- package/dist/db/errors.d.ts.map +1 -0
- package/dist/db/errors.js +33 -0
- package/dist/db/errors.js.map +1 -0
- package/dist/db/errors.test.d.ts +2 -0
- package/dist/db/errors.test.d.ts.map +1 -0
- package/dist/db/errors.test.js +32 -0
- package/dist/db/errors.test.js.map +1 -0
- package/dist/db/index.d.ts +5 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +5 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/repositories/index.d.ts +2 -0
- package/dist/db/repositories/index.d.ts.map +1 -0
- package/dist/db/repositories/index.js +2 -0
- package/dist/db/repositories/index.js.map +1 -0
- package/dist/db/repositories/profile.d.ts +32 -0
- package/dist/db/repositories/profile.d.ts.map +1 -0
- package/dist/db/repositories/profile.integration.test.d.ts +2 -0
- package/dist/db/repositories/profile.integration.test.d.ts.map +1 -0
- package/dist/db/repositories/profile.integration.test.js +119 -0
- package/dist/db/repositories/profile.integration.test.js.map +1 -0
- package/dist/db/repositories/profile.js +126 -0
- package/dist/db/repositories/profile.js.map +1 -0
- package/dist/db/repositories/profile.test.d.ts +2 -0
- package/dist/db/repositories/profile.test.d.ts.map +1 -0
- package/dist/db/repositories/profile.test.js +126 -0
- package/dist/db/repositories/profile.test.js.map +1 -0
- package/dist/db/testing/create-fixture.d.ts +8 -0
- package/dist/db/testing/create-fixture.d.ts.map +1 -0
- package/dist/db/testing/create-fixture.js +286 -0
- package/dist/db/testing/create-fixture.js.map +1 -0
- package/dist/db/testing/open-fixture.d.ts +14 -0
- package/dist/db/testing/open-fixture.d.ts.map +1 -0
- package/dist/db/testing/open-fixture.js +21 -0
- package/dist/db/testing/open-fixture.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/services/app.d.ts +62 -0
- package/dist/services/app.d.ts.map +1 -0
- package/dist/services/app.js +198 -0
- package/dist/services/app.js.map +1 -0
- package/dist/services/app.test.d.ts +2 -0
- package/dist/services/app.test.d.ts.map +1 -0
- package/dist/services/app.test.js +265 -0
- package/dist/services/app.test.js.map +1 -0
- package/dist/services/errors.d.ts +45 -0
- package/dist/services/errors.d.ts.map +1 -0
- package/dist/services/errors.js +66 -0
- package/dist/services/errors.js.map +1 -0
- package/dist/services/errors.test.d.ts +2 -0
- package/dist/services/errors.test.d.ts.map +1 -0
- package/dist/services/errors.test.js +71 -0
- package/dist/services/errors.test.js.map +1 -0
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/instance-lifecycle.d.ts +38 -0
- package/dist/services/instance-lifecycle.d.ts.map +1 -0
- package/dist/services/instance-lifecycle.js +87 -0
- package/dist/services/instance-lifecycle.js.map +1 -0
- package/dist/services/instance-lifecycle.test.d.ts +2 -0
- package/dist/services/instance-lifecycle.test.d.ts.map +1 -0
- package/dist/services/instance-lifecycle.test.js +152 -0
- package/dist/services/instance-lifecycle.test.js.map +1 -0
- package/dist/services/instance.d.ts +50 -0
- package/dist/services/instance.d.ts.map +1 -0
- package/dist/services/instance.js +121 -0
- package/dist/services/instance.js.map +1 -0
- package/dist/services/instance.test.d.ts +2 -0
- package/dist/services/instance.test.d.ts.map +1 -0
- package/dist/services/instance.test.js +181 -0
- package/dist/services/instance.test.js.map +1 -0
- package/dist/services/launcher.d.ts +51 -0
- package/dist/services/launcher.d.ts.map +1 -0
- package/dist/services/launcher.js +147 -0
- package/dist/services/launcher.js.map +1 -0
- package/dist/services/launcher.test.d.ts +2 -0
- package/dist/services/launcher.test.d.ts.map +1 -0
- package/dist/services/launcher.test.js +126 -0
- package/dist/services/launcher.test.js.map +1 -0
- package/dist/services/profile.d.ts +44 -0
- package/dist/services/profile.d.ts.map +1 -0
- package/dist/services/profile.js +83 -0
- package/dist/services/profile.js.map +1 -0
- package/dist/services/profile.test.d.ts +2 -0
- package/dist/services/profile.test.d.ts.map +1 -0
- package/dist/services/profile.test.js +145 -0
- package/dist/services/profile.test.js.map +1 -0
- package/dist/services/status.d.ts +33 -0
- package/dist/services/status.d.ts.map +1 -0
- package/dist/services/status.js +76 -0
- package/dist/services/status.js.map +1 -0
- package/dist/services/status.test.d.ts +2 -0
- package/dist/services/status.test.d.ts.map +1 -0
- package/dist/services/status.test.js +207 -0
- package/dist/services/status.test.js.map +1 -0
- package/dist/testing/e2e-helpers.d.ts +41 -0
- package/dist/testing/e2e-helpers.d.ts.map +1 -0
- package/dist/testing/e2e-helpers.js +111 -0
- package/dist/testing/e2e-helpers.js.map +1 -0
- package/dist/types/account.d.ts +13 -0
- package/dist/types/account.d.ts.map +1 -0
- package/dist/types/account.js +2 -0
- package/dist/types/account.js.map +1 -0
- package/dist/types/account.test.d.ts +2 -0
- package/dist/types/account.test.d.ts.map +1 -0
- package/dist/types/account.test.js +24 -0
- package/dist/types/account.test.js.map +1 -0
- package/dist/types/cdp.d.ts +18 -0
- package/dist/types/cdp.d.ts.map +1 -0
- package/dist/types/cdp.js +2 -0
- package/dist/types/cdp.js.map +1 -0
- package/dist/types/cdp.test.d.ts +2 -0
- package/dist/types/cdp.test.d.ts.map +1 -0
- package/dist/types/cdp.test.js +28 -0
- package/dist/types/cdp.test.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/instance.d.ts +36 -0
- package/dist/types/instance.d.ts.map +1 -0
- package/dist/types/instance.js +8 -0
- package/dist/types/instance.js.map +1 -0
- package/dist/types/instance.test.d.ts +2 -0
- package/dist/types/instance.test.d.ts.map +1 -0
- package/dist/types/instance.test.js +57 -0
- package/dist/types/instance.test.js.map +1 -0
- package/dist/types/profile.d.ts +50 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +8 -0
- package/dist/types/profile.js.map +1 -0
- package/dist/types/profile.test.d.ts +2 -0
- package/dist/types/profile.test.d.ts.map +1 -0
- package/dist/types/profile.test.js +103 -0
- package/dist/types/profile.test.js.map +1 -0
- package/package.json +20 -8
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
import { DatabaseClient } from "../client.js";
|
|
3
|
+
import { ProfileNotFoundError } from "../errors.js";
|
|
4
|
+
import { FIXTURE_PATH } from "../testing/open-fixture.js";
|
|
5
|
+
import { ProfileRepository } from "./profile.js";
|
|
6
|
+
describe("ProfileRepository (integration)", () => {
|
|
7
|
+
let client;
|
|
8
|
+
let repo;
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
client = new DatabaseClient(FIXTURE_PATH);
|
|
11
|
+
repo = new ProfileRepository(client);
|
|
12
|
+
});
|
|
13
|
+
afterAll(() => {
|
|
14
|
+
client.close();
|
|
15
|
+
});
|
|
16
|
+
describe("findById", () => {
|
|
17
|
+
it("assembles a full profile from the real schema", () => {
|
|
18
|
+
const profile = repo.findById(1);
|
|
19
|
+
expect(profile.id).toBe(1);
|
|
20
|
+
// Mini profile
|
|
21
|
+
expect(profile.miniProfile.firstName).toBe("Ada");
|
|
22
|
+
expect(profile.miniProfile.lastName).toBe("Lovelace");
|
|
23
|
+
expect(profile.miniProfile.headline).toBe("Principal Analytical Engine Programmer");
|
|
24
|
+
expect(profile.miniProfile.avatar).toBe("https://example.test/avatars/ada.jpg");
|
|
25
|
+
// External IDs
|
|
26
|
+
expect(profile.externalIds.length).toBeGreaterThanOrEqual(2);
|
|
27
|
+
const publicId = profile.externalIds.find((e) => e.typeGroup === "public");
|
|
28
|
+
expect(publicId?.externalId).toBe("ada-lovelace-test");
|
|
29
|
+
const memberId = profile.externalIds.find((e) => e.typeGroup === "member");
|
|
30
|
+
expect(memberId?.externalId).toBe("100000001");
|
|
31
|
+
expect(memberId?.isMemberId).toBe(true);
|
|
32
|
+
// Current position
|
|
33
|
+
expect(profile.currentPosition).not.toBeNull();
|
|
34
|
+
expect(profile.currentPosition?.company).toBe("Babbage Industries");
|
|
35
|
+
expect(profile.currentPosition?.title).toBe("Lead Programmer");
|
|
36
|
+
// Position history with year-month formatting
|
|
37
|
+
expect(profile.positions.length).toBeGreaterThanOrEqual(2);
|
|
38
|
+
const currentPos = profile.positions.find((p) => p.isCurrent);
|
|
39
|
+
expect(currentPos?.company).toBe("Babbage Industries");
|
|
40
|
+
expect(currentPos?.startDate).toBe("2020-03");
|
|
41
|
+
expect(currentPos?.endDate).toBeNull();
|
|
42
|
+
const pastPos = profile.positions.find((p) => !p.isCurrent);
|
|
43
|
+
expect(pastPos?.company).toBe("Difference Engine Co");
|
|
44
|
+
expect(pastPos?.startDate).toBe("2015-09");
|
|
45
|
+
expect(pastPos?.endDate).toBe("2019-12");
|
|
46
|
+
// Education with year-only formatting
|
|
47
|
+
expect(profile.education.length).toBeGreaterThanOrEqual(1);
|
|
48
|
+
const edu = profile.education.find((e) => e.school === "University of Mathematica");
|
|
49
|
+
expect(edu?.degree).toBe("BSc");
|
|
50
|
+
expect(edu?.field).toBe("Mathematics");
|
|
51
|
+
expect(edu?.startDate).toBe("2011");
|
|
52
|
+
expect(edu?.endDate).toBe("2015");
|
|
53
|
+
// Skills (joined from skills table)
|
|
54
|
+
expect(profile.skills.length).toBeGreaterThanOrEqual(2);
|
|
55
|
+
const skillNames = profile.skills.map((s) => s.name);
|
|
56
|
+
expect(skillNames).toContain("Algorithm Design");
|
|
57
|
+
expect(skillNames).toContain("Mechanical Computing");
|
|
58
|
+
// Emails
|
|
59
|
+
expect(profile.emails).toContain("ada@example.test");
|
|
60
|
+
});
|
|
61
|
+
it("assembles a minimal profile without optional data", () => {
|
|
62
|
+
const profile = repo.findById(2);
|
|
63
|
+
expect(profile.id).toBe(2);
|
|
64
|
+
expect(profile.miniProfile.firstName).toBe("Charlie");
|
|
65
|
+
expect(profile.miniProfile.lastName).toBeNull();
|
|
66
|
+
expect(profile.miniProfile.headline).toBeNull();
|
|
67
|
+
expect(profile.miniProfile.avatar).toBeNull();
|
|
68
|
+
expect(profile.currentPosition).toBeNull();
|
|
69
|
+
expect(profile.positions).toEqual([]);
|
|
70
|
+
expect(profile.education).toEqual([]);
|
|
71
|
+
expect(profile.skills).toEqual([]);
|
|
72
|
+
expect(profile.emails).toEqual([]);
|
|
73
|
+
});
|
|
74
|
+
it("assembles a profile with multiple emails", () => {
|
|
75
|
+
const profile = repo.findById(3);
|
|
76
|
+
expect(profile.emails).toHaveLength(2);
|
|
77
|
+
expect(profile.emails).toContain("grace@example.test");
|
|
78
|
+
expect(profile.emails).toContain("grace.personal@example.test");
|
|
79
|
+
});
|
|
80
|
+
it("throws ProfileNotFoundError for a nonexistent ID", () => {
|
|
81
|
+
expect(() => repo.findById(999)).toThrow(ProfileNotFoundError);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("findByPublicId", () => {
|
|
85
|
+
it("resolves a public ID to the correct profile", () => {
|
|
86
|
+
const profile = repo.findByPublicId("ada-lovelace-test");
|
|
87
|
+
expect(profile.id).toBe(1);
|
|
88
|
+
expect(profile.miniProfile.firstName).toBe("Ada");
|
|
89
|
+
});
|
|
90
|
+
it("resolves another public ID", () => {
|
|
91
|
+
const profile = repo.findByPublicId("grace-hopper-test");
|
|
92
|
+
expect(profile.id).toBe(3);
|
|
93
|
+
expect(profile.miniProfile.firstName).toBe("Grace");
|
|
94
|
+
});
|
|
95
|
+
it("throws ProfileNotFoundError for an unknown public ID", () => {
|
|
96
|
+
expect(() => repo.findByPublicId("no-such-person")).toThrow(ProfileNotFoundError);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe("cross-table consistency", () => {
|
|
100
|
+
it("external IDs reference the correct person", () => {
|
|
101
|
+
const profile = repo.findById(1);
|
|
102
|
+
// Every external ID should belong to person 1 — verified by
|
|
103
|
+
// the JOIN in the query, but this tests the assembly is coherent.
|
|
104
|
+
for (const extId of profile.externalIds) {
|
|
105
|
+
expect(extId.externalId).toBeTruthy();
|
|
106
|
+
expect(["member", "public", "hash", "avatar"]).toContain(extId.typeGroup);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
it("current position and position history agree on current role", () => {
|
|
110
|
+
const profile = repo.findById(1);
|
|
111
|
+
const currentPos = profile.positions.find((p) => p.isCurrent);
|
|
112
|
+
expect(profile.currentPosition).not.toBeNull();
|
|
113
|
+
expect(currentPos).toBeDefined();
|
|
114
|
+
// The current_position table and positions table should show the same company
|
|
115
|
+
expect(profile.currentPosition?.company).toBe(currentPos?.company);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=profile.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.integration.test.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ProfileNotFoundError } from "../errors.js";
|
|
2
|
+
function formatDate(year, month) {
|
|
3
|
+
if (year == null)
|
|
4
|
+
return null;
|
|
5
|
+
if (month == null)
|
|
6
|
+
return String(year);
|
|
7
|
+
return `${String(year)}-${String(month).padStart(2, "0")}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Read-only repository for assembling {@link Profile} objects from
|
|
11
|
+
* LinkedHelper's SQLite database.
|
|
12
|
+
*/
|
|
13
|
+
export class ProfileRepository {
|
|
14
|
+
stmtPersonById;
|
|
15
|
+
stmtPersonByPublicId;
|
|
16
|
+
stmtMiniProfile;
|
|
17
|
+
stmtExternalIds;
|
|
18
|
+
stmtCurrentPosition;
|
|
19
|
+
stmtPositions;
|
|
20
|
+
stmtEducation;
|
|
21
|
+
stmtSkills;
|
|
22
|
+
stmtEmails;
|
|
23
|
+
constructor(client) {
|
|
24
|
+
const { db } = client;
|
|
25
|
+
this.stmtPersonById = db.prepare("SELECT id FROM people WHERE id = ?");
|
|
26
|
+
this.stmtPersonByPublicId = db.prepare(`SELECT p.id
|
|
27
|
+
FROM people p
|
|
28
|
+
JOIN person_external_ids pei ON p.id = pei.person_id
|
|
29
|
+
WHERE pei.type_group = 'public' AND pei.external_id = ?`);
|
|
30
|
+
this.stmtMiniProfile = db.prepare(`SELECT first_name, last_name, headline, avatar
|
|
31
|
+
FROM person_mini_profile WHERE person_id = ?`);
|
|
32
|
+
this.stmtExternalIds = db.prepare(`SELECT external_id, type_group, is_member_id
|
|
33
|
+
FROM person_external_ids WHERE person_id = ?`);
|
|
34
|
+
this.stmtCurrentPosition = db.prepare(`SELECT company, position
|
|
35
|
+
FROM person_current_position WHERE person_id = ?`);
|
|
36
|
+
this.stmtPositions = db.prepare(`SELECT company_name, title, start_year, start_month,
|
|
37
|
+
end_year, end_month, is_default
|
|
38
|
+
FROM person_positions WHERE person_id = ?`);
|
|
39
|
+
this.stmtEducation = db.prepare(`SELECT school_name, degree_name, field_of_study, start_year, end_year
|
|
40
|
+
FROM person_education WHERE person_id = ?`);
|
|
41
|
+
this.stmtSkills = db.prepare(`SELECT s.name
|
|
42
|
+
FROM person_skill ps
|
|
43
|
+
JOIN skills s ON ps.skill_id = s.id
|
|
44
|
+
WHERE ps.person_id = ?`);
|
|
45
|
+
this.stmtEmails = db.prepare(`SELECT email FROM person_email WHERE person_id = ?`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Looks up a profile by its internal database ID.
|
|
49
|
+
*
|
|
50
|
+
* @throws {ProfileNotFoundError} if no person exists with the given ID.
|
|
51
|
+
*/
|
|
52
|
+
findById(id) {
|
|
53
|
+
const row = this.stmtPersonById.get(id);
|
|
54
|
+
if (!row)
|
|
55
|
+
throw new ProfileNotFoundError(id);
|
|
56
|
+
return this.assembleProfile(row.id);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Looks up a profile by LinkedIn public ID (the slug from a profile URL).
|
|
60
|
+
*
|
|
61
|
+
* @throws {ProfileNotFoundError} if no person matches the public ID.
|
|
62
|
+
*/
|
|
63
|
+
findByPublicId(slug) {
|
|
64
|
+
const row = this.stmtPersonByPublicId.get(slug);
|
|
65
|
+
if (!row)
|
|
66
|
+
throw new ProfileNotFoundError(slug);
|
|
67
|
+
return this.assembleProfile(row.id);
|
|
68
|
+
}
|
|
69
|
+
assembleProfile(personId) {
|
|
70
|
+
const miniRow = this.stmtMiniProfile.get(personId);
|
|
71
|
+
const miniProfile = miniRow
|
|
72
|
+
? {
|
|
73
|
+
firstName: miniRow.first_name,
|
|
74
|
+
lastName: miniRow.last_name,
|
|
75
|
+
headline: miniRow.headline,
|
|
76
|
+
avatar: miniRow.avatar,
|
|
77
|
+
}
|
|
78
|
+
: { firstName: "", lastName: null, headline: null, avatar: null };
|
|
79
|
+
const externalIds = this.stmtExternalIds
|
|
80
|
+
.all(personId)
|
|
81
|
+
.map((r) => ({
|
|
82
|
+
externalId: r.external_id,
|
|
83
|
+
typeGroup: r.type_group,
|
|
84
|
+
isMemberId: r.is_member_id === 1,
|
|
85
|
+
}));
|
|
86
|
+
const cpRow = this.stmtCurrentPosition.get(personId);
|
|
87
|
+
const currentPosition = cpRow
|
|
88
|
+
? { company: cpRow.company, title: cpRow.position }
|
|
89
|
+
: null;
|
|
90
|
+
const positions = this.stmtPositions
|
|
91
|
+
.all(personId)
|
|
92
|
+
.map((r) => ({
|
|
93
|
+
company: r.company_name,
|
|
94
|
+
title: r.title,
|
|
95
|
+
startDate: formatDate(r.start_year, r.start_month),
|
|
96
|
+
endDate: formatDate(r.end_year, r.end_month),
|
|
97
|
+
isCurrent: r.is_default != null,
|
|
98
|
+
}));
|
|
99
|
+
const education = this.stmtEducation
|
|
100
|
+
.all(personId)
|
|
101
|
+
.map((r) => ({
|
|
102
|
+
school: r.school_name,
|
|
103
|
+
degree: r.degree_name,
|
|
104
|
+
field: r.field_of_study,
|
|
105
|
+
startDate: formatDate(r.start_year, null),
|
|
106
|
+
endDate: formatDate(r.end_year, null),
|
|
107
|
+
}));
|
|
108
|
+
const skills = this.stmtSkills
|
|
109
|
+
.all(personId)
|
|
110
|
+
.map((r) => ({ name: r.name }));
|
|
111
|
+
const emails = this.stmtEmails
|
|
112
|
+
.all(personId)
|
|
113
|
+
.map((r) => r.email);
|
|
114
|
+
return {
|
|
115
|
+
id: personId,
|
|
116
|
+
miniProfile,
|
|
117
|
+
externalIds,
|
|
118
|
+
currentPosition,
|
|
119
|
+
positions,
|
|
120
|
+
education,
|
|
121
|
+
skills,
|
|
122
|
+
emails,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.test.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/profile.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { DatabaseClient } from "../client.js";
|
|
3
|
+
import { ProfileNotFoundError } from "../errors.js";
|
|
4
|
+
import { openFixture } from "../testing/open-fixture.js";
|
|
5
|
+
import { ProfileRepository } from "./profile.js";
|
|
6
|
+
describe("ProfileRepository", () => {
|
|
7
|
+
let db;
|
|
8
|
+
let client;
|
|
9
|
+
let repo;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
db = openFixture();
|
|
12
|
+
client = { db };
|
|
13
|
+
repo = new ProfileRepository(client);
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
db.close();
|
|
17
|
+
});
|
|
18
|
+
describe("findById", () => {
|
|
19
|
+
it("returns a fully assembled profile", () => {
|
|
20
|
+
const profile = repo.findById(1);
|
|
21
|
+
expect(profile.id).toBe(1);
|
|
22
|
+
expect(profile.miniProfile).toEqual({
|
|
23
|
+
firstName: "Ada",
|
|
24
|
+
lastName: "Lovelace",
|
|
25
|
+
headline: "Principal Analytical Engine Programmer",
|
|
26
|
+
avatar: "https://example.test/avatars/ada.jpg",
|
|
27
|
+
});
|
|
28
|
+
expect(profile.externalIds).toHaveLength(3);
|
|
29
|
+
expect(profile.externalIds).toContainEqual({
|
|
30
|
+
externalId: "ada-lovelace-test",
|
|
31
|
+
typeGroup: "public",
|
|
32
|
+
isMemberId: false,
|
|
33
|
+
});
|
|
34
|
+
expect(profile.externalIds).toContainEqual({
|
|
35
|
+
externalId: "100000001",
|
|
36
|
+
typeGroup: "member",
|
|
37
|
+
isMemberId: true,
|
|
38
|
+
});
|
|
39
|
+
expect(profile.externalIds).toContainEqual({
|
|
40
|
+
externalId: "h4sh-ada-001",
|
|
41
|
+
typeGroup: "hash",
|
|
42
|
+
isMemberId: false,
|
|
43
|
+
});
|
|
44
|
+
expect(profile.currentPosition).toEqual({
|
|
45
|
+
company: "Babbage Industries",
|
|
46
|
+
title: "Lead Programmer",
|
|
47
|
+
});
|
|
48
|
+
expect(profile.positions).toHaveLength(2);
|
|
49
|
+
expect(profile.positions).toContainEqual({
|
|
50
|
+
company: "Babbage Industries",
|
|
51
|
+
title: "Lead Programmer",
|
|
52
|
+
startDate: "2020-03",
|
|
53
|
+
endDate: null,
|
|
54
|
+
isCurrent: true,
|
|
55
|
+
});
|
|
56
|
+
expect(profile.positions).toContainEqual({
|
|
57
|
+
company: "Difference Engine Co",
|
|
58
|
+
title: "Junior Analyst",
|
|
59
|
+
startDate: "2015-09",
|
|
60
|
+
endDate: "2019-12",
|
|
61
|
+
isCurrent: false,
|
|
62
|
+
});
|
|
63
|
+
expect(profile.education).toHaveLength(2);
|
|
64
|
+
expect(profile.education).toContainEqual({
|
|
65
|
+
school: "University of Mathematica",
|
|
66
|
+
degree: "BSc",
|
|
67
|
+
field: "Mathematics",
|
|
68
|
+
startDate: "2011",
|
|
69
|
+
endDate: "2015",
|
|
70
|
+
});
|
|
71
|
+
expect(profile.education).toContainEqual({
|
|
72
|
+
school: "Royal Polytechnic",
|
|
73
|
+
degree: "MSc",
|
|
74
|
+
field: "Computational Logic",
|
|
75
|
+
startDate: "2015",
|
|
76
|
+
endDate: "2017",
|
|
77
|
+
});
|
|
78
|
+
expect(profile.skills).toEqual([
|
|
79
|
+
{ name: "Algorithm Design" },
|
|
80
|
+
{ name: "Mechanical Computing" },
|
|
81
|
+
]);
|
|
82
|
+
expect(profile.emails).toEqual(["ada@example.test"]);
|
|
83
|
+
});
|
|
84
|
+
it("throws ProfileNotFoundError for a missing ID", () => {
|
|
85
|
+
expect(() => repo.findById(999)).toThrow(ProfileNotFoundError);
|
|
86
|
+
expect(() => repo.findById(999)).toThrow("Profile not found for id 999");
|
|
87
|
+
});
|
|
88
|
+
it("handles a person with minimal data", () => {
|
|
89
|
+
const profile = repo.findById(2);
|
|
90
|
+
expect(profile.id).toBe(2);
|
|
91
|
+
expect(profile.miniProfile.firstName).toBe("Charlie");
|
|
92
|
+
expect(profile.miniProfile.lastName).toBeNull();
|
|
93
|
+
expect(profile.miniProfile.headline).toBeNull();
|
|
94
|
+
expect(profile.miniProfile.avatar).toBeNull();
|
|
95
|
+
expect(profile.externalIds).toHaveLength(1);
|
|
96
|
+
expect(profile.currentPosition).toBeNull();
|
|
97
|
+
expect(profile.positions).toEqual([]);
|
|
98
|
+
expect(profile.education).toEqual([]);
|
|
99
|
+
expect(profile.skills).toEqual([]);
|
|
100
|
+
expect(profile.emails).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
it("handles multiple emails", () => {
|
|
103
|
+
const profile = repo.findById(3);
|
|
104
|
+
expect(profile.emails).toHaveLength(2);
|
|
105
|
+
expect(profile.emails).toContain("grace@example.test");
|
|
106
|
+
expect(profile.emails).toContain("grace.personal@example.test");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe("findByPublicId", () => {
|
|
110
|
+
it("finds a profile by LinkedIn public ID slug", () => {
|
|
111
|
+
const profile = repo.findByPublicId("ada-lovelace-test");
|
|
112
|
+
expect(profile.id).toBe(1);
|
|
113
|
+
expect(profile.miniProfile.firstName).toBe("Ada");
|
|
114
|
+
});
|
|
115
|
+
it("finds another profile by public ID", () => {
|
|
116
|
+
const profile = repo.findByPublicId("grace-hopper-test");
|
|
117
|
+
expect(profile.id).toBe(3);
|
|
118
|
+
expect(profile.miniProfile.firstName).toBe("Grace");
|
|
119
|
+
});
|
|
120
|
+
it("throws ProfileNotFoundError for an unknown slug", () => {
|
|
121
|
+
expect(() => repo.findByPublicId("nonexistent")).toThrow(ProfileNotFoundError);
|
|
122
|
+
expect(() => repo.findByPublicId("nonexistent")).toThrow('Profile not found for public ID "nonexistent"');
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=profile.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.test.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,EAAqB,CAAC;IAC1B,IAAI,MAAsB,CAAC;IAC3B,IAAI,IAAuB,CAAC;IAE5B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,GAAG,WAAW,EAAE,CAAC;QACnB,MAAM,GAAG,EAAE,EAAE,EAAoB,CAAC;QAClC,IAAI,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAEjC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC;gBAClC,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,wCAAwC;gBAClD,MAAM,EAAE,sCAAsC;aAC/C,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,cAAc,CAAC;gBACzC,UAAU,EAAE,mBAAmB;gBAC/B,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,KAAK;aAClB,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,cAAc,CAAC;gBACzC,UAAU,EAAE,WAAW;gBACvB,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,cAAc,CAAC;gBACzC,UAAU,EAAE,cAAc;gBAC1B,SAAS,EAAE,MAAM;gBACjB,UAAU,EAAE,KAAK;aAClB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC;gBACtC,OAAO,EAAE,oBAAoB;gBAC7B,KAAK,EAAE,iBAAiB;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC;gBACvC,OAAO,EAAE,oBAAoB;gBAC7B,KAAK,EAAE,iBAAiB;gBACxB,SAAS,EAAE,SAAS;gBACpB,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC;gBACvC,OAAO,EAAE,sBAAsB;gBAC/B,KAAK,EAAE,gBAAgB;gBACvB,SAAS,EAAE,SAAS;gBACpB,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,KAAK;aACjB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC;gBACvC,MAAM,EAAE,2BAA2B;gBACnC,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,aAAa;gBACpB,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC;gBACvC,MAAM,EAAE,mBAAmB;gBAC3B,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,qBAAqB;gBAC5B,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;gBAC7B,EAAE,IAAI,EAAE,kBAAkB,EAAE;gBAC5B,EAAE,IAAI,EAAE,sBAAsB,EAAE;aACjC,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAEjC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC9C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC3C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAEjC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;YACvD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;YAEzD,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;YAEzD,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CACtD,oBAAoB,CACrB,CAAC;YACF,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CACtD,+CAA+C,CAChD,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-fixture.d.ts","sourceRoot":"","sources":["../../../src/db/testing/create-fixture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|