dibs-query-schema 0.1.1

Facet types for the dibs query DSL schema
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
@schema {id crate:dibs-queries@1, cli dibs}

// Queries for my-app ecommerce example.
// These are parsed by dibs-qgen and generate Rust code + SQL.
//
// This file showcases all supported query features including:
// - Basic queries with WHERE, ORDER BY, LIMIT/OFFSET
// - Parameters and filters (@null, @ilike, @gte, @lte, @in, @ne)
// - Relations (first true, vec relations)
// - Mutations (INSERT, UPDATE, UPSERT, DELETE)
// - SQL functions (@now, @coalesce, @lower, @concat, etc.)
// - DISTINCT and COUNT queries
// - JSONB operators (@>, @?, ->, ->>)

// ============================================================================
// Basic Queries
// ============================================================================

AllProducts @select{
    from product
    where {deleted_at @null}
    order-by {created_at desc}
    fields {id, handle, status, active}
}

ActiveProducts @select{
    from product
    where {status "published", active true, deleted_at @null}
    order-by {created_at desc}
    limit 2
    fields {id, handle, status}
}

ProductByHandle @select{
    params {handle @string}
    from product
    where {handle $handle, deleted_at @null}
    first true
    fields {id, handle, status, active}
}

SearchProducts @select{
    params {q @string}
    from product
    where {handle @ilike($q), deleted_at @null}
    order-by {handle asc}
    limit 50
    fields {id, handle, status}
}
// Paginated query with limit/offset parameters

ProductsPaginated @select{
    params {page_size @int, page_offset @int}
    from product
    where {deleted_at @null}
    order-by {handle asc}
    limit $page_size
    offset $page_offset
    fields {id, handle, status, active}
}
// Query with JOIN - returns product with its first translation (singular relation)

ProductWithTranslation @select{
    params {handle @string}
    from product
    where {handle $handle, deleted_at @null}
    first true
    fields {
        id
        handle
        status
        translation @rel{
            from product_translation
            first true
            fields {locale, title, description}
        }
    }
}

// Query with vec relation - returns product with all translations (plural relation)

ProductWithAllTranslations @select{
    params {handle @string}
    from product
    where {handle $handle, deleted_at @null}
    first true
    fields {
        id
        handle
        status
        translations @rel{
            from product_translation
            fields {locale, title, description}
        }
    }
}

// DISTINCT query - unique statuses

UniqueStatuses @select{
    from product
    where {deleted_at @null}
    distinct true
    fields {status}
}

// COUNT query - count products by status

CountProducts @select{
    from product
    where {deleted_at @null}
    count true
    fields {id}
}

// Query with filter operators
// TODO: Fix SQL generation bug where multiple filters on same column aren't all included
//
// ProductsByPriceRange @select{
//     params {min_price @int, max_price @int}
//     from product
//     where {
//         price @gte($min_price)
//         price @lte($max_price)
//         deleted_at @null
//     }
//     fields {id, handle, price}
// }

// Query with literal @in filter

ProductsByKnownHandles @select{
    from product
    where {handle @in("prod-1" "prod-2" "prod-3"), deleted_at @null}
    fields {id, handle, status}
}

// Query with @ne filter

ProductsExcludingStatus @select{
    params {excluded_status @string}
    from product
    where {status @ne($excluded_status), deleted_at @null}
    fields {id, handle, status}
}

// ============================================================================
// Mutations
// ============================================================================

// Insert a new product with @now function

CreateProduct @insert{
    params {handle @string, status @string}
    into product
    values {handle $handle, status $status, created_at @now}
    returning {id, handle, status}
}

// Insert with multiple SQL functions

CreateProductWithFunctions @insert{
    params {handle @string, status @string, description @string}
    into product
    values {
        handle @lower($handle)
        status @coalesce($status "draft")
        description $description
        created_at @now
    }
    returning {id, handle, status}
}

// Insert with nested function calls

CreateProductNormalized @insert{
    params {handle @string}
    into product
    values {
        handle @lower(@concat("prod-" $handle))
        status "draft"
        created_at @now
    }
    returning {id, handle}
}

// Insert a product with default status

CreateProductWithDefaults @insert{
    params {handle @string}
    into product
    values {handle $handle, status @default, created_at @now}
    returning {id, handle, status}
}

// Upsert a product - insert or update on conflict

UpsertProduct @upsert{
    params {handle @string, status @string}
    into product
    on-conflict {
        target {handle}
        update {status, updated_at @now}
    }
    values {handle $handle, status $status, created_at @now}
    returning {id, handle, status}
}

// ============================================================================
// Bulk Mutations (insert/upsert multiple rows with a single query)
// ============================================================================

// Bulk insert products - inserts multiple rows using UNNEST
// Generated function accepts &[BulkCreateProductsParams] slice

BulkCreateProducts @insert-many{
    params {handle @string, status @string}
    into product
    values {handle $handle, status $status, created_at @now}
    returning {id, handle, status}
}

// Bulk upsert products - upserts multiple rows using UNNEST + ON CONFLICT
// Great for syncing data from external sources

BulkUpsertProducts @upsert-many{
    params {handle @string, status @string}
    into product
    on-conflict {
        target {handle}
        update {status, updated_at @now}
    }
    values {handle $handle, status $status, created_at @now}
    returning {id, handle, status}
}

// Update a product by handle

UpdateProductStatus @update{
    params {handle @string, status @string}
    table product
    set {status $status, updated_at @now}
    where {handle $handle}
    returning {id, handle, status}
}

// Update with SQL functions

UpdateProductWithFunctions @update{
    params {handle @string, new_handle @string, new_status @string}
    table product
    set {
        handle @lower($new_handle)
        status @coalesce($new_status "draft")
        updated_at @now
    }
    where {handle $handle}
    returning {id, handle, status}
}

// Soft delete a product

SoftDeleteProduct @update{
    params {handle @string}
    table product
    set {deleted_at @now}
    where {handle $handle}
    returning {id, handle}
}

// Hard delete a product (use with caution!)

DeleteProduct @delete{
    params {id @int}
    from product
    where {id $id}
    returning {id, handle}
}

// ============================================================================
// JSONB Operators (if you have JSONB columns)
// ============================================================================
// Note: These examples show the syntax but require a metadata JSONB column
// in your product table to work. Commented out for now.

// Query with JSONB containment (@>)
// Finds products where metadata contains the specified key-value pair
//
// ProductsByMetadataContains @select{
//     params {search_json @string}
//     from product
//     where {metadata @>($search_json), deleted_at @null}
//     fields {id, handle, metadata}
// }

// Query with JSONB key exists (@?)
//
// ProductsWithMetadataKey @select{
//     params {key_name @string}
//     from product
//     where {metadata @?($key_name), deleted_at @null}
//     fields {id, handle, metadata}
// }

// Query with JSONB field access (->)
//
// ProductsByMetadataField @select{
//     params {tag @string}
//     from product
//     where {metadata -> "tags" @>($tag), deleted_at @null}
//     fields {id, handle, metadata}
// }

// Query with JSONB text extraction (->>)
//
// ProductsByMetadataText @select{
//     params {category @string}
//     from product
//     where {metadata ->> "category" $category, deleted_at @null}
//     fields {id, handle, metadata}
// }

// ============================================================================
// Advanced Examples
// ============================================================================

// Complex query with multiple relations, filters, and ordering

ProductDetailsFull @select{
    params {id @int}
    from product
    where {id $id, deleted_at @null}
    first true
    fields {
        id
        handle
        status
        active
        price
        created_at
        updated_at
        locales @rel{
            from product_translation
            where {locale @in("en" "fr")}
            order-by {locale asc}
            fields {locale, title, description}
        }
        variants @rel{
            from product_variant
            where {deleted_at @null}
            order-by {position asc}
            fields {
                id
                sku
                price
                inventory_quantity
            }
        }
    }
}

// Upsert with functions - insert with fallback values

UpsertProductWithDefaults @upsert{
    params {handle @string, status @string, description @string}
    into product
    on-conflict {
        target {handle}
        update {
            status @coalesce($status status)
            description @coalesce($description description)
            updated_at @now
        }
    }
    values {
        handle @lower($handle)
        status @coalesce($status "draft")
        description $description
        created_at @now
    }
    returning {id, handle, status, description}
}

// Query with raw SQL (for complex queries not expressible in DSL)

ProductStats @select{
    sql <<SQL,sql
        SELECT
            status,
            COUNT(*) as count,
            AVG(price) as avg_price,
            MIN(price) as min_price,
            MAX(price) as max_price
        FROM product
        WHERE deleted_at IS NULL
        GROUP BY status
        ORDER BY status
    SQL
    returns {
        status @string
        count @int
        avg_price @decimal
        min_price @decimal
        max_price @decimal
    }
}