Skip to content

Commit 72aaeb4

Browse files
authored
Add helpers functions to sql(db) (#4)
* separate pg shorthand * add pg.js to package.json's files * update readme * update types * Add helpers functions to `sql(db)` * replace sql(db).one by sql.one(db) * update tests * cleaner tests * add types * add sql(db).query * update test * update type definitions * update readme
1 parent 5ed3843 commit 72aaeb4

File tree

5 files changed

+139
-53
lines changed

5 files changed

+139
-53
lines changed

pg.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
const sql = require('./sql')
22

3-
const sqlPG = db => async (...args) => {
3+
module.exports = sql
4+
5+
module.exports.query = db => (...args) => db.query(sql(...args))
6+
7+
module.exports.one = db => async (...args) => {
8+
const {
9+
rows: [row]
10+
} = await db.query(sql(...args))
11+
return row
12+
}
13+
14+
module.exports.many = db => async (...args) => {
415
const { rows } = await db.query(sql(...args))
516
return rows
617
}
718

8-
module.exports = sqlPG
19+
module.exports.count = db => async (...args) => {
20+
const { rowCount } = await db.query(sql(...args))
21+
return rowCount
22+
}

readme.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,25 +165,31 @@ const main = async () => {
165165

166166
#### Shorthand for postgres
167167

168-
Since we ❤️ [node-postgres](https://github.com/brianc/node-postgres) so much, we created a shorthand for it :
168+
Since we ❤️ [node-postgres](https://github.com/brianc/node-postgres) so much, we created shorthands and helpers for it :
169169

170170
```js
171-
// long-version
172-
const sql = require('@sequencework/sql')
173-
const { rows: movies } = await db.query(sql`select * from movies`)
174-
175-
// equivalent, short-version
176171
const sql = require('@sequencework/sql/pg') // ⚠️ we import @sequencework/sql/pg
177-
const movies = await sql(db)`select * from movies`
178-
// sql(db) just calls db.query so db can be a client or a pool :)
172+
173+
// main export stays the same
174+
const query = sql`select * from movies where id = ${id}`
175+
176+
// default pg result object : https://node-postgres.com/api/result
177+
const { rows, rowCount } = await sql.query(db)`select * from movies`
178+
179+
// helpers
180+
const movies = await sql.many(db)`select * from movies`
181+
const movie = await sql.one(db)`select * from movies where id = ${id}`
182+
const nbMovie = await sql.count(
183+
db
184+
)`update from movies set name = ${name} where id = ${id}`
179185
```
180186

181187
You can then rewrite the previous `listMoviesByYear` function in a much more concise way 😎
182188

183189
```js
184190
const sql = require('@sequencework/sql/pg') // ⚠️ we import @sequencework/sql/pg
185191

186-
const listMoviesByYear = async (db, yearRange) => sql(db)`
192+
const listMoviesByYear = async (db, yearRange) => sql.many(db)`
187193
select * from movies
188194
where
189195
year >= ${yearRange[0]}

test/pg.test.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
1-
const sqlPG = require('../pg')
1+
const sql = require('../pg')
22

3-
test('shorthand for node-postgres', async () => {
4-
const sampleBooks = ['book1', 'book2']
5-
const db = {
6-
query: async ({ text, values }) => {
7-
if (text === 'select * from books') {
8-
return { rows: sampleBooks }
9-
}
10-
return { rows: [] }
3+
const sampleBooks = ['book1', 'book2']
4+
const db = {
5+
query: async ({ text, values }) => {
6+
if (text === 'select * from books') {
7+
return { rows: sampleBooks, rowCount: sampleBooks.length }
118
}
9+
return { rows: [], rowCount: 0 }
1210
}
11+
}
1312

14-
const books = await sqlPG(db)`select * from books`
13+
test("sql.query should return pg's query result", async () => {
14+
const { rows, rowCount } = await sql.query(db)`select * from books`
15+
expect(rows).toBe(sampleBooks)
16+
expect(rowCount).toBe(sampleBooks.length)
17+
})
18+
19+
test('sql.one should return the first row', async () => {
20+
const book = await sql.one(db)`select * from books`
21+
expect(book).toBe(sampleBooks[0])
22+
})
23+
24+
test('sql.many should return rows', async () => {
25+
const books = await sql.many(db)`select * from books`
1526
expect(books).toBe(sampleBooks)
1627
})
28+
29+
test('sql.count should return rowCount', async () => {
30+
const nbBooks = await sql.count(db)`select * from books`
31+
expect(nbBooks).toBe(sampleBooks.length)
32+
})

types/index.d.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,64 @@
11
// TypeScript Version: 2.9
22

3-
declare namespace sqlElements {
4-
interface QueryConfig {
5-
_sql?: SqlContainer
6-
text: string
7-
values: any[]
8-
}
9-
10-
class SqlContainer {
11-
constructor(chains: ReadonlyArray<string>, expressions: any[])
12-
readonly chains: ReadonlyArray<string>
13-
readonly expressions: any[]
14-
}
15-
}
16-
173
declare module '@sequencework/sql' {
184
function sql(
195
chains: ReadonlyArray<string>,
206
...expressions: any[]
21-
): sqlElements.QueryConfig
7+
): sql.QueryConfig
8+
9+
namespace sql {
10+
interface QueryConfig {
11+
_sql?: SqlContainer
12+
text: string
13+
values: any[]
14+
}
15+
16+
class SqlContainer {
17+
constructor(chains: ReadonlyArray<string>, expressions: any[])
18+
readonly chains: ReadonlyArray<string>
19+
readonly expressions: any[]
20+
}
21+
}
2222

2323
export = sql
2424
}
2525

2626
declare module '@sequencework/sql/pg' {
27-
function sqlPG(chains: {
28-
readonly query: (
29-
queryExpression: sqlElements.QueryConfig
30-
) => Promise<{
27+
import _sql = require('@sequencework/sql')
28+
29+
function sql(
30+
chains: ReadonlyArray<string>,
31+
...expressions: any[]
32+
): sql.QueryConfig
33+
34+
namespace sql {
35+
type QueryConfig = _sql.QueryConfig
36+
37+
interface PGQueryResult {
38+
rowCount: number
3139
rows: any[]
32-
}>
33-
}): (chains: ReadonlyArray<string>, ...expressions: any[]) => Promise<any[]>
40+
}
41+
42+
interface queryable<T extends PGQueryResult = PGQueryResult> {
43+
readonly query: (queryExpression: QueryConfig) => Promise<T>
44+
}
45+
46+
function query<T extends PGQueryResult>(
47+
db: queryable<T>
48+
): (chains: ReadonlyArray<string>, ...expressions: any[]) => Promise<T>
3449

35-
export = sqlPG
50+
function one(
51+
chains: queryable
52+
): (chains: ReadonlyArray<string>, ...expressions: any[]) => Promise<any>
53+
54+
function many(
55+
chains: queryable
56+
): (chains: ReadonlyArray<string>, ...expressions: any[]) => Promise<any[]>
57+
58+
function count(
59+
chains: queryable
60+
): (chains: ReadonlyArray<string>, ...expressions: any[]) => Promise<number>
61+
}
62+
63+
export = sql
3664
}

types/test.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,39 @@ sql`
5353

5454
// shorthand for node-postgres
5555
const sampleBooks = ['book1', 'book2']
56-
const db = {
57-
query: async ({ text, values }: { text: string; values: any[] }) => {
56+
interface CustomQueryResult {
57+
rows: any[]
58+
rowCount: number
59+
oid: number
60+
}
61+
const db: sqlPG.queryable<CustomQueryResult> = {
62+
query: async ({ text, values }) => {
5863
if (text === 'select * from books') {
59-
return { rows: sampleBooks }
64+
return {
65+
rows: sampleBooks,
66+
rowCount: sampleBooks.length,
67+
oid: Math.random()
68+
}
6069
}
61-
return { rows: [] }
70+
return { rows: [], rowCount: 0, oid: Math.random() }
6271
}
6372
}
64-
const getBooks = async (): Promise<string[]> => {
65-
const rows = await sqlPG(db)`select * from books`
66-
return rows as string[]
67-
}
68-
// $ExpectType Promise<string[]>
69-
getBooks()
73+
// sqlPG.query should return pg's query result
74+
// $ExpectType Promise<CustomQueryResult>
75+
sqlPG.query(db)`select * from books`
76+
77+
// sqlPG.one should return the first row
78+
// $ExpectType Promise<any>
79+
sqlPG.one(db)`select * from books`
80+
81+
// sqlPG.many should return rows
82+
// $ExpectType Promise<any[]>
83+
sqlPG.many(db)`select * from books`
84+
85+
// sqlPG.count should return rowCount
86+
// $ExpectType Promise<number>
87+
sqlPG.count(db)`select * from books`
88+
89+
// sqlPG should return PGQueryConfig
90+
// $ExpectType QueryConfig
91+
sqlPG`select * from books`

0 commit comments

Comments
 (0)