Skip to content

Commit

Permalink
packages/modeldb: add $primary syntax for defining primary keys manually
Browse files Browse the repository at this point in the history
  • Loading branch information
joeltg committed Jan 16, 2025
1 parent cdc9527 commit ae44d40
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 21 deletions.
24 changes: 9 additions & 15 deletions packages/modeldb/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,22 @@ export function parseConfig(init: ModelSchema): Config {
const relations: Relation[] = []
const models: Model[] = []

for (const [modelName, { $indexes, ...rest }] of Object.entries(init)) {
assert(
namePattern.test(modelName),
`error defining ${modelName}: expected model name to match /^[a-zA-Z0-9$:_\\-\\.]+$/`,
)
for (const [modelName, { $indexes, $primary, ...rest }] of Object.entries(init)) {
if (!namePattern.test(modelName)) {
throw new Error(`error defining ${modelName}: expected model name to match /^[a-zA-Z0-9$:_\\-\\.]+$/`)
}

const primaryKeys: string[] = []
const indexes: string[][] = []
const properties: Record<string, Property> = {}

for (const [propertyName, propertyType] of Object.entries(rest)) {
assert(
!Array.isArray(propertyType),
`error defining ${modelName}: invalid property type for ${propertyName}: ${propertyType}`,
)
assert(
typeof propertyType !== "function",
`error defining ${modelName}: invalid property type for ${propertyName}`,
)

const [property, primary] = parseProperty(modelName, propertyName, propertyType)
if (primary) {
if (primary || $primary === property.name) {
assert(property.kind === "primitive", "primary keys must have type string")
assert(property.type === "string", "primary keys must have type string")
assert(property.nullable === false, "primary keys canont be nullable")

primaryKeys.push(propertyName)
}

Expand Down
12 changes: 7 additions & 5 deletions packages/modeldb/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type PropertyType =
/** property name, or property names joined by slashes */
export type IndexInit = string

export type ModelSchema = Record<string, { $indexes?: IndexInit[] } | Record<string, PropertyType>>
export type ModelSchema = Record<string, { $indexes?: IndexInit[]; $primary?: string } | Record<string, PropertyType>>

// These are more structured representations of the schema defined by ModelSchema that are easier
// to work with at runtime
Expand Down Expand Up @@ -76,7 +76,7 @@ export type QueryParams = {
offset?: number
}

// Derives typed PropertyValue = PrimaryKeyValue | PrimitiveValue | ReferenceValue | RelationValue | JSONValue
// Derives typed PropertyValue = PrimitiveValue | ReferenceValue | RelationValue | JSONValue
// from a given PropertyType

export type DerivePropertyType<T extends PropertyType> = T extends "primary"
Expand Down Expand Up @@ -108,13 +108,15 @@ export type DerivePropertyType<T extends PropertyType> = T extends "primary"
: never

export type DeriveModelTypes<T extends ModelSchema> = {
[K in keyof T as Exclude<K, "$indexes">]: {
[P in keyof T[K] as Exclude<P, "$indexes">]: T[K][P] extends PropertyType ? DerivePropertyType<T[K][P]> : never
[K in keyof T as Exclude<K, "$indexes" | "$primary">]: {
[P in keyof T[K] as Exclude<P, "$indexes" | "$primary">]: T[K][P] extends PropertyType
? DerivePropertyType<T[K][P]>
: never
}
}

export type DeriveModelType<T extends { $indexes?: IndexInit[] } | Record<string, PropertyType>> = {
[P in keyof T as Exclude<P, "$indexes">]: T[P] extends PropertyType ? DerivePropertyType<T[P]> : never
[P in keyof T as Exclude<P, "$indexes" | "$primary">]: T[P] extends PropertyType ? DerivePropertyType<T[P]> : never
}

export type Contract<T extends ModelSchema = ModelSchema> = {
Expand Down
4 changes: 3 additions & 1 deletion packages/modeldb/test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ test("parse config", (t) => {
},

room: {
$primary: "id",
id: "primary",
creator: "@user",
members: "@user[]",
$indexes: ["members", "id/creator"],
},

message: {
id: "primary",
$primary: "id",
id: "string",
room: "@room",
sender: "@user",
content: "string",
Expand Down

0 comments on commit ae44d40

Please sign in to comment.