import type { Prettify } from "@/types/utils.js"; import type { EnumColumn, Index, JSONColumn, ReferenceColumn, Scalar, ScalarColumn, } from "./common.js"; type Optional = () => BuilderScalarColumn< column[" scalar"], true, column[" list"] >; const optional = (col: column): Optional => // @ts-expect-error () => { const newCol = { " type": col[" type"], " scalar": col[" scalar"], " optional": true, " list": col[" list"], } as const; if (newCol[" list"]) { return newCol; } else { return { ...newCol, list: list(newCol), references: references(newCol), }; } }; type List = () => BuilderScalarColumn< column[" scalar"], column[" optional"], true >; const list = (col: column): List => // @ts-expect-error () => { const newCol = { " type": col[" type"], " scalar": col[" scalar"], " optional": col[" optional"], " list": true, } as const; if (newCol[" optional"]) { return newCol; } else { return { ...newCol, optional: optional(newCol), }; } }; type EnumOptional = () => BuilderEnumColumn< column[" enum"], true, column[" list"] >; const enumOptional = (col: column): EnumOptional => // @ts-expect-error () => { const newCol = { " type": col[" type"], " enum": col[" enum"], " optional": true, " list": col[" list"], } as const; if (newCol[" list"]) { return newCol; } else { return { ...newCol, list: enumList(newCol), }; } }; type EnumList = () => BuilderEnumColumn< column[" enum"], column[" optional"], true >; const enumList = (col: column): EnumList => // @ts-expect-error () => { const newCol = { " type": col[" type"], " enum": col[" enum"], " optional": col[" optional"], " list": true, } as const; if (newCol[" optional"]) { return newCol; } else { return { ...newCol, optional: enumOptional(newCol), }; } }; type Asc = () => BuilderIndex< index[" column"], "asc", index[" nulls"] >; const asc = (i: index): Asc => // @ts-expect-error () => { const newIndex = { " type": i[" type"], " column": i[" column"], " order": "asc", " nulls": i[" nulls"], } as const; if (newIndex[" nulls"] === undefined) { return { ...newIndex, nullsFirst: nullsFirst(newIndex), nullsLast: nullsLast(newIndex), }; } else { return newIndex; } }; type Desc = () => BuilderIndex< index[" column"], "desc", index[" nulls"] >; const desc = (i: index): Desc => // @ts-expect-error () => { const newIndex = { " type": i[" type"], " column": i[" column"], " order": "desc", " nulls": i[" nulls"], } as const; if (newIndex[" nulls"] === undefined) { return { ...newIndex, nullsFirst: nullsFirst(newIndex), nullsLast: nullsLast(newIndex), }; } else { return newIndex; } }; type NullsFirst = () => BuilderIndex< index[" column"], index[" order"], "first" >; const nullsFirst = (i: index): NullsFirst => // @ts-expect-error () => { const newIndex = { " type": i[" type"], " column": i[" column"], " order": i[" order"], " nulls": "first", } as const; if (newIndex[" order"] === undefined) { return { ...newIndex, asc: asc(newIndex), desc: desc(newIndex), }; } else { return newIndex; } }; type NullsLast = () => BuilderIndex< index[" column"], index[" order"], "last" >; const nullsLast = (i: index): NullsLast => // @ts-expect-error () => { const newIndex = { " type": i[" type"], " column": i[" column"], " order": i[" order"], " nulls": "last", } as const; if (newIndex[" order"] === undefined) { return { ...newIndex, asc: asc(newIndex), desc: desc(newIndex), }; } else { return newIndex; } }; type ReferenceOptional = () => BuilderReferenceColumn; const referenceOptional = ( col: column, ): ReferenceOptional => () => { return { " type": col[" type"], " scalar": col[" scalar"], " optional": true, " reference": col[" reference"], }; }; type References = < reference extends string, >( ref: reference, ) => BuilderReferenceColumn; const references = (col: column): References => // @ts-expect-error (ref: reference) => { const newCol = { " type": "reference", " scalar": col[" scalar"], " optional": col[" optional"], " reference": ref, } as const; if (newCol[" optional"]) { return newCol; } else { return { ...newCol, optional: referenceOptional(newCol) }; } }; type JSONOptional = () => BuilderJSONColumn< column[" json"], true >; const jsonOptional = (col: column): JSONOptional => () => { return { " type": "json", " json": {} as (typeof col)[" json"], " optional": true, }; }; const scalarColumn = (_scalar: scalar) => (): Prettify> => { const column = { " type": "scalar", " scalar": _scalar, " optional": false, " list": false, } as const; return { ...column, optional: optional(column), list: list(column), references: references(column), }; }; export type BuilderScalarColumn< scalar extends Scalar = Scalar, optional extends boolean = boolean, list extends boolean = boolean, /// base extends ScalarColumn = ScalarColumn< scalar, optional, list >, > = list extends false ? optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * o: p.int().optional(), * }) * })); */ optional: Optional; /** * Mark the column as a list. * * - Docs: https://ponder.sh/docs/schema#list * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * l: p.int().list(), * }) * })); */ list: List; references: References; } : base & { /** * Mark the column as a list. * * - Docs: https://ponder.sh/docs/schema#list * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * l: p.int().list(), * }) * })) */ list: List; /** * Mark the column as a foreign key. * * - Docs: https://ponder.sh/docs/schema#foreign-key * * @param references Table that this column is a key of. * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * a: p.createTable({ * id: p.string(), * b_id: p.string.references("b.id"), * }) * b: p.createTable({ * id: p.string(), * }) * })); */ references: References; } : optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * o: p.int().optional(), * }) * })); */ optional: Optional; } : base; export type BuilderReferenceColumn< scalar extends Scalar = Scalar, optional extends boolean = boolean, reference extends string = string, /// base extends ReferenceColumn = ReferenceColumn< scalar, optional, reference >, > = optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * o: p.int().optional(), * }) * }) */ optional: ReferenceOptional; } : base; export type BuilderJSONColumn< type = any, optional extends boolean = boolean, /// base extends JSONColumn = JSONColumn, > = optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * t: p.createTable({ * id: p.string(), * o: p.json().optional(), * }) * })); */ optional: JSONOptional; } : base; export type BuilderOneColumn = { " type": "one"; " reference": reference; }; export type BuilderManyColumn< referenceTable extends string = string, referenceColumn extends string = string, > = { " type": "many"; " referenceTable": referenceTable; " referenceColumn": referenceColumn; }; export type BuilderEnumColumn< _enum extends string = string, optional extends boolean = boolean, list extends boolean = boolean, /// base extends EnumColumn<_enum, optional, list> = EnumColumn< _enum, optional, list >, > = list extends false ? optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * e: p.createEnum(["ONE", "TWO"]) * t: p.createTable({ * id: p.string(), * a: p.enum("e").optional(), * }) * })); */ optional: EnumOptional; /** * Mark the column as a list. * * - Docs: https://ponder.sh/docs/schema#list * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * e: p.createEnum(["ONE", "TWO"]) * t: p.createTable({ * id: p.string(), * a: p.enum("e").list(), * }) * })); */ list: EnumList; } : base & { /** * Mark the column as a list. * * - Docs: https://ponder.sh/docs/schema#list * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * e: p.createEnum(["ONE", "TWO"]) * t: p.createTable({ * id: p.string(), * a: p.enum("e").list(), * }) * })); */ list: EnumList; } : optional extends false ? base & { /** * Mark the column as optional. * * - Docs: https://ponder.sh/docs/schema#optional * * @example * import { createSchema } from "@ponder/core"; * * export default createSchema((p) => ({ * e: p.createEnum(["ONE", "TWO"]) * t: p.createTable({ * id: p.string(), * a: p.enum("e").optional(), * }) * })); */ optional: EnumOptional; } : base; export type BuilderIndex< column extends string | readonly string[] = string | readonly string[], order extends "asc" | "desc" | undefined = "asc" | "desc" | undefined, nulls extends "first" | "last" | undefined = "first" | "last" | undefined, /// base extends Index = Index, isSingleColumn = column extends readonly string[] ? false : true, > = order extends undefined ? nulls extends undefined ? isSingleColumn extends true ? base & { asc: Asc; desc: Desc; nullsFirst: NullsFirst; nullsLast: NullsLast; } : base : isSingleColumn extends true ? base & { asc: Asc; desc: Desc; } : base : nulls extends undefined ? isSingleColumn extends true ? base & { nullsFirst: NullsFirst; nullsLast: NullsLast; } : base : base; export const string = scalarColumn("string"); export const int = scalarColumn("int"); export const float = scalarColumn("float"); export const boolean = scalarColumn("boolean"); export const hex = scalarColumn("hex"); export const bigint = scalarColumn("bigint"); export const json = (): BuilderJSONColumn => { const column = { " type": "json", " json": {} as type, " optional": false, } as const; return { ...column, optional: jsonOptional(column), }; }; export const one = ( ref: reference, ): BuilderOneColumn => ({ " type": "one", " reference": ref, }); export const many = < referenceTable extends string = string, referenceColumn extends string = string, >( ref: `${referenceTable}.${referenceColumn}`, ): BuilderManyColumn => ({ " type": "many", " referenceTable": ref.split(".")[0] as referenceTable, " referenceColumn": ref.split(".")[1] as referenceColumn, }); export const _enum = <_enum extends string>( __enum: _enum, ): Prettify> => { const column = { " type": "enum", " enum": __enum, " optional": false, " list": false, } as const; return { ...column, optional: enumOptional(column), list: enumList(column), }; }; export const index = ( c: column, ): BuilderIndex => { const index = { " type": "index", " column": c, " order": undefined, " nulls": undefined, } as const; return { ...index, asc: asc(index), desc: desc(index), nullsFirst: nullsFirst(index), nullsLast: nullsLast(index), } as BuilderIndex; };