workers-qb 1.9.0 → 1.10.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.
- package/README.md +90 -48
- package/dist/index.js +6 -1
- package/dist/index.mjs +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,44 +1,69 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>workers-qb</h1>
|
|
3
|
+
<p><em>Zero-dependency Query Builder for Cloudflare Workers</em></p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://workers-qb.massadas.com/" target="_blank">
|
|
7
|
+
<img src="https://img.shields.io/badge/docs-workers--qb-blue.svg" alt="Documentation">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/workers-qb" target="_blank">
|
|
10
|
+
<img src="https://img.shields.io/npm/v/workers-qb.svg" alt="npm version">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/G4brym/workers-qb/blob/main/LICENSE" target="_blank">
|
|
13
|
+
<img src="https://img.shields.io/badge/license-MIT-brightgreen.svg" alt="Software License">
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
4
17
|
|
|
5
|
-
|
|
18
|
+
## Overview
|
|
6
19
|
|
|
7
|
-
|
|
8
|
-
traditional ORM.
|
|
20
|
+
workers-qb is a lightweight query builder designed specifically for Cloudflare Workers. It provides a simple, standardized interface while maintaining the performance benefits of raw queries over traditional ORMs.
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
from code for direct SQL access using convenient wrapper methods.
|
|
22
|
+
📚 [Read the full documentation](https://workers-qb.massadas.com/)
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
### Key Differences from ORMs
|
|
14
25
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
26
|
+
- Focused on direct SQL access with convenient wrapper methods
|
|
27
|
+
- Maintains raw query performance
|
|
28
|
+
- Zero dependencies
|
|
29
|
+
- Lightweight and Worker-optimized
|
|
30
|
+
|
|
31
|
+
## Supported Databases
|
|
32
|
+
|
|
33
|
+
- ☁️ [Cloudflare D1](https://workers-qb.massadas.com/databases/cloudflare-d1/)
|
|
34
|
+
- 💾 [Cloudflare Durable Objects](https://workers-qb.massadas.com/databases/cloudflare-do/)
|
|
35
|
+
- 🐘 [PostgreSQL (via node-postgres)](https://workers-qb.massadas.com/databases/postgresql/)
|
|
36
|
+
- 🔌 [Bring Your Own Database](https://workers-qb.massadas.com/databases/bring-your-own-database/)
|
|
19
37
|
|
|
20
38
|
## Features
|
|
21
39
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
40
|
+
### Core Features
|
|
41
|
+
- Zero dependencies
|
|
42
|
+
- Full TypeScript support
|
|
43
|
+
- Database schema migrations
|
|
44
|
+
- Type checking for data reads
|
|
45
|
+
- Lazy row loading
|
|
46
|
+
|
|
47
|
+
### Query Operations
|
|
48
|
+
- Table operations (create/drop)
|
|
49
|
+
- CRUD operations (insert/update/select/delete)
|
|
50
|
+
- Bulk inserts
|
|
51
|
+
- JOIN queries
|
|
52
|
+
- Modular SELECT queries
|
|
53
|
+
- ON CONFLICT handling
|
|
54
|
+
- UPSERT support
|
|
32
55
|
|
|
33
56
|
## Installation
|
|
34
57
|
|
|
35
|
-
```
|
|
58
|
+
```bash
|
|
36
59
|
npm install workers-qb --save
|
|
37
60
|
```
|
|
38
61
|
|
|
39
|
-
##
|
|
62
|
+
## Usage Examples
|
|
63
|
+
|
|
64
|
+
### Cloudflare D1
|
|
40
65
|
|
|
41
|
-
```
|
|
66
|
+
```typescript
|
|
42
67
|
import { D1QB } from 'workers-qb'
|
|
43
68
|
|
|
44
69
|
export interface Env {
|
|
@@ -55,7 +80,7 @@ export default {
|
|
|
55
80
|
level: number
|
|
56
81
|
}
|
|
57
82
|
|
|
58
|
-
//
|
|
83
|
+
// Using object syntax
|
|
59
84
|
const employeeList = await qb
|
|
60
85
|
.fetchAll<Employee>({
|
|
61
86
|
tableName: 'employees',
|
|
@@ -66,11 +91,11 @@ export default {
|
|
|
66
91
|
})
|
|
67
92
|
.execute()
|
|
68
93
|
|
|
69
|
-
//
|
|
70
|
-
const employeeListModular = await qb
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
// Using method chaining
|
|
95
|
+
const employeeListModular = await qb
|
|
96
|
+
.select<Employee>('employees')
|
|
97
|
+
.where('active = ?', true)
|
|
98
|
+
.execute()
|
|
74
99
|
|
|
75
100
|
return Response.json({
|
|
76
101
|
activeEmployees: employeeList.results?.length || 0,
|
|
@@ -79,41 +104,39 @@ export default {
|
|
|
79
104
|
}
|
|
80
105
|
```
|
|
81
106
|
|
|
82
|
-
|
|
107
|
+
### Cloudflare Durable Objects
|
|
83
108
|
|
|
84
|
-
```
|
|
109
|
+
```typescript
|
|
85
110
|
import { DOQB } from 'workers-qb'
|
|
86
111
|
|
|
87
112
|
export class DOSRS extends DurableObject {
|
|
88
113
|
getEmployees() {
|
|
89
114
|
const qb = new DOQB(this.ctx.storage.sql)
|
|
90
|
-
|
|
91
|
-
|
|
115
|
+
|
|
116
|
+
return qb
|
|
92
117
|
.fetchAll({
|
|
93
118
|
tableName: 'employees',
|
|
94
119
|
})
|
|
95
120
|
.execute()
|
|
96
|
-
|
|
97
|
-
return fetched.results
|
|
121
|
+
.results
|
|
98
122
|
}
|
|
99
123
|
}
|
|
100
124
|
```
|
|
101
125
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Remember to close the connection using `ctx.waitUntil(qb.close());` or `await qb.close();` at the end of your request.
|
|
105
|
-
You may also reuse this connection to execute multiple queries, or share it between multiple requests if you are using
|
|
106
|
-
a connection pool in front of your PostgreSQL.
|
|
107
|
-
|
|
108
|
-
You must also enable `node_compat = true` in your `wrangler.toml`
|
|
109
|
-
|
|
110
|
-
You need to install `node-postgres`:
|
|
126
|
+
### PostgreSQL Integration
|
|
111
127
|
|
|
128
|
+
First, install the required PostgreSQL client:
|
|
112
129
|
```bash
|
|
113
130
|
npm install pg --save
|
|
114
131
|
```
|
|
115
132
|
|
|
116
|
-
|
|
133
|
+
Enable Node compatibility in `wrangler.toml`:
|
|
134
|
+
```toml
|
|
135
|
+
node_compat = true
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Example usage:
|
|
139
|
+
```typescript
|
|
117
140
|
import { PGQB } from 'workers-qb'
|
|
118
141
|
import { Client } from 'pg'
|
|
119
142
|
|
|
@@ -126,7 +149,6 @@ export default {
|
|
|
126
149
|
const qb = new PGQB(new Client(env.DB_URL))
|
|
127
150
|
await qb.connect()
|
|
128
151
|
|
|
129
|
-
// Generated query: SELECT count(*) as count FROM employees WHERE active = ?1 LIMIT 1
|
|
130
152
|
const fetched = await qb
|
|
131
153
|
.fetchOne({
|
|
132
154
|
tableName: 'employees',
|
|
@@ -138,10 +160,30 @@ export default {
|
|
|
138
160
|
})
|
|
139
161
|
.execute()
|
|
140
162
|
|
|
163
|
+
// Important: Close the connection
|
|
141
164
|
ctx.waitUntil(qb.close())
|
|
165
|
+
|
|
142
166
|
return Response.json({
|
|
143
167
|
activeEmployees: fetched.results?.count || 0,
|
|
144
168
|
})
|
|
145
169
|
},
|
|
146
170
|
}
|
|
147
171
|
```
|
|
172
|
+
|
|
173
|
+
## Documentation
|
|
174
|
+
|
|
175
|
+
Visit our [comprehensive documentation](https://workers-qb.massadas.com/) for detailed information about:
|
|
176
|
+
|
|
177
|
+
- [Basic Queries](https://workers-qb.massadas.com/basic-queries/)
|
|
178
|
+
- [Advanced Queries](https://workers-qb.massadas.com/advanced-queries/)
|
|
179
|
+
- [Migrations](https://workers-qb.massadas.com/migrations/)
|
|
180
|
+
- [Type Checking](https://workers-qb.massadas.com/type-check/)
|
|
181
|
+
- [Database-specific guides](https://workers-qb.massadas.com/databases/)
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/dist/index.js
CHANGED
|
@@ -546,6 +546,11 @@ var QueryBuilder = class {
|
|
|
546
546
|
}
|
|
547
547
|
_update(params) {
|
|
548
548
|
const whereParamsLength = typeof params.where === "object" && !Array.isArray(params.where) && params.where?.params ? Array.isArray(params.where?.params) ? Object.keys(params.where?.params).length : 1 : 0;
|
|
549
|
+
let whereString = this._where(params.where);
|
|
550
|
+
let parameterIndex = 1;
|
|
551
|
+
if (whereString && whereString.match(/(?<!\d)\?(?!\d)/)) {
|
|
552
|
+
whereString = whereString.replace(/\?/g, () => `?${parameterIndex++}`);
|
|
553
|
+
}
|
|
549
554
|
const set = [];
|
|
550
555
|
let index = 1;
|
|
551
556
|
for (const [key, value] of Object.entries(params.data)) {
|
|
@@ -557,7 +562,7 @@ var QueryBuilder = class {
|
|
|
557
562
|
}
|
|
558
563
|
}
|
|
559
564
|
return `UPDATE ${this._onConflict(params.onConflict)}${params.tableName}
|
|
560
|
-
SET ${set.join(", ")}` +
|
|
565
|
+
SET ${set.join(", ")}` + whereString + this._returning(params.returning);
|
|
561
566
|
}
|
|
562
567
|
_delete(params) {
|
|
563
568
|
return `DELETE
|
package/dist/index.mjs
CHANGED
|
@@ -504,6 +504,11 @@ var QueryBuilder = class {
|
|
|
504
504
|
}
|
|
505
505
|
_update(params) {
|
|
506
506
|
const whereParamsLength = typeof params.where === "object" && !Array.isArray(params.where) && params.where?.params ? Array.isArray(params.where?.params) ? Object.keys(params.where?.params).length : 1 : 0;
|
|
507
|
+
let whereString = this._where(params.where);
|
|
508
|
+
let parameterIndex = 1;
|
|
509
|
+
if (whereString && whereString.match(/(?<!\d)\?(?!\d)/)) {
|
|
510
|
+
whereString = whereString.replace(/\?/g, () => `?${parameterIndex++}`);
|
|
511
|
+
}
|
|
507
512
|
const set = [];
|
|
508
513
|
let index = 1;
|
|
509
514
|
for (const [key, value] of Object.entries(params.data)) {
|
|
@@ -515,7 +520,7 @@ var QueryBuilder = class {
|
|
|
515
520
|
}
|
|
516
521
|
}
|
|
517
522
|
return `UPDATE ${this._onConflict(params.onConflict)}${params.tableName}
|
|
518
|
-
SET ${set.join(", ")}` +
|
|
523
|
+
SET ${set.join(", ")}` + whereString + this._returning(params.returning);
|
|
519
524
|
}
|
|
520
525
|
_delete(params) {
|
|
521
526
|
return `DELETE
|