211 lines · 6.4 KB · TypeScript
RawDownload
import type {  AnySchema,  AnyTable,  Relation,  TableColumnValues,  TableInsertValues,  TableUpdateValues,} from "../schema/create";import type { Condition, ConditionBuilder } from "./condition-builder";import type { ORMAdapter } from "./orm"; export type { Condition, ConditionBuilder } from "./condition-builder";export { ConditionType } from "./condition-builder";export { withQueryContext } from "./orm";export type {  CompiledJoin,  ORMAdapter,  SimplifiedCountOptions,  SimplifyFindOptions,} from "./orm"; export type AnySelectClause = SelectClause<AnyTable>; export type SelectClause<T extends AnyTable> = true | (keyof T["columns"])[]; export type TableToColumnValues<T extends AnyTable> = TableColumnValues<T>; export type TableToInsertValues<T extends AnyTable> = TableInsertValues<T>; export type TableToUpdateValues<T extends AnyTable> = TableUpdateValues<T>; export type MainSelectResult<  S extends SelectClause<T>,  T extends AnyTable,> = S extends true  ? TableToColumnValues<T>  : S extends (keyof T["columns"])[]    ? Pick<TableToColumnValues<T>, S[number]>    : never; export type JoinBuilder<T extends AnyTable, Out = {}> = {  [K in keyof T["relations"]]: T["relations"][K] extends Relation<    infer Type,    infer Target  >    ? <Select extends SelectClause<Target> = true, JoinOut = {}>(        options?: Type extends "many"          ? FindManyOptions<Target, Select, JoinOut, false>          : FindFirstOptions<Target, Select, JoinOut, false>      ) => JoinBuilder<        T,        Out & {          [$K in K]: MapRelationType<            SelectResult<Target, JoinOut, Select>,            T["relations"][K]["implied"]          >[Type];        }      >    : never;}; export type SelectResult<  T extends AnyTable,  JoinOut,  Select extends SelectClause<T>,> = MainSelectResult<Select, T> & JoinOut; export type OrderBy<Column = string> = [columnName: Column, "asc" | "desc"]; export type FindFirstOptions<  T extends AnyTable = AnyTable,  Select extends SelectClause<T> = SelectClause<T>,  JoinOut = {},  IsRoot extends boolean = true,> = Omit<  FindManyOptions<T, Select, JoinOut, IsRoot>,  IsRoot extends true ? "limit" : "limit" | "offset" | "orderBy">; interface MapRelationType<Type, Implied extends boolean> {  one: Implied extends true ? Type | null : Type;  many: Type[];} export type FindManyOptions<  T extends AnyTable = AnyTable,  Select extends SelectClause<T> = SelectClause<T>,  JoinOut = {},  IsRoot extends boolean = true,> = {  select?: Select;  where?: (eb: ConditionBuilder<T["columns"]>) => Condition | boolean;   limit?: number;  orderBy?: OrderBy<keyof T["columns"]> | OrderBy<keyof T["columns"]>[];  join?: (builder: JoinBuilder<T, {}>) => JoinBuilder<T, JoinOut>;} & (IsRoot extends true  ? {      // drizzle doesn't support `offset` in join queries (this may be changed in future, we can add it back)      offset?: number;    }  : {}); export interface AbstractQuery<S extends AnySchema> {  internal: ORMAdapter<S>;   /**   * Rebind the query context used by table policies.   *   * Wrappers around `AbstractQuery` should forward this method instead of   * rebuilding from `.internal`, otherwise public query decorators can be   * bypassed.   */  withContext?: <TContext>(context: TContext) => AbstractQuery<S>;   /**   * The code in the transaction will receive a transaction query instance.   *   * If you use that instance to write the database (e.g. insert) and an error is thrown, FumaDB will automatically rollback the changes + rethrow the error.   *   * It works by using the transaction API that's natively available for the database/ORM, or falling back to the soft transaction layer built by FumaDB.   */  transaction: <T>(run: (orm: AbstractQuery<S>) => Promise<T>) => Promise<T>;   /**   * Count (all)   */  count: <TableName extends keyof S["tables"]>(    table: TableName,    v?: {      where?: (        eb: ConditionBuilder<S["tables"][TableName]["columns"]>      ) => Condition | boolean;    }  ) => Promise<number>;   findFirst: <      TableName extends keyof S["tables"],      JoinOut = {},      Select extends SelectClause<S["tables"][TableName]> = true,    >(      table: TableName,      v: FindFirstOptions<S["tables"][TableName], Select, JoinOut>) => Promise<SelectResult<S["tables"][TableName], JoinOut, Select> | null>;   findMany: <      TableName extends keyof S["tables"],      JoinOut = {},      Select extends SelectClause<S["tables"][TableName]> = true,    >(      table: TableName,      v?: FindManyOptions<S["tables"][TableName], Select, JoinOut>) => Promise<SelectResult<S["tables"][TableName], JoinOut, Select>[]>;   // not every database supports returning in update/delete, hence they will not be implemented.  // TODO: maybe reconsider this in future   /**   * Upsert a **single row**.   *   * For ORMs:   * - use built-in method whenever possible.   *   * Otherwise:   * - run `update`.   * - if updated zero rows, run `create`.   */  upsert: <TableName extends keyof S["tables"]>(    table: TableName,    v: {      where: (        eb: ConditionBuilder<S["tables"][TableName]["columns"]>      ) => Condition | boolean;      update: TableToUpdateValues<S["tables"][TableName]>;      create: TableToInsertValues<S["tables"][TableName]>;    }  ) => Promise<void>;   /**   * Note: you cannot update the id of a row, some databases don't support that (including MongoDB).   */  updateMany: <TableName extends keyof S["tables"]>(      table: TableName,      v: {        where?: (          eb: ConditionBuilder<S["tables"][TableName]["columns"]>        ) => Condition | boolean;        set: TableToUpdateValues<S["tables"][TableName]>;      }) => Promise<void>;   createMany: <TableName extends keyof S["tables"]>(      table: TableName,      values: TableToInsertValues<S["tables"][TableName]>[]) => Promise<      {        _id: string;      }[]    >;   /**   * Note: when you don't need to receive the result, always use `createMany` for better performance.   */  create: <TableName extends keyof S["tables"]>(      table: TableName,      values: TableToInsertValues<S["tables"][TableName]>) => Promise<TableToColumnValues<S["tables"][TableName]>>;   deleteMany: <TableName extends keyof S["tables"]>(      table: TableName,      v: {        where?: (          eb: ConditionBuilder<S["tables"][TableName]["columns"]>        ) => Condition | boolean;      }) => Promise<void>;}