PawQL uses plain JavaScript objects to define your database schema. TypeScript automatically infers types from these definitions.
Use standard JavaScript constructors as column types:
const schema = {
users: {
id: Number, // → INTEGER
name: String, // → TEXT
isActive: Boolean, // → BOOLEAN
createdAt: Date, // → TIMESTAMP
}
};
| JavaScript | PostgreSQL | MySQL | SQLite | TypeScript |
|---|---|---|---|---|
Number | INTEGER | INTEGER | INTEGER | number |
String | TEXT | TEXT | TEXT | string |
Boolean | BOOLEAN | BOOLEAN (→ TINYINT(1)) | INTEGER | boolean |
Date | TIMESTAMP | TIMESTAMP | TIMESTAMP | Date |
Dialect-aware: PawQL generates the correct DDL per adapter (
PostgresAdaptervsMysqlAdaptervsSqliteAdapter) viacreateTables()andMigrationRunner. Note: For precise sizing likeVARCHAR(255)orDECIMAL(10,2), check out the Custom Types section.
For more advanced configuration, use an object definition:
const schema = {
users: {
// Primary key
id: { type: Number, primaryKey: true },
// Nullable column
email: { type: String, nullable: true },
// Default value
isActive: { type: Boolean, default: true },
score: { type: Number, default: 0 },
role: { type: String, default: 'user' },
}
};
| Option | Type | Description |
|---|---|---|
type | ColumnTypeValue | Column type (required for object definitions) |
primaryKey | boolean | Mark as primary key |
nullable | boolean | Allow NULL (default: false) |
default | any | Default value |
PawQL provides helper functions for advanced data types.
import { uuid } from 'pawql';
const schema = {
users: {
id: uuid, // → UUID (pg) / VARCHAR(36) (mysql) / TEXT (sqlite), TypeScript type: string
name: String,
}
};
Generated DDL (dialect-aware):
"id" UUID NOT NULL`id` VARCHAR(36) NOT NULL"id" TEXT NOT NULLimport { json } from 'pawql';
const schema = {
products: {
id: { type: Number, primaryKey: true },
metadata: json<{
tags: string[];
color: string;
dimensions?: { width: number; height: number };
}>(),
}
};
metadata is of type { tags: string[]; color: string; ... }<T> provides type safety for the JSON dataGenerated DDL (dialect-aware):
"metadata" JSONB NOT NULL`metadata` JSON NOT NULL"metadata" TEXT NOT NULL (JSON stored as TEXT)import { enumType } from 'pawql';
const schema = {
users: {
id: { type: Number, primaryKey: true },
role: enumType('admin', 'user', 'guest'),
status: enumType('active', 'inactive', 'banned'),
}
};
TEXT column with a CHECK constraint'admin' | 'user' | 'guest')Generated DDL:
"role" TEXT NOT NULL CHECK ("role" IN ('admin', 'user', 'guest'))
import { arrayType } from 'pawql';
const schema = {
posts: {
id: { type: Number, primaryKey: true },
tags: arrayType(String), // → TEXT[], TypeScript: string[]
scores: arrayType(Number), // → INTEGER[], TypeScript: number[]
}
};
Generated DDL (PostgreSQL only):
"tags" TEXT[] NOT NULL,
"scores" INTEGER[] NOT NULL
⚠️ PostgreSQL-only:
arrayType()uses nativeTEXT[]/INTEGER[]. On MySQL/SQLite it throwsArrayType is only supported on PostgreSQL — Use json() for MySQL/SQLite instead.. For cross-dialect arrays, usejson<string[]>().
For finer-grained SQL definitions beyond standard Javascript primitives, import explicit markers from PawQL:
import { varchar, text, bigint, decimal } from 'pawql';
const schema = {
transactions: {
id: bigint(), // → BIGINT, TypeScript: number|string
description: varchar(255), // → VARCHAR(255), TypeScript: string
notes: text(), // → TEXT, TypeScript: string
balance: decimal(10, 2), // → DECIMAL(10, 2), TypeScript: number|string
}
};
import { createDB, uuid, enumType } from 'pawql';
const db = createDB({
users: {
id: uuid,
name: String,
email: { type: String, nullable: true },
role: enumType('admin', 'user'),
},
posts: {
id: { type: Number, primaryKey: true },
userId: Number, // Foreign key (manual)
title: String,
content: String,
publishedAt: { type: Date, nullable: true },
},
comments: {
id: { type: Number, primaryKey: true },
postId: Number,
userId: Number,
text: String,
createdAt: Date,
}
}, adapter);
PawQL automatically infers types from your schema. No need to define interfaces manually:
// TypeScript knows that:
// - users.id → string (because of uuid)
// - users.role → 'admin' | 'user' (because of enumType)
// - posts.publishedAt → Date | null (because of nullable)
const users = await db.query('users').execute();
// Type: { id: string; name: string; email: string | null; role: 'admin' | 'user' }[]
const posts = await db.query('posts').execute();
// Type: { id: number; userId: number; title: string; content: string; publishedAt: Date | null }[]
// Create all tables defined in the schema (dialect-aware)
await db.createTables();
This runs CREATE TABLE IF NOT EXISTS for each table with dialect-correct types (UUID→VARCHAR(36)/TEXT, JSONB→JSON/TEXT, BOOLEAN→INTEGER on SQLite). It's safe to run multiple times — existing tables will not be affected.
Use migrations (
Migrator) for production schema transitions.