Skip to content

Commit fe77e79

Browse files
committed
tweak README.md
1 parent 6d51908 commit fe77e79

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

README.md

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ await db.update(Users, {name: "Alice Smith"}, user.id);
115115
Zen is the missing link between SQL and typed data. By writing tables with Zod schema, you get idempotent migration helpers, typed CRUD, normalized object references, and many features other database clients cannot provide.
116116

117117
### What Zen is not:
118-
- **Zen is not a query builder** — Rather than fluent query building `.where().orderBy().limit()` chains, you write SQL directly: `` db.all(Posts)`WHERE published = ${true} ORDER BY created_at DESC LIMIT 20` ``
119-
- **Zen is not an ORM** — Tables are not classes, they are Zod-powered singletons which provide schema-aware SQL-fragment helpers. These tables can be passed to CRUD helpers to validate writes, generate DDL, and normalize joined data into an object graph.
118+
- **Zen is not a query builder** — Rather than building SQL with fluent chains `.where().orderBy().limit()`, you write it directly with templates: `` db.all(Posts)`WHERE published = ${true} ORDER BY created_at DESC LIMIT 20` `` Helper functions help you write the tedious parts of SQL without hiding it or limiting your queries.
119+
- **Zen is not an ORM** — Tables are not classes. They are Zod-powered singletons which provide schema-aware utilities. These tables can be used to validate writes, generate DDL, and deduplicate joined data.
120120
- **Zen is not a startup** — Zen is an open-source library, not a venture-backed SaaS. There will never be a managed “ZenDB” instance or a “Zen Studio.” The library is a thin wrapper around Zod and JavaScript SQL drivers, with a focus on runtime abstractions rather than complicated tooling.
121121

122122
### Safety
@@ -127,9 +127,6 @@ Zen is the missing link between SQL and typed data. By writing tables with Zod s
127127
- **No destructive helpers** — No `dropColumn()`, `dropTable()`, `renameColumn()`
128128
- **No automatic migrations** — Schema changes are explicit in upgrade events
129129

130-
Migrations are **additive and idempotent** by design. Use `ensureColumn()`, `ensureIndex()`, `copyColumn()` for safe schema evolution. Breaking changes require multi-step migrations. Rollbacks are new forward migrations.
131-
132-
133130
## Table Definitions
134131

135132
```typescript
@@ -491,6 +488,29 @@ await db.exec`CREATE INDEX idx_posts_author ON ${Posts}(${Posts.cols.authorId})`
491488
const count = await db.val<number>`SELECT COUNT(*) FROM ${Posts}`;
492489
```
493490

491+
## CRUD Helpers
492+
```typescript
493+
// Insert with Zod validation (uses RETURNING to get actual row)
494+
const user = await db.insert(Users, {
495+
496+
name: "Alice",
497+
});
498+
// Returns actual row from DB, including auto-generated id and DB-computed defaults
499+
const userId = user.id;
500+
501+
// Update by primary key (uses RETURNING)
502+
const updated = await db.update(Users, {name: "Bob"}, userId);
503+
504+
// Delete by primary key
505+
await db.delete(Users, userId);
506+
507+
// Soft delete (sets deletedAt timestamp, requires softDelete() field)
508+
await db.softDelete(Users, userId);
509+
```
510+
511+
**RETURNING support:** `insert()` and `update()` use `RETURNING *` on SQLite and PostgreSQL to return the actual row from the database, including DB-computed defaults and triggers. MySQL falls back to a separate SELECT.
512+
513+
494514
## Fragment Helpers
495515

496516
Type-safe SQL fragments as methods on Table objects:
@@ -540,29 +560,6 @@ const posts = await db.all(Posts)`WHERE ${Posts.in("id", [])}`;
540560
// → WHERE 1 = 0
541561
```
542562

543-
## CRUD Helpers
544-
545-
```typescript
546-
// Insert with Zod validation (uses RETURNING to get actual row)
547-
const user = await db.insert(Users, {
548-
549-
name: "Alice",
550-
});
551-
// Returns actual row from DB, including auto-generated id and DB-computed defaults
552-
const userId = user.id;
553-
554-
// Update by primary key (uses RETURNING)
555-
const updated = await db.update(Users, {name: "Bob"}, userId);
556-
557-
// Delete by primary key
558-
await db.delete(Users, userId);
559-
560-
// Soft delete (sets deletedAt timestamp, requires softDelete() field)
561-
await db.softDelete(Users, userId);
562-
```
563-
564-
**RETURNING support:** `insert()` and `update()` use `RETURNING *` on SQLite and PostgreSQL to return the actual row from the database, including DB-computed defaults and triggers. MySQL falls back to a separate SELECT.
565-
566563
## Transactions
567564

568565
```typescript
@@ -839,6 +836,7 @@ const refs = Posts.references(); // [{fieldName: "authorId", table: Users,
839836
- Tagged template queries are cached by template object identity (compiled once per call site)
840837
- Normalization cost is O(rows) with hash maps per table
841838
- Reference resolution is zero-cost after deduplication
839+
- Zod validation happens on writes, never on reads.
842840

843841
## Driver Interface
844842

0 commit comments

Comments
 (0)