@vanit-co/sql-ts 0.2.0 → 0.3.0

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.
Files changed (2) hide show
  1. package/README.md +48 -45
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@ Writing raw SQL in TypeScript runs into a set of recurring friction points that
10
10
 
11
11
  - **Automatic identifier quoting** — table and column names are interpolated as properly quoted identifiers (`` `name` `` for MySQL, `"name"` for PostgreSQL), never as bind parameters. No manual quoting, no dialect-specific escaping scattered across your codebase.
12
12
 
13
- - **Table alias and qualified column references** — the `select` tag (and its aliases `join`, `where`) automatically expands schema tables as `"table" "alias"` and columns as `"alias"."column"`, so JOIN-heavy queries stay unambiguous without hand-writing every qualified reference.
13
+ - **Table alias and qualified column references** — the `select` tag (and its aliases `groupBy`, `having`, `join`, `orderBy`, `where`) automatically expands schema tables as `"table" "alias"` and columns as `"alias"."column"`, so JOIN-heavy queries stay unambiguous without hand-writing every qualified reference.
14
14
 
15
15
  - **Column alias expansion** — `selectAs` goes further, rendering each column as `"alias"."column" as "alias_column"`. When querying multiple joined tables, result-set keys no longer collide.
16
16
 
@@ -26,7 +26,7 @@ npm install @vanit-co/sql-ts
26
26
 
27
27
  ## Quick example
28
28
 
29
- **sql** tagged template literal takes care of quoting the identifiers (tables and columns) with the proper quotes `` ` `` for MySQL and `"` for PostgreSQL.
29
+ **sql** tag takes care of quoting the identifiers (tables and columns) with the proper quotes `` ` `` for MySQL and `"` for PostgreSQL.
30
30
 
31
31
  ```ts
32
32
  import { schema, sql, all } from '@vanit-co/sql-ts'
@@ -46,7 +46,7 @@ console.log(query.values) // [42]
46
46
 
47
47
  ## Full query example
48
48
 
49
- **select** tagged template literal works like **sql** but automatically adds table aliases and column prefixes. The other tagged template literals **join** and **where** are just aliases to **select** with the aim of maintaining semantics. The **selectAs** tagged template literal besides the column prefixes will also add the column alias using the format `$prefix_$columnName`.
49
+ **select** tag works like **sql** but automatically adds table aliases and column prefixes. The other tags **groupBy**, **having**, **join**, **orderBy** and **where** are just aliases to **select** with the aim of maintaining semantics. The **selectAs** tag besides the column prefixes will also add the column alias using the format `$prefix_$columnName`.
50
50
 
51
51
  ```ts
52
52
  import { schema, select, selectAs, join, where, all, insert, update, empty } from '@vanit-co/sql-ts'
@@ -74,9 +74,9 @@ ins.text // insert into "users" ("id" ,"email") values ($1 ,$2)
74
74
  ins.values // [1, 'alice@example.com']
75
75
 
76
76
  // UPDATE
77
- const upd = update(users, { email: 'new@example.com' })
78
- upd.text // update "users" set "email" = $1
79
- upd.values // ['new@example.com']
77
+ const upd = update(users, { email: 'new@example.com' }).append(sql` where ${users.id} = ${id}`)
78
+ upd.text // update "users" set "email" = $1 where "id" = $2
79
+ upd.values // ['new@example.com', 42]
80
80
  ```
81
81
 
82
82
  ---
@@ -105,34 +105,6 @@ const u = schema({ table: 'users', columns: ['id', 'email'], alias: 'u' })
105
105
 
106
106
  After calling `schema`, the returned object has a typed property for each column (`users.id`, `users.email`, etc.).
107
107
 
108
- ### `as(column)`
109
-
110
- Returns the aliased column name as a plain string — the same `prefix_name` string that `selectAs` writes into the SQL `AS` clause. Use this to read a column out of query results by its aliased key without repeating the string manually.
111
-
112
- ```ts
113
- import { schema, as, selectAs, all } from '@vanit-co/sql-ts'
114
-
115
- const users = schema({ table: 'users', columns: ['id', 'email'] })
116
- const u = schema({ table: 'users', columns: ['id', 'email'], alias: 'u' })
117
-
118
- as(users.id) // 'users_id'
119
- as(users.email) // 'users_email'
120
-
121
- as(u.id) // 'u_id'
122
- as(u.email) // 'u_email'
123
- ```
124
-
125
- This is particularly useful when mapping over result rows:
126
-
127
- ```ts
128
- const rows = await client.query(selectAs`SELECT ${all(users)} FROM ${users}`)
129
-
130
- rows.map(row => ({
131
- id: row[as(users.id)], // row['users_id']
132
- email: row[as(users.email)], // row['users_email']
133
- }))
134
- ```
135
-
136
108
  ---
137
109
 
138
110
  ### Result object
@@ -225,20 +197,23 @@ selectAs`SELECT ${users.email}`.text // SELECT "users"."email" as "users_email"
225
197
  sa`SELECT ${u.email}`.text // SELECT "u"."email" as "u_email"
226
198
  ```
227
199
 
228
- ### `join` (alias: `j`) and `where` (alias: `w`)
200
+ ### `groupBy` (alias: `g`), `having` (alias: `h`), `join` (alias: `j`), `orderBy` (alias: `o`) and `where` (alias: `w`)
229
201
 
230
- These are identical to `select`. They exist as semantic aliases so your query construction reads naturally.
202
+ These are all identical to `select`. They exist as semantic aliases so your query construction reads naturally — each tag signals which SQL clause it belongs to.
231
203
 
232
204
  ```ts
233
- import { select, join, j, where, w, schema } from '@vanit-co/sql-ts'
205
+ import { select, join, j, where, w, groupBy, g, having, h, orderBy, o, schema } from '@vanit-co/sql-ts'
234
206
 
235
207
  const posts = schema({ table: 'posts', columns: ['id', 'user_id', 'title'] })
236
208
  const users = schema({ table: 'users', columns: ['id', 'email'] })
237
209
 
238
210
  const q = select`SELECT ${posts.title}, ${users.email}`
239
- const fromClause = join`FROM ${posts}`
240
- const joinClause = join`JOIN ${users} ON ${posts.user_id} = ${users.id}`
241
- const whereClause = where`WHERE ${users.id} = ${99}`
211
+ const fromClause = join` FROM ${posts}`
212
+ const joinClause = join` JOIN ${users} ON ${posts.user_id} = ${users.id}`
213
+ const whereClause = where` WHERE ${users.id} = ${99}`
214
+ const groupClause = groupBy` GROUP BY ${posts.title}`
215
+ const havingClause = having` HAVING COUNT(${posts.id}) > ${1}`
216
+ const orderClause = orderBy` ORDER BY ${posts.title}`
242
217
  ```
243
218
 
244
219
  ---
@@ -293,6 +268,34 @@ selectAs`SELECT ${pick(users.id, users.email)}`.text
293
268
  // SELECT "users"."id" as "users_id" ,"users"."email" as "users_email"
294
269
  ```
295
270
 
271
+ ### `as(column)`
272
+
273
+ Returns the aliased column name as a plain string — the same `prefix_name` string that `selectAs` writes into the SQL `AS` clause. Use this to read a column out of query results by its aliased key without repeating the string manually.
274
+
275
+ ```ts
276
+ import { schema, as, selectAs, all } from '@vanit-co/sql-ts'
277
+
278
+ const users = schema({ table: 'users', columns: ['id', 'email'] })
279
+ const u = schema({ table: 'users', columns: ['id', 'email'], alias: 'u' })
280
+
281
+ as(users.id) // 'users_id'
282
+ as(users.email) // 'users_email'
283
+
284
+ as(u.id) // 'u_id'
285
+ as(u.email) // 'u_email'
286
+ ```
287
+
288
+ This is particularly useful when mapping over result rows:
289
+
290
+ ```ts
291
+ const rows = await client.query(selectAs`SELECT ${all(users)} FROM ${users}`)
292
+
293
+ rows.map(row => ({
294
+ id: row[as(users.id)], // row['users_id']
295
+ email: row[as(users.email)], // row['users_email']
296
+ }))
297
+ ```
298
+
296
299
  ---
297
300
 
298
301
  ## Statement builders: `insert` and `update`
@@ -382,7 +385,7 @@ const posts = schema({ table: 'posts', columns: ['id', 'user_id', 'title'], alia
382
385
 
383
386
  const buildQuery = (userId: number) =>
384
387
  pipe(
385
- concat(join` JOIN ${users} ON ${posts.user_id} = ${users.id}`),
388
+ concat(join` JOIN ${users} ON ${posts.user_id} = ${users.id}`),
386
389
  concat(where` WHERE ${users.id} = ${userId}`)
387
390
  )(selectAs`SELECT ${all(users, posts)} FROM ${posts}`)
388
391
 
@@ -404,7 +407,7 @@ import { schema, selectAs, join, where, concat, all } from '@vanit-co/sql-ts'
404
407
 
405
408
  const q = pipe(
406
409
  selectAs`SELECT ${all(users, posts)} FROM ${posts}`,
407
- concat(join` JOIN ${users} ON ${posts.user_id} = ${users.id}`),
410
+ concat(join` JOIN ${users} ON ${posts.user_id} = ${users.id}`),
408
411
  concat(where` WHERE ${users.id} = ${42}`)
409
412
  )
410
413
  ```
@@ -425,9 +428,9 @@ type Filters = { userId?: number; titleLike?: string }
425
428
  const buildPostsQuery = ({ userId, titleLike }: Filters) => {
426
429
  const clauses = [
427
430
  select`SELECT ${all(users, posts)} FROM ${posts}`,
428
- join` JOIN ${users} ON ${posts.user_id} = ${users.id}`,
429
- userId ? where` WHERE ${users.id} = ${userId}` : empty,
430
- titleLike ? where` AND ${posts.title} LIKE ${titleLike}` : empty,
431
+ join` JOIN ${users} ON ${posts.user_id} = ${users.id}`,
432
+ userId ? where` WHERE ${users.id} = ${userId}` : empty,
433
+ titleLike ? where` AND ${posts.title} LIKE ${titleLike}` : empty,
431
434
  ]
432
435
 
433
436
  return reduce(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanit-co/sql-ts",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A TypeScript SQL query builder using tagged template literals. Write plain SQL with safe, automatic parameter binding and properly quoted identifiers. No DSL to learn, no magic, no ORM.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",