@parsrun/entity
v0.2.12
Published
Single-source entity definitions for Pars - generates ArkType schemas and Drizzle tables
Maintainers
Readme
@parsrun/entity
Single-source entity definitions for the Pars framework. Define once, generate ArkType validation schemas and Drizzle ORM tables.
Installation
npm install @parsrun/entity
# or
pnpm add @parsrun/entityQuick Start
import { defineEntity, ref, enumField } from '@parsrun/entity'
import { toPgTable } from '@parsrun/entity/pg'
// or for SQLite/D1:
// import { toSqliteTable } from '@parsrun/entity/sqlite'
// Define your entity once
const Product = defineEntity({
name: 'products',
tenant: true, // Adds tenantId field
timestamps: true, // Adds insertedAt, updatedAt
softDelete: true, // Adds deletedAt
fields: {
name: 'string >= 1',
slug: 'string',
description: { type: 'string', optional: true },
price: { type: 'number', min: 0 },
stock: { type: 'number.integer', min: 0, default: 0 },
status: enumField(['draft', 'active', 'archived'], { default: 'draft' }),
categoryId: ref('categories', { onDelete: 'set null', optional: true }),
},
indexes: [
{ fields: ['tenantId', 'slug'], unique: true },
{ fields: ['tenantId', 'status'] },
],
})
// Generated schemas available:
Product.schema // Full entity schema
Product.createSchema // For create operations (no id, timestamps)
Product.updateSchema // For updates (all optional)
Product.querySchema // For filtering (includes pagination)
// Generate Drizzle table
const productsTable = toPgTable(Product)Usage
Validation
import { type } from 'arktype'
// Validate create input
const input = Product.createSchema(requestBody)
if (input instanceof type.errors) {
return { error: 'Validation failed', details: input }
}
// input is now typed and validated
await db.insert(productsTable).values({
tenantId: ctx.tenantId,
...input,
})Database Queries
import { eq, and } from 'drizzle-orm'
import { toPgTable } from '@parsrun/entity/pg'
const productsTable = toPgTable(Product)
// Select
const products = await db
.select()
.from(productsTable)
.where(and(
eq(productsTable.tenantId, tenantId),
eq(productsTable.status, 'active')
))
// Insert
const [product] = await db
.insert(productsTable)
.values({ tenantId, name: 'Widget', price: 9.99 })
.returning()
// Update
await db
.update(productsTable)
.set({ price: 14.99 })
.where(eq(productsTable.id, productId))Multiple Entities with References
import { createPgSchema } from '@parsrun/entity/pg'
const Category = defineEntity({
name: 'categories',
tenant: true,
timestamps: true,
fields: {
name: 'string >= 1',
slug: 'string',
},
})
const Product = defineEntity({
name: 'products',
tenant: true,
timestamps: true,
fields: {
name: 'string >= 1',
categoryId: ref(Category, { onDelete: 'cascade' }),
},
})
// Creates tables with proper foreign key references
const schema = createPgSchema({ Category, Product })
// schema.Category, schema.ProductField Types
| Type | Description | Example |
|------|-------------|---------|
| 'string' | Text field | name: 'string' |
| 'string >= N' | Min length | name: 'string >= 1' |
| 'string.uuid' | UUID field | id: 'string.uuid' |
| 'string.email' | Email field | email: 'string.email' |
| 'string.url' | URL field | website: 'string.url' |
| 'number' | Numeric field | price: 'number' |
| 'number >= N' | Min value | price: 'number >= 0' |
| 'number.integer' | Integer field | stock: 'number.integer' |
| 'boolean' | Boolean field | isActive: 'boolean' |
| 'Date' | Timestamp | expiresAt: 'Date' |
| 'json' | JSON field | metadata: 'json' |
| "'a' \| 'b'" | Union/Enum | status: "'draft' \| 'active'" |
Helper Functions
enumField(values, options?)
status: enumField(['draft', 'active', 'archived'], {
default: 'draft',
optional: false
})ref(entity, options?)
categoryId: ref('categories', {
field: 'id', // default: 'id'
onDelete: 'cascade', // 'cascade' | 'set null' | 'restrict'
optional: true
})
// Or with entity reference
categoryId: ref(Category, { onDelete: 'cascade' })decimal(precision, scale, options?)
price: decimal(10, 2, { min: 0 }) // DECIMAL(10,2)jsonField(options?)
metadata: jsonField({ optional: true, default: {} })SQLite / Cloudflare D1
import { toSqliteTable, createSqliteSchema } from '@parsrun/entity/sqlite'
const productsTable = toSqliteTable(Product)
// Or multiple tables
const schema = createSqliteSchema({ Category, Product })TypeScript Types
import type { InferEntity, InferCreateInput, InferUpdateInput } from '@parsrun/entity'
type Product = InferEntity<typeof Product>
type CreateProductInput = InferCreateInput<typeof Product>
type UpdateProductInput = InferUpdateInput<typeof Product>License
MIT
