Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/lib/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ export class SourceService {
}),
);

const inputLookup = new Map<string, SourceCreateInput>();
const makeLookupKey = (
userId: string,
type: SourceType,
externalId: string,
) => `${userId}:${type}:${externalId}`;
Comment on lines +80 to +84
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current method of creating a lookup key by concatenating userId, type, and externalId with a colon separator is not robust. If userId or externalId were to contain a colon, it could lead to key collisions and incorrect data association. For example, userId: 'user:conversation', type: 'document', externalId: 'ext1' would produce the same key as userId: 'user', type: 'conversation', externalId: 'document:ext1'. This would cause one of the inputs to be overwritten in the lookup map, and could lead to incorrect metadata being associated with an inserted source.

A safer approach is to use a method that guarantees uniqueness, such as JSON stringifying an array of the key components. This will prevent any potential key collisions.

Suggested change
const makeLookupKey = (
userId: string,
type: SourceType,
externalId: string,
) => `${userId}:${type}:${externalId}`;
const makeLookupKey = (
userId: string,
type: SourceType,
externalId: string,
) => JSON.stringify([userId, type, externalId]);

inputs.forEach((input) => {
inputLookup.set(
makeLookupKey(input.userId, input.sourceType, input.externalId),
input,
);
});

const inserted = await this.db
.insert(sources)
.values(insertRows)
Expand All @@ -85,9 +98,15 @@ export class SourceService {
.returning();

// 2. Handle payloads
for (let i = 0; i < inserted.length; i++) {
const row = inserted[i]!;
const input = inputs[i]!;
for (const row of inserted) {
const lookupKey = makeLookupKey(row.userId, row.type, row.externalId);
const input = inputLookup.get(lookupKey);
if (!input) {
console.warn(
`No matching input found for inserted source ${row.id} (${lookupKey})`,
);
continue;
}
const key = `${input.userId}/${row.id}`;

// Inline payload if small enough or content provided
Expand Down
Loading