Skip to content

Commit 13d26ed

Browse files
committed
ergonomics: .column should default to 0 | 1 unless nonNull: false
1 parent 30848e8 commit 13d26ed

30 files changed

Lines changed: 217 additions & 200 deletions

examples/basic/src/tables/collars.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { Dogs } from "./dogs";
55

66
export class Collars extends db.Table("collars") {
77
// @generated-start
8-
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
9-
@expose() color = (Text<1>).column({ nonNull: true });
10-
@expose() dog_id = (Int8<1>).column({ nonNull: true });
8+
@expose() id = Int8.column({ nonNull: true, generated: true });
9+
@expose() color = Text.column({ nonNull: true });
10+
@expose() dog_id = Int8.column({ nonNull: true });
1111
// relations
1212
@expose() dog() { return Dogs.scope(Collars.contextOf(this)).where(({ dogs }) => dogs.id.eq(this.dog_id)).cardinality("one"); }
1313
// @generated-end

examples/basic/src/tables/dogs.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { Toys } from "./toys";
88

99
export class Dogs extends db.Table("dogs") {
1010
// @generated-start
11-
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
12-
@expose() name = (Text<1>).column({ nonNull: true });
13-
@expose() breed = (Text<0 | 1>).column();
14-
@expose() created_at = (Timestamptz<1>).column({ nonNull: true, default: sql`now()` });
15-
@expose() team_id = (Int8<1>).column({ nonNull: true });
16-
@expose() rival_id = (Int8<0 | 1>).column();
11+
@expose() id = Int8.column({ nonNull: true, generated: true });
12+
@expose() name = Text.column({ nonNull: true });
13+
@expose() breed = Text.column();
14+
@expose() created_at = Timestamptz.column({ nonNull: true, default: sql`now()` });
15+
@expose() team_id = Int8.column({ nonNull: true });
16+
@expose() rival_id = Int8.column();
1717
// relations
1818
@expose() rival() { return Dogs.scope(Dogs.contextOf(this)).where(({ dogs }) => dogs.id.eq(this.rival_id)).cardinality("maybe"); }
1919
@expose() team() { return Teams.scope(Dogs.contextOf(this)).where(({ teams }) => teams.id.eq(this.team_id)).cardinality("one"); }

examples/basic/src/tables/microchips.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { Dogs } from "./dogs";
55

66
export class Microchips extends db.Table("microchips") {
77
// @generated-start
8-
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
9-
@expose() serial = (Text<1>).column({ nonNull: true });
10-
@expose() dog_id = (Int8<0 | 1>).column();
8+
@expose() id = Int8.column({ nonNull: true, generated: true });
9+
@expose() serial = Text.column({ nonNull: true });
10+
@expose() dog_id = Int8.column();
1111
// relations
1212
@expose() dog() { return Dogs.scope(Microchips.contextOf(this)).where(({ dogs }) => dogs.id.eq(this.dog_id)).cardinality("maybe"); }
1313
// @generated-end

examples/basic/src/tables/teams.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { Dogs } from "./dogs";
55

66
export class Teams extends db.Table("teams") {
77
// @generated-start
8-
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
9-
@expose() name = (Text<1>).column({ nonNull: true });
8+
@expose() id = Int8.column({ nonNull: true, generated: true });
9+
@expose() name = Text.column({ nonNull: true });
1010
// relations
1111
@expose() dogs() { return Dogs.scope(Teams.contextOf(this)).where(({ dogs }) => dogs.team_id.eq(this.id)).cardinality("many"); }
1212
// @generated-end

examples/basic/src/tables/toys.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { Dogs } from "./dogs";
55

66
export class Toys extends db.Table("toys") {
77
// @generated-start
8-
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
9-
@expose() name = (Text<1>).column({ nonNull: true });
10-
@expose() dog_id = (Int8<1>).column({ nonNull: true });
8+
@expose() id = Int8.column({ nonNull: true, generated: true });
9+
@expose() name = Text.column({ nonNull: true });
10+
@expose() dog_id = Int8.column({ nonNull: true });
1111
// relations
1212
@expose() dog() { return Dogs.scope(Toys.contextOf(this)).where(({ dogs }) => dogs.id.eq(this.dog_id)).cardinality("one"); }
1313
// @generated-end

examples/sqlite/src/tables/dogs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { Teams } from "./teams";
55

66
export class Dogs extends db.Table("dogs") {
77
// @generated-start
8-
@expose() id = (Integer<1>).column({ nonNull: true, generated: true });
9-
@expose() name = (Text<1>).column({ nonNull: true });
10-
@expose() breed = (Text<0 | 1>).column();
11-
@expose() team_id = (Integer<1>).column({ nonNull: true });
8+
@expose() id = Integer.column({ nonNull: true, generated: true });
9+
@expose() name = Text.column({ nonNull: true });
10+
@expose() breed = Text.column();
11+
@expose() team_id = Integer.column({ nonNull: true });
1212
// relations
1313
@expose() team() { return Teams.scope(Dogs.contextOf(this)).where(({ teams }) => teams.id.eq(this.team_id)).cardinality("one"); }
1414
// @generated-end

examples/sqlite/src/tables/teams.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { Dogs } from "./dogs";
55

66
export class Teams extends db.Table("teams") {
77
// @generated-start
8-
@expose() id = (Integer<1>).column({ nonNull: true, generated: true });
9-
@expose() name = (Text<1>).column({ nonNull: true });
8+
@expose() id = Integer.column({ nonNull: true, generated: true });
9+
@expose() name = Text.column({ nonNull: true });
1010
// relations
1111
@expose() dogs() { return Dogs.scope(Teams.contextOf(this)).where(({ dogs }) => dogs.team_id.eq(this.id)).cardinality("many"); }
1212
// @generated-end

src/builder/delete.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test("delete with where", async () => {
1313
await tx.execute(sql`INSERT INTO logs (msg) VALUES ('keep'), ('remove'), ('keep2')`);
1414

1515
class Logs extends db.Table("logs") {
16-
id = (Int8<1>).column({ nonNull: true, generated: true }); msg = (Text<1>).column({ nonNull: true }); }
16+
id = Int8.column({ nonNull: true, generated: true }); msg = Text.column({ nonNull: true }); }
1717

1818
await tx.execute(Logs.delete().where(({ logs }) => logs.msg["="]("remove")));
1919

@@ -34,7 +34,7 @@ test("delete returning", async () => {
3434
await tx.execute(sql`INSERT INTO tags (name) VALUES ('a'), ('b'), ('c')`);
3535

3636
class Tags extends db.Table("tags") {
37-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); }
37+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); }
3838

3939
const rows = await tx.execute(
4040
Tags.delete()
@@ -57,7 +57,7 @@ test("delete: multiple where calls AND-combine", async () => {
5757
await tx.execute(sql`INSERT INTO items (name, score) VALUES ('a', 10), ('b', 20), ('c', 10), ('d', 30)`);
5858

5959
class Items extends db.Table("items") {
60-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); score = (Int8<1>).column({ nonNull: true, default: sql`0` }); }
60+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); score = Int8.column({ nonNull: true, default: sql`0` }); }
6161

6262
await tx.execute(
6363
Items.delete()
@@ -88,8 +88,8 @@ test("delete: where(true) after a real .where() is a no-op", async () => {
8888
await tx.execute(sql`INSERT INTO guards (name) VALUES ('keep'), ('doomed'), ('keep2')`);
8989

9090
class Guards extends db.Table("guards") {
91-
id = (Int8<1>).column({ nonNull: true, generated: true });
92-
name = (Text<1>).column({ nonNull: true });
91+
id = Int8.column({ nonNull: true, generated: true });
92+
name = Text.column({ nonNull: true });
9393
}
9494

9595
await tx.execute(
@@ -113,7 +113,7 @@ test("delete without where throws", async () => {
113113
await tx.execute(sql`CREATE TABLE noop2 (id int8 GENERATED ALWAYS AS IDENTITY PRIMARY KEY)`);
114114

115115
class Noop2 extends db.Table("noop2") {
116-
id = (Int8<1>).column({ nonNull: true, generated: true }); }
116+
id = Int8.column({ nonNull: true, generated: true }); }
117117

118118
await expect(tx.execute(Noop2.delete())).rejects.toThrow("requires .where()");
119119
});

src/builder/insert.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test("insert", async () => {
1616
)`);
1717

1818
class Cats extends db.Table("cats") {
19-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); color = (Text<0 | 1>).column(); }
19+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); color = Text.column(); }
2020

2121
// name is required, id and color are optional
2222
// @ts-expect-error — missing required field 'name'
@@ -43,7 +43,7 @@ test("insert returning", async () => {
4343
)`);
4444

4545
class Items extends db.Table("items") {
46-
id = (Int8<1>).column({ nonNull: true, generated: true }); label = (Text<1>).column({ nonNull: true }); }
46+
id = Int8.column({ nonNull: true, generated: true }); label = Text.column({ nonNull: true }); }
4747

4848
const rows = await tx.execute(
4949
Items.insert({ label: "A" }, { label: "B" })
@@ -67,7 +67,7 @@ test("columns no row provides are pruned so DB defaults apply", async () => {
6767
)`);
6868

6969
class Tagged extends db.Table("tagged") {
70-
id = (Int8<1>).column({ nonNull: true, generated: true }); label = (Text<1>).column({ nonNull: true }); status = (Text<1>).column({ nonNull: true, default: sql`'new'` }); }
70+
id = Int8.column({ nonNull: true, generated: true }); label = Text.column({ nonNull: true }); status = Text.column({ nonNull: true, default: sql`'new'` }); }
7171

7272
// `status` appears in no row → pruned from the column list → the
7373
// DB's DEFAULT 'new' applies (not NULL, not an error).
@@ -91,7 +91,7 @@ test("postgres: column provided in some rows but not others → DEFAULT keyword
9191
)`);
9292

9393
class Mixed extends db.Table("mixed") {
94-
id = (Int8<1>).column({ nonNull: true, generated: true }); label = (Text<1>).column({ nonNull: true }); status = (Text<1>).column({ nonNull: true, default: sql`'new'` }); }
94+
id = Int8.column({ nonNull: true, generated: true }); label = Text.column({ nonNull: true }); status = Text.column({ nonNull: true, default: sql`'new'` }); }
9595

9696
const rows = await tx.execute(
9797
Mixed.insert({ label: "A" }, { label: "B", status: "old" })
@@ -157,7 +157,7 @@ test("all-default single row uses DEFAULT VALUES; multi-row raises", async () =>
157157
)`);
158158

159159
class Counters extends db.Table("counters") {
160-
id = (Int8<1>).column({ nonNull: true, generated: true }); }
160+
id = Int8.column({ nonNull: true, generated: true }); }
161161

162162
const rows = await tx.execute(
163163
Counters.insert({}).returning(({ counters }) => ({ id: counters.id })),

src/builder/query.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,9 @@ test("inner join", async () => {
370370
await tx.execute(sql`INSERT INTO pets (name, owner_id) VALUES ('Rex', 1), ('Fido', 2), ('Buddy', 1)`);
371371

372372
class Owners extends db.Table("owners") {
373-
id = (Int8<1>).column({ nonNull: true }); name = (Text<1>).column({ nonNull: true }); }
373+
id = Int8.column({ nonNull: true }); name = Text.column({ nonNull: true }); }
374374
class Pets extends db.Table("pets") {
375-
id = (Int8<1>).column({ nonNull: true }); name = (Text<1>).column({ nonNull: true }); owner_id = (Int8<1>).column({ nonNull: true }); }
375+
id = Int8.column({ nonNull: true }); name = Text.column({ nonNull: true }); owner_id = Int8.column({ nonNull: true }); }
376376

377377
const rows = await tx.execute(Pets.from()
378378
.join(Owners, ({ pets, owners }) => pets.owner_id["="](owners.id))
@@ -406,9 +406,9 @@ test("left join — unmatched rows return null", async () => {
406406
await tx.execute(sql`INSERT INTO books (title, author_id) VALUES ('Book A', 1)`);
407407

408408
class Authors extends db.Table("authors") {
409-
id = (Int8<1>).column({ nonNull: true }); name = (Text<1>).column({ nonNull: true }); }
409+
id = Int8.column({ nonNull: true }); name = Text.column({ nonNull: true }); }
410410
class Books extends db.Table("books") {
411-
id = (Int8<1>).column({ nonNull: true }); title = (Text<1>).column({ nonNull: true }); author_id = (Int8<1>).column({ nonNull: true }); }
411+
id = Int8.column({ nonNull: true }); title = Text.column({ nonNull: true }); author_id = Int8.column({ nonNull: true }); }
412412

413413
const rows = await tx.execute(Authors.from()
414414
.leftJoin(Books, ({ authors, books }) => authors.id["="](books.author_id))
@@ -441,9 +441,9 @@ test("join with where on joined table", async () => {
441441
await tx.execute(sql`INSERT INTO employees (name, dept_id) VALUES ('Alice', 1), ('Bob', 1), ('Carol', 2)`);
442442

443443
class Departments extends db.Table("departments") {
444-
id = (Int8<1>).column({ nonNull: true }); name = (Text<1>).column({ nonNull: true }); }
444+
id = Int8.column({ nonNull: true }); name = Text.column({ nonNull: true }); }
445445
class Employees extends db.Table("employees") {
446-
id = (Int8<1>).column({ nonNull: true }); name = (Text<1>).column({ nonNull: true }); dept_id = (Int8<0 | 1>).column(); }
446+
id = Int8.column({ nonNull: true }); name = Text.column({ nonNull: true }); dept_id = Int8.column(); }
447447

448448
const rows = await tx.execute(Departments.from()
449449
.join(Employees, ({ departments, employees }) => departments.id["="](employees.dept_id))
@@ -479,9 +479,9 @@ test("scalar with cardinality 'one'", async () => {
479479
await tx.execute(sql`INSERT INTO books (title, author_id) VALUES ('Book A', 1), ('Book B', 1)`);
480480

481481
class Authors extends db.Table("authors") {
482-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); }
482+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); }
483483
class Books extends db.Table("books") {
484-
id = (Int8<1>).column({ nonNull: true, generated: true }); title = (Text<1>).column({ nonNull: true }); author_id = (Int8<1>).column({ nonNull: true }); }
484+
id = Int8.column({ nonNull: true, generated: true }); title = Text.column({ nonNull: true }); author_id = Int8.column({ nonNull: true }); }
485485

486486
// Scalar subquery: get author for a book (cardinality 'one')
487487
const rows = await tx.execute(Books.from()
@@ -518,9 +518,9 @@ test("scalar with cardinality 'maybe' — null when no match", async () => {
518518
await tx.execute(sql`INSERT INTO profiles (person_id, bio) VALUES (1, 'Hello')`);
519519

520520
class People extends db.Table("people") {
521-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); }
521+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); }
522522
class Profiles extends db.Table("profiles") {
523-
id = (Int8<1>).column({ nonNull: true, generated: true }); person_id = (Int8<1>).column({ nonNull: true }); bio = (Text<1>).column({ nonNull: true }); }
523+
id = Int8.column({ nonNull: true, generated: true }); person_id = Int8.column({ nonNull: true }); bio = Text.column({ nonNull: true }); }
524524

525525
const rows = await tx.execute(People.from()
526526
.select(({ people }) => ({
@@ -560,9 +560,9 @@ test("scalar with cardinality 'many' — array result", async () => {
560560
await tx.execute(sql`INSERT INTO children (name, parent_id) VALUES ('Charlie', 1), ('Diana', 1)`);
561561

562562
class Parents extends db.Table("parents") {
563-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); }
563+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); }
564564
class Children extends db.Table("children") {
565-
id = (Int8<1>).column({ nonNull: true, generated: true }); name = (Text<1>).column({ nonNull: true }); parent_id = (Int8<1>).column({ nonNull: true }); }
565+
id = Int8.column({ nonNull: true, generated: true }); name = Text.column({ nonNull: true }); parent_id = Int8.column({ nonNull: true }); }
566566

567567
const rows = await tx.execute(Parents.from()
568568
.select(({ parents }) => ({
@@ -861,9 +861,9 @@ test("type test: conn.execute(Table.from()) row methods are never-typed (uncalla
861861

862862
class Widgets extends db.Table("widgets") {
863863
@expose()
864-
id = (Int8<1>).column({ nonNull: true, generated: true });
864+
id = Int8.column({ nonNull: true, generated: true });
865865
@expose()
866-
name = (Text<1>).column({ nonNull: true });
866+
name = Text.column({ nonNull: true });
867867

868868
// Plain method — should not be a callable function on the row type.
869869
doStuff(): string {

0 commit comments

Comments
 (0)