Skip to content
Merged
Show file tree
Hide file tree
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
10 changes: 5 additions & 5 deletions packages/database/src/crossAppContracts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ContentType } from "@repo/content-model";
import { Enums } from "./dbTypes";

type LocalRef = {
export type LocalRef = {
// This localId is expected to be unique within the current space
localId: string;
};
Expand All @@ -12,24 +12,24 @@ type DbRef = {
};

// Generalized reference
type Ref = LocalRef | DbRef;
export type Ref = LocalRef | DbRef;

// Common attributes for most types
type CrossAppBase = LocalRef & {
export type CrossAppBase = LocalRef & {
createdAt: Date;
modifiedAt?: Date;
author: Ref;
};

// An inline vector semantic embedding
type CrossAppEmbedding = {
export type CrossAppEmbedding = {
value: number[];
embedding?: Enums<"EmbeddingName">;
};

// A Content object. It can be put inline inside a concept.
// Missing CrossAppBase attributes are inferred from enclosing object.
type InlineCrossAppContent = Partial<CrossAppBase> & {
export type InlineCrossAppContent = Partial<CrossAppBase> & {
value: string;
embedding?: CrossAppEmbedding;
scale?: Enums<"Scale">;
Expand Down
91 changes: 91 additions & 0 deletions packages/database/src/lib/crossAppConverters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
LocalRef,
Ref,
CrossAppEmbedding,
InlineCrossAppContent,
CrossAppBase,
CrossAppNode,
} from "../crossAppContracts";
import { LocalContentDataInput } from "../inputTypes";
import { Enums, CompositeTypes } from "../dbTypes";

type InlineEmbeddingInput = CompositeTypes<"inline_embedding_input">;
type InlineAbstractBase = Partial<CrossAppBase>;

const decodeLocalRef = <LocalVarName extends string>(
ref: LocalRef | InlineAbstractBase | undefined,
localVarName: LocalVarName,
): Record<LocalVarName, string> | Record<string, never> => {
if (ref === undefined) return {};
if ("localId" in ref) {
return {
[localVarName]: ref.localId,
} as Record<LocalVarName, string>;
}
return {};
};

const decodeRef = <DbVarName extends string, LocalVarName extends string>(
ref: Ref | undefined,
dbVarName: DbVarName,
localVarName: LocalVarName,
):
| Record<DbVarName, number>
| Record<LocalVarName, string>
| Record<string, never> => {
if (ref === undefined) return {};
if ("dbId" in ref)
return { [dbVarName]: ref.dbId } as Record<DbVarName, number>;
return decodeLocalRef(ref, localVarName);
};

const crossAppEmbeddingToDbEmbedding = (
embedding: CrossAppEmbedding | undefined,
): InlineEmbeddingInput | undefined =>
embedding === undefined
? undefined
: {
vector: embedding.value,
model: embedding.embedding || "openai_text_embedding_3_small_1536",
};

const filterUndefined = <T extends Record<string, unknown>>(data: T): T => {
return Object.fromEntries(
Object.entries(data).filter(([, v]) => v !== undefined),
) as T;
};

const inlineCrossAppContentToDbContent = (
content: InlineCrossAppContent | undefined,
variant: Enums<"ContentVariant">,
): LocalContentDataInput | undefined => {
if (content === undefined) return undefined;
return filterUndefined<LocalContentDataInput>({
...decodeLocalRef(content, "source_local_id"),
text: content.value,
scale: content.scale || "document",
content_type: content.contentType || "text/plain",
variant,
created: content.createdAt?.toISOString(),
last_modified: content.modifiedAt?.toISOString(),
...decodeRef(content.author, "author_id", "author_local_id"),
embedding_inline: crossAppEmbeddingToDbEmbedding(content.embedding),
});
};

export const crossAppNodeToDbContent = (
node: CrossAppNode | undefined,
variant: "full" | "direct",
): LocalContentDataInput | undefined => {
if (node === undefined) return undefined;
const content = node.content[variant];
return inlineCrossAppContentToDbContent(
{
...content,
createdAt: content.createdAt || node.createdAt,
modifiedAt: content.modifiedAt || node.modifiedAt,
author: content.author || node.author,
},
variant,
);
};