{"version":3,"file":"select.mjs","names":[],"sources":["../../../../src/common/schema/sql/select.ts"],"sourcesContent":["import type { Infer, Type } from '../schema'\nimport type { Expr } from './expr'\nimport type { Column, TableColumns, TableShape } from './table'\n\nexport type RowFromTable<T> = T extends TableColumns<any, infer S>\n  ? { [K in keyof S]: Infer<S[K]> }\n  : never\n\nexport type RowFromSelection<S> = {\n  [K in keyof S]: S[K] extends Column<infer T> ? T : never\n}\n\nexport interface QueryDependencies {\n  readonly table: string\n  readonly select: readonly string[]\n  readonly where: readonly string[]\n  readonly orderBy: readonly string[]\n  readonly all: readonly string[]\n}\n\nexport interface CompiledQuery<Row> {\n  readonly sql: string\n  readonly params: readonly unknown[]\n  readonly dependencies: readonly QueryDependencies[]\n  readonly __row?: Row\n}\n\ninterface OrderByEntry {\n  col: Column\n  dir: 'ASC' | 'DESC'\n}\n\ninterface SelectState {\n  selection?: Record<string, Column>\n  from?: TableColumns<any, any>\n  where?: Expr\n  orderBy: OrderByEntry[]\n  limit?: number\n  offset?: number\n}\n\ntype ShapeRow<S> = { [K in keyof S]: S[K] extends Type<infer T> ? T : never }\n\nexport class SelectBuilder<Row, Shape = unknown> {\n  private _state: SelectState\n\n  constructor(state: SelectState) {\n    this._state = state\n  }\n\n  from<N extends string, S extends TableShape>(\n    t: TableColumns<N, S>,\n  ): SelectBuilder<Row extends void ? ShapeRow<S> : Row, S> {\n    this._state.from = t\n    return this as any\n  }\n\n  pick<K extends Extract<keyof Shape, string>>(\n    ...keys: K[]\n  ): SelectBuilder<{ [P in K]: Shape[P] extends Type<infer T> ? T : never }, Shape> {\n    if (!this._state.from)\n      throw new Error('pick: from() must be called first')\n    const sel: Record<string, Column> = {}\n    for (const k of keys) sel[k] = (this._state.from as any)[k]\n    this._state.selection = sel\n    return this as any\n  }\n\n  where(expr: Expr): this {\n    this._state.where = expr\n    return this\n  }\n\n  orderBy(col: Column, dir: 'ASC' | 'DESC' = 'ASC'): this {\n    this._state.orderBy.push({ col, dir })\n    return this\n  }\n\n  limit(n: number): this {\n    this._state.limit = n\n    return this\n  }\n\n  offset(n: number): this {\n    this._state.offset = n\n    return this\n  }\n\n  toSQL(): CompiledQuery<Row> {\n    const s = this._state\n    if (!s.from)\n      throw new Error('select: from() is required')\n\n    const tableName = s.from._name\n    const params: unknown[] = []\n    const selectRefs: Column[] = []\n    const whereRefs: Column[] = []\n    const orderByRefs: Column[] = []\n\n    let cols: string\n    if (s.selection) {\n      const parts: string[] = []\n      for (const [alias, col] of Object.entries(s.selection)) {\n        selectRefs.push(col)\n        const ident = `\"${col._table}\".\"${col._name}\"`\n        parts.push(alias === col._name ? ident : `${ident} AS \"${alias}\"`)\n      }\n      cols = parts.join(', ')\n    }\n    else {\n      const shape = s.from._shape\n      const names = Object.keys(shape)\n      for (const n of names) selectRefs.push((s.from as any)[n])\n      cols = names.map(n => `\"${tableName}\".\"${n}\"`).join(', ')\n    }\n\n    let sql = `SELECT ${cols} FROM \"${tableName}\"`\n\n    if (s.where) {\n      sql += ` WHERE ${s.where.sql}`\n      params.push(...s.where.params)\n      whereRefs.push(...s.where.refs)\n    }\n\n    if (s.orderBy.length) {\n      const parts = s.orderBy.map((o) => {\n        orderByRefs.push(o.col)\n        return `\"${o.col._table}\".\"${o.col._name}\" ${o.dir}`\n      })\n      sql += ` ORDER BY ${parts.join(', ')}`\n    }\n\n    if (s.limit != null) {\n      sql += ` LIMIT ?`\n      params.push(s.limit)\n    }\n\n    if (s.offset != null) {\n      sql += ` OFFSET ?`\n      params.push(s.offset)\n    }\n\n    return {\n      sql,\n      params,\n      dependencies: collectDependencies(selectRefs, whereRefs, orderByRefs),\n      __row: undefined as any,\n    }\n  }\n\n  dependencies(): readonly QueryDependencies[] {\n    return this.toSQL().dependencies\n  }\n}\n\nfunction collectDependencies(\n  selectRefs: Column[],\n  whereRefs: Column[],\n  orderByRefs: Column[],\n): QueryDependencies[] {\n  interface Buckets {\n    select: Set<string>\n    where: Set<string>\n    orderBy: Set<string>\n  }\n  const map = new Map<string, Buckets>()\n  const bucket = (table: string): Buckets => {\n    let b = map.get(table)\n    if (!b) {\n      b = { select: new Set(), where: new Set(), orderBy: new Set() }\n      map.set(table, b)\n    }\n    return b\n  }\n  for (const c of selectRefs) bucket(c._table).select.add(c._name)\n  for (const c of whereRefs) bucket(c._table).where.add(c._name)\n  for (const c of orderByRefs) bucket(c._table).orderBy.add(c._name)\n\n  return Array.from(map, ([table, b]) => {\n    const all = new Set<string>([...b.select, ...b.where, ...b.orderBy])\n    return {\n      table,\n      select: Array.from(b.select).sort(),\n      where: Array.from(b.where).sort(),\n      orderBy: Array.from(b.orderBy).sort(),\n      all: Array.from(all).sort(),\n    }\n  })\n}\n\nexport function select(): SelectBuilder<void>\nexport function select<S extends Record<string, Column<any>>>(\n  selection: S,\n): SelectBuilder<RowFromSelection<S>>\nexport function select(selection?: Record<string, Column>): SelectBuilder<any> {\n  return new SelectBuilder({ selection, orderBy: [] })\n}\n\nexport function from<N extends string, S extends TableShape>(\n  t: TableColumns<N, S>,\n): SelectBuilder<ShapeRow<S>, S> {\n  return new SelectBuilder<ShapeRow<S>, S>({ from: t, orderBy: [] })\n}\n\nexport type InferRow<Q> = Q extends SelectBuilder<infer R>\n  ? R\n  : Q extends CompiledQuery<infer R> ? R : never\n"],"mappings":"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"}