defineSchema

Define your database schema for type-safe queries, validation, and migrations.

Import

import.ts
import { defineSchema } from 'genaql';

Basic Usage

basic.ts
const schema = defineSchema({
  users: {
    id: 'serial',
    name: 'text',
    email: 'text',
    created_at: 'timestamp'
  },
  posts: {
    id: 'serial',
    user_id: 'integer',
    title: 'text',
    content: 'text',
    published: 'boolean'
  }
});

Column Types

TypeTypeScriptDescription
'text'stringVariable-length string
'integer'number32-bit integer
'serial'numberAuto-incrementing integer
'bigint'bigint64-bit integer
'boolean'booleanTrue/false
'timestamp'DateDate and time
'date'DateDate only
'json'unknownJSON/JSONB
'uuid'stringUUID string
'decimal'stringPrecise decimal

Column Options

options.ts
const schema = defineSchema({
  users: {
    // Simple type
    id: 'serial',

    // With options
    name: { type: 'text', notNull: true },
    email: { type: 'text', notNull: true, unique: true },
    role: { type: 'text', default: 'user' },
    bio: { type: 'text', nullable: true },  // or 'text?'
    created_at: { type: 'timestamp', default: 'now()' },

    // Foreign key
    organization_id: {
      type: 'integer',
      references: 'organizations.id',
      onDelete: 'cascade'
    },

    // Custom TypeScript type
    metadata: { type: 'json', tsType: 'UserMetadata' }
  }
});

Relations

relations.ts
import { defineSchema, got, stacked, simps, linked } from 'genaql';

const schema = defineSchema({
  users: { /* ... */ },
  profiles: { /* ... */ },
  posts: { /* ... */ },
  tags: { /* ... */ },
  post_tags: { /* ... */ }
}, {
  relations: {
    users: {
      profile: got('profiles', 'user_id'),
      posts: stacked('posts', 'user_id')
    },
    posts: {
      author: simps('users', 'user_id'),
      tags: linked('tags', 'post_tags', 'post_id', 'tag_id')
    }
  }
});

Schema Options

schema-options.ts
const schema = defineSchema(tables, {
  // Relations (see above)
  relations: { /* ... */ },

  // Soft delete configuration
  softDelete: {
    column: 'deleted_at',
    tables: ['users', 'posts']
  },

  // Auto timestamps
  timestamps: {
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    tables: ['users', 'posts', 'comments']
  },

  // Table name transformations
  tableNames: {
    style: 'snake_case',  // or 'camelCase', 'PascalCase'
    pluralize: true
  }
});

Type Inference

inference.ts
import { InferTable, InferInsert, InferUpdate } from 'genaql';

// Infer types from schema
type User = InferTable<typeof schema, 'users'>;
// { id: number; name: string; email: string; created_at: Date }

type NewUser = InferInsert<typeof schema, 'users'>;
// { name: string; email: string; created_at?: Date }  (id is auto)

type UserUpdate = InferUpdate<typeof schema, 'users'>;
// { name?: string; email?: string; created_at?: Date }

Best Practice

Define your schema in a separate file and export it. Import it wherever you need type-safe queries or database operations. This ensures consistency across your codebase.