flint-orm 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ ---
2
+ name: write-queries
3
+ description: >
4
+ Read, write, and modify data with type-safe SELECT, INSERT, UPDATE, DELETE,
5
+ joins, and aggregates. Covers selectFrom, insert, update, delete, leftJoin,
6
+ innerJoin, where, columns, single, orderBy, limit, offset, distinct,
7
+ returning, onConflictDoNothing, onConflictDoUpdate, count, sum, avg, min,
8
+ max, and raw SQL. Load when building queries or troubleshooting query issues.
9
+ metadata:
10
+ type: core
11
+ library: flint-orm
12
+ library_version: 0.7.0
13
+ sources:
14
+ - 'kavenlabs/flint-orm:src/query/builder.ts'
15
+ - 'kavenlabs/flint-orm:src/query/conditions.ts'
16
+ - 'kavenlabs/flint-orm:src/query/aggregates.ts'
17
+ - 'kavenlabs/flint-orm:src/flint.ts'
18
+ - 'kavenlabs/flint-orm:README.md'
19
+ - 'kavenlabs/flint-orm:API.md'
20
+ ---
21
+
22
+ # flint-orm — Queries
23
+
24
+ ## Setup
25
+
26
+ ```ts
27
+ import { flint } from 'flint-orm/bun-sqlite';
28
+ import { table, text, integer } from 'flint-orm/table';
29
+ import { eq, and } from 'flint-orm/expressions';
30
+
31
+ const users = table('users', {
32
+ id: text('id').primaryKey(),
33
+ name: text('name').notNull(),
34
+ age: integer('age'),
35
+ });
36
+
37
+ const db = flint({ url: './app.db' });
38
+ ```
39
+
40
+ ## Core Patterns
41
+
42
+ ### SELECT with conditions
43
+
44
+ ```ts
45
+ const adults = await db
46
+ .selectFrom(users)
47
+ .where(eq(users.age, 18))
48
+ .execute();
49
+ ```
50
+
51
+ ### SELECT specific columns
52
+
53
+ ```ts
54
+ const names = await db
55
+ .selectFrom(users)
56
+ .columns(['id', 'name'])
57
+ .execute();
58
+ // Returns: { id: string; name: string }[]
59
+ ```
60
+
61
+ ### Get a single row
62
+
63
+ ```ts
64
+ const user = await db
65
+ .selectFrom(users)
66
+ .where(eq(users.id, 'u1'))
67
+ .single()
68
+ .execute();
69
+ // Returns: User | null
70
+ ```
71
+
72
+ ### INSERT with returning
73
+
74
+ ```ts
75
+ // Return all columns
76
+ const inserted = await db
77
+ .insert(users)
78
+ .values({ id: 'u1', name: 'Alice', age: 30 })
79
+ .returning()
80
+ .execute();
81
+
82
+ // Return specific columns
83
+ const inserted = await db
84
+ .insert(users)
85
+ .values({ id: 'u1', name: 'Alice', age: 30 })
86
+ .returning(['id', 'name'])
87
+ .execute();
88
+ ```
89
+
90
+ ### UPSERT
91
+
92
+ ```ts
93
+ await db
94
+ .insert(users)
95
+ .values({ id: 'u1', name: 'Alice' })
96
+ .onConflictDoUpdate({
97
+ target: users.id,
98
+ set: { name: 'Alice Updated' },
99
+ })
100
+ .execute();
101
+ ```
102
+
103
+ ### UPDATE with conditions
104
+
105
+ ```ts
106
+ // Update without returning
107
+ await db
108
+ .update(users)
109
+ .set({ name: 'Bob' })
110
+ .where(eq(users.id, 'u1'))
111
+ .execute();
112
+
113
+ // Update with returning
114
+ const updated = await db
115
+ .update(users)
116
+ .set({ name: 'Bob' })
117
+ .where(eq(users.id, 'u1'))
118
+ .returning(['id', 'name'])
119
+ .execute();
120
+ ```
121
+
122
+ ### DELETE with conditions
123
+
124
+ ```ts
125
+ // Delete without returning
126
+ await db
127
+ .delete(users)
128
+ .where(eq(users.id, 'u1'))
129
+ .execute();
130
+
131
+ // Delete with returning
132
+ const deleted = await db
133
+ .delete(users)
134
+ .where(eq(users.id, 'u1'))
135
+ .returning()
136
+ .execute();
137
+ ```
138
+
139
+ ### LEFT JOIN
140
+
141
+ ```ts
142
+ const posts = table('posts', {
143
+ id: text('id').primaryKey(),
144
+ userId: text('userId').notNull().references(users.id),
145
+ title: text('title').notNull(),
146
+ });
147
+
148
+ const postsWithAuthors = await db
149
+ .leftJoin(users)
150
+ .on(posts)
151
+ .execute();
152
+ // Returns: { id: string; name: string; posts: Post[] }[]
153
+ ```
154
+
155
+ ### Aggregate functions
156
+
157
+ ```ts
158
+ const total = await db.count(users);
159
+ const activeCount = await db.count(users, eq(users.active, true));
160
+ const totalViews = await db.sum(posts, posts.views);
161
+ const avgAge = await db.avg(users, users.age);
162
+ ```
163
+
164
+ ## Building Queries Conditionally
165
+
166
+ The query builder is immutable — you can compose queries conditionally:
167
+
168
+ ```ts
169
+ let query = db.selectFrom(users);
170
+
171
+ if (filter.name) {
172
+ query = query.where(eq(users.name, filter.name));
173
+ }
174
+ if (filter.minAge) {
175
+ query = query.where(gte(users.age, filter.minAge));
176
+ }
177
+
178
+ const results = await query.execute();
179
+ ```
180
+
181
+ Call `.execute()` at the terminal state when ready to run the query.
182
+
183
+ ## Common Mistakes
184
+
185
+ ### CRITICAL Not calling .execute() at terminal state
186
+
187
+ Wrong:
188
+
189
+ ```ts
190
+ const query = db.selectFrom(users).where(eq(users.id, 'u1')); // Builder, not executed
191
+ const data = query; // Missing .execute()
192
+ ```
193
+
194
+ Correct:
195
+
196
+ ```ts
197
+ // Building queries conditionally is fine:
198
+ let query = db.selectFrom(users);
199
+ if (filter) query = query.where(eq(users.active, true));
200
+ // But call .execute() at the terminal state:
201
+ const data = await query.execute();
202
+ ```
203
+
204
+ Queries are builders — you can compose them conditionally, but `.execute()` must be called when ready to run the query.
205
+
206
+ Source: maintainer interview
207
+
208
+ ### CRITICAL Not awaiting .execute()
209
+
210
+ Wrong:
211
+
212
+ ```ts
213
+ const users = db.selectFrom(users).where(eq(users.id, 'u1')).execute(); // Promise, not data
214
+ ```
215
+
216
+ Correct:
217
+
218
+ ```ts
219
+ const users = await db.selectFrom(users).where(eq(users.id, 'u1')).execute();
220
+ ```
221
+
222
+ `.execute()` returns a Promise — without `await`, you get the Promise object, not the data.
223
+
224
+ Source: maintainer interview
225
+
226
+ ### HIGH Mixing Kysely/Drizzle/Supabase API patterns
227
+
228
+ Wrong:
229
+
230
+ ```ts
231
+ // Supabase-style (wrong)
232
+ const users = await db.from('users').select('id, name');
233
+ ```
234
+
235
+ Correct:
236
+
237
+ ```ts
238
+ // Flint-style
239
+ const users = await db.selectFrom(users).columns(['id', 'name']).execute();
240
+ ```
241
+
242
+ flint-orm has its own API — `selectFrom().columns([...]).single()` is specific to this library.
243
+
244
+ Source: maintainer interview
245
+
246
+ ### HIGH Using WHERE conditions with columns from wrong table
247
+
248
+ Wrong:
249
+
250
+ ```ts
251
+ // Using posts column in users query
252
+ await db.selectFrom(users).where(eq(posts.userId, 'u1')).execute(); // ERROR
253
+ ```
254
+
255
+ Correct:
256
+
257
+ ```ts
258
+ await db.selectFrom(users).where(eq(users.id, 'u1')).execute();
259
+ ```
260
+
261
+ The builder validates column ownership — columns in WHERE must belong to the queried table(s).
262
+
263
+ Source: src/query/builder.ts
264
+
265
+ ## References
266
+
267
+ - [Full condition operators reference](references/condition-operators.md)
@@ -0,0 +1,220 @@
1
+ # Condition Operators Reference
2
+
3
+ Detailed reference for all condition operators in flint-orm.
4
+
5
+ All conditions are imported from `flint-orm/expressions`.
6
+
7
+ ## Comparison Operators
8
+
9
+ ### eq(column, value)
10
+
11
+ Equal comparison.
12
+
13
+ ```ts
14
+ import { eq } from 'flint-orm/expressions';
15
+
16
+ // Value comparison
17
+ eq(users.name, 'Alice') // name = 'Alice'
18
+
19
+ // Column-to-column comparison
20
+ eq(posts.userId, users.id) // posts.userId = users.id
21
+ ```
22
+
23
+ ### neq(column, value)
24
+
25
+ Not equal comparison.
26
+
27
+ ```ts
28
+ import { neq } from 'flint-orm/expressions';
29
+
30
+ neq(users.id, 'excluded') // id != 'excluded'
31
+ ```
32
+
33
+ ### gt(column, value)
34
+
35
+ Greater than.
36
+
37
+ ```ts
38
+ import { gt } from 'flint-orm/expressions';
39
+
40
+ gt(users.age, 18) // age > 18
41
+ ```
42
+
43
+ ### gte(column, value)
44
+
45
+ Greater than or equal.
46
+
47
+ ```ts
48
+ import { gte } from 'flint-orm/expressions';
49
+
50
+ gte(users.age, 18) // age >= 18
51
+ ```
52
+
53
+ ### lt(column, value)
54
+
55
+ Less than.
56
+
57
+ ```ts
58
+ import { lt } from 'flint-orm/expressions';
59
+
60
+ lt(users.age, 65) // age < 65
61
+ ```
62
+
63
+ ### lte(column, value)
64
+
65
+ Less than or equal.
66
+
67
+ ```ts
68
+ import { lte } from 'flint-orm/expressions';
69
+
70
+ lte(users.age, 65) // age <= 65
71
+ ```
72
+
73
+ ## Range Operator
74
+
75
+ ### between(column, low, high)
76
+
77
+ Between two values (inclusive).
78
+
79
+ ```ts
80
+ import { between } from 'flint-orm/expressions';
81
+
82
+ between(users.age, 18, 65) // age BETWEEN 18 AND 65
83
+ ```
84
+
85
+ ## Null Check Operators
86
+
87
+ ### isNull(column)
88
+
89
+ Check for NULL.
90
+
91
+ ```ts
92
+ import { isNull } from 'flint-orm/expressions';
93
+
94
+ isNull(users.deletedAt) // deletedAt IS NULL
95
+ ```
96
+
97
+ ### isNotNull(column)
98
+
99
+ Check for NOT NULL.
100
+
101
+ ```ts
102
+ import { isNotNull } from 'flint-orm/expressions';
103
+
104
+ isNotNull(users.email) // email IS NOT NULL
105
+ ```
106
+
107
+ ## Array Operators
108
+
109
+ ### isIn(column, values)
110
+
111
+ Check if value is in array.
112
+
113
+ ```ts
114
+ import { isIn } from 'flint-orm/expressions';
115
+
116
+ isIn(users.id, ['u1', 'u2', 'u3']) // id IN ('u1', 'u2', 'u3')
117
+ ```
118
+
119
+ ### isNotIn(column, values)
120
+
121
+ Check if value is not in array.
122
+
123
+ ```ts
124
+ import { isNotIn } from 'flint-orm/expressions';
125
+
126
+ isNotIn(users.id, ['excluded']) // id NOT IN ('excluded')
127
+ ```
128
+
129
+ ## Pattern Matching Operators
130
+
131
+ ### like(column, pattern)
132
+
133
+ SQL LIKE pattern matching (% = any characters, _ = single char, case-insensitive).
134
+
135
+ ```ts
136
+ import { like } from 'flint-orm/expressions';
137
+
138
+ like(users.name, 'A%') // name LIKE 'A%'
139
+ ```
140
+
141
+ ### glob(column, pattern)
142
+
143
+ SQL GLOB pattern matching (* = any characters, ? = single char, case-sensitive).
144
+
145
+ ```ts
146
+ import { glob } from 'flint-orm/expressions';
147
+
148
+ glob(users.name, 'A*') // name GLOB 'A*'
149
+ ```
150
+
151
+ ## Logical Operators
152
+
153
+ ### and(...conditions)
154
+
155
+ Logical AND.
156
+
157
+ ```ts
158
+ import { and, eq, gt } from 'flint-orm/expressions';
159
+
160
+ and(eq(users.active, true), gt(users.age, 18))
161
+ // active = 1 AND age > 18
162
+ ```
163
+
164
+ ### or(...conditions)
165
+
166
+ Logical OR (wraps in parentheses).
167
+
168
+ ```ts
169
+ import { or, eq } from 'flint-orm/expressions';
170
+
171
+ or(eq(users.role, 'admin'), eq(users.role, 'moderator'))
172
+ // (role = 'admin' OR role = 'moderator')
173
+ ```
174
+
175
+ ## Composing Conditions
176
+
177
+ Conditions can be nested and combined:
178
+
179
+ ```ts
180
+ import { and, or, eq, gt, lte, isIn } from 'flint-orm/expressions';
181
+
182
+ // Complex condition
183
+ and(
184
+ or(eq(users.role, 'admin'), eq(users.role, 'moderator')),
185
+ gt(users.age, 18),
186
+ isIn(users.status, ['active', 'pending'])
187
+ )
188
+ // ((role = 'admin' OR role = 'moderator') AND age > 18 AND status IN ('active', 'pending'))
189
+ ```
190
+
191
+ ## Column-to-Column Comparisons
192
+
193
+ `eq` supports comparing two columns:
194
+
195
+ ```ts
196
+ import { eq } from 'flint-orm/expressions';
197
+
198
+ // Compare columns from different tables (useful for joins)
199
+ eq(posts.userId, users.id)
200
+ ```
201
+
202
+ ## Operator Summary
203
+
204
+ | Operator | SQL | Notes |
205
+ |----------|-----|-------|
206
+ | `eq` | `=` | Supports column-to-column |
207
+ | `neq` | `!=` | |
208
+ | `gt` | `>` | |
209
+ | `gte` | `>=` | |
210
+ | `lt` | `<` | |
211
+ | `lte` | `<=` | |
212
+ | `between` | `BETWEEN` | Inclusive range |
213
+ | `isNull` | `IS NULL` | |
214
+ | `isNotNull` | `IS NOT NULL` | |
215
+ | `isIn` | `IN` | Array of values |
216
+ | `isNotIn` | `NOT IN` | Array of values |
217
+ | `like` | `LIKE` | % and _ wildcards, case-insensitive |
218
+ | `glob` | `GLOB` | * and ? wildcards, case-sensitive |
219
+ | `and` | `AND` | Composable |
220
+ | `or` | `OR` | Wraps in parentheses |