@possumtech/sqlrite 0.1.2 → 0.1.5
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/CODE_OF_CONDUCT.md +13 -0
- package/CONTRIBUTING.md +1 -0
- package/README.md +63 -10
- package/SqlRite.d.ts +22 -0
- package/SqlRite.js +32 -11
- package/biome.json +1 -1
- package/package.json +1 -1
- package/sql/test.sql +3 -0
- package/test/test.js +2 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# sqlrite Contributor Code of Conduct
|
|
2
|
+
|
|
3
|
+
sqlrite is an open source project and not a community. It exists to perform the
|
|
4
|
+
technical goals outlined in the readme and implemented in the codebase. All
|
|
5
|
+
contributions are equally welcome, except from those who reject the premise that
|
|
6
|
+
Sqlrite is an open source project and not a community.
|
|
7
|
+
|
|
8
|
+
Those seeking a "community" are encouraged to reach out to a local church,
|
|
9
|
+
mosque, temple, synagogue, or local civic organization, at your discretion, for
|
|
10
|
+
community support. sqlrite does not support or endorse any cause or campaign.
|
|
11
|
+
|
|
12
|
+
Conversations on the platform are to pertain to the project. All other topics
|
|
13
|
+
are unwelcome.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Contributions are welcome, and I will do my best to work with you on any workflow, coding style, or other issues that may arise.
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ them all.
|
|
|
47
47
|
|
|
48
48
|
There are three types of "chunk" one can add to a `.sql` file:
|
|
49
49
|
|
|
50
|
-
1. **INIT**: A transaction that is executed when the
|
|
50
|
+
1. **INIT**: A transaction that is executed when the module is instantiated.
|
|
51
51
|
This is where you should create your tables, for example.
|
|
52
52
|
|
|
53
53
|
2. **EXEC**: A transaction that can be executed at any time. For example,
|
|
@@ -55,7 +55,36 @@ This is where you should create your tables, for example.
|
|
|
55
55
|
not prepared statements, like maintaining your database.
|
|
56
56
|
|
|
57
57
|
3. **PREP**: A prepared statement that can be executed at any time. This is
|
|
58
|
-
where you should put your queries.
|
|
58
|
+
where you should put your queries. After declaring a prepared statement, you can
|
|
59
|
+
then run it with either the `.all({})`, `.get({})` or `.run({})` methods, as per
|
|
60
|
+
the native sqlite API.
|
|
61
|
+
|
|
62
|
+
| Method | Description |
|
|
63
|
+
|------------|-------------------------------------------------------|
|
|
64
|
+
| `.all({})` | Returns all rows that match the query. |
|
|
65
|
+
| `.get({})` | Returns the first row that matches the query. |
|
|
66
|
+
| `.run({})` | Executes the query and returns the (optional) result. |
|
|
67
|
+
|
|
68
|
+
### Synchronous/Asynchronous
|
|
69
|
+
|
|
70
|
+
The native sqlite module currently only supports synchronous operations. This
|
|
71
|
+
can pose a performance issue in some common cases. Sqlrite addresses this by
|
|
72
|
+
allowing one to run one's queries asynchronously by appending `.async`:
|
|
73
|
+
|
|
74
|
+
For example, instead of:
|
|
75
|
+
|
|
76
|
+
**Synchronous**
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
console.log(sql.getPositions.all());
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Asynchronous**
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
sql.async.getPositions.all().then((positions) => console.log(positions));
|
|
86
|
+
```
|
|
87
|
+
|
|
59
88
|
|
|
60
89
|
**Example SQL File**
|
|
61
90
|
|
|
@@ -83,6 +112,9 @@ END TRANSACTION;
|
|
|
83
112
|
INSERT INTO employees (name, position, salary)
|
|
84
113
|
VALUES ($name, $position, $salary);
|
|
85
114
|
|
|
115
|
+
-- PREP: getPositions
|
|
116
|
+
SELECT name, position FROM employees;
|
|
117
|
+
|
|
86
118
|
-- PREP: getHighestPaidEmployee
|
|
87
119
|
SELECT name FROM employees ORDER BY salary DESC LIMIT 1;
|
|
88
120
|
```
|
|
@@ -101,32 +133,53 @@ sql.addEmployee.run({ name: "Jill", position: "CIO", salary: 49996 });
|
|
|
101
133
|
|
|
102
134
|
const employee = sql.getHighestPaidEmployee.get();
|
|
103
135
|
|
|
136
|
+
assert(employee?.name === "John", "The highest paid employee should be John");
|
|
137
|
+
|
|
138
|
+
sql.async.getPositions.all().then((positions) => console.log(positions));
|
|
139
|
+
|
|
104
140
|
console.log(`The highest paid employee is ${employee.name}.`);
|
|
105
141
|
|
|
106
142
|
sql.deleteTable();
|
|
107
|
-
|
|
108
143
|
```
|
|
109
144
|
|
|
110
145
|
## Installation
|
|
111
146
|
|
|
112
|
-
Navigate to your project directory and run the following command:
|
|
147
|
+
1. Navigate to your project directory and run the following command:
|
|
113
148
|
|
|
114
149
|
```bash
|
|
115
150
|
npm install @possumtech/sqlrite
|
|
116
151
|
```
|
|
117
152
|
|
|
153
|
+
2. Then create a `sql` directory in your project directory. This is where you
|
|
154
|
+
will put your SQL files.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
mkdir sql
|
|
158
|
+
cd sql
|
|
159
|
+
touch exampleFile.sql
|
|
160
|
+
```
|
|
161
|
+
|
|
118
162
|
## Configuration
|
|
119
163
|
|
|
120
164
|
```js
|
|
121
|
-
import
|
|
165
|
+
import SqlRite from "@possumtech/sqlrite";
|
|
122
166
|
|
|
123
|
-
const sql = new
|
|
124
|
-
|
|
125
|
-
|
|
167
|
+
const sql = new SqlRite({
|
|
168
|
+
// SQLite database file path.
|
|
169
|
+
path: ":memory:",
|
|
126
170
|
|
|
127
|
-
|
|
128
|
-
|
|
171
|
+
// Path to your SQL directory.
|
|
172
|
+
dir: "sql/",
|
|
129
173
|
});
|
|
130
174
|
```
|
|
175
|
+
|
|
176
|
+
You will almost certainly wish to replace the `path` with a path to your
|
|
177
|
+
database file. Otherwise, the database will be created in memory and lost when
|
|
178
|
+
the process ends.
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
const sql = new SqlRite({ path: "path/to/your/database.sqlite3" });
|
|
182
|
+
```
|
|
183
|
+
|
|
131
184
|
Additional arguments will be passed to the options object of the native sqlite
|
|
132
185
|
module.
|
package/SqlRite.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Database, DatabaseSync, Statement } from 'node:sqlite';
|
|
2
|
+
|
|
3
|
+
interface SqlRiteOptions {
|
|
4
|
+
path?: string;
|
|
5
|
+
dir?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface SqlRiteAsyncPreparedStatements {
|
|
9
|
+
all: (params?: Record<string, any>) => Promise<any[]>;
|
|
10
|
+
get: (params?: Record<string, any>) => Promise<any>;
|
|
11
|
+
run: (params?: Record<string, any>) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SqlRiteAsyncMethods {
|
|
15
|
+
[key: string]: (() => Promise<void>) | SqlRiteAsyncPreparedStatements;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default class SqlRite {
|
|
19
|
+
constructor(options?: SqlRiteOptions);
|
|
20
|
+
async: SqlRiteAsyncMethods;
|
|
21
|
+
[key: string]: (() => void) | Statement | SqlRiteAsyncMethods | any;
|
|
22
|
+
}
|
package/SqlRite.js
CHANGED
|
@@ -16,22 +16,43 @@ export default class SqlRite {
|
|
|
16
16
|
const files = fs.readdirSync(dir);
|
|
17
17
|
const code = files.map((f) => fs.readFileSync(dir + f, "utf8")).join("");
|
|
18
18
|
|
|
19
|
+
this.async = {};
|
|
20
|
+
|
|
19
21
|
const chunks =
|
|
20
22
|
/-- (?<chunk>(?<type>INIT|EXEC|PREP): (?<name>\w+)\n(?<sql>.*?))($|(?=-- (INIT|EXEC|PREP):))/gs;
|
|
21
23
|
|
|
24
|
+
const initChunks = [];
|
|
25
|
+
const execChunks = [];
|
|
26
|
+
const prepChunks = [];
|
|
27
|
+
|
|
22
28
|
for (const chunk of code.matchAll(chunks)) {
|
|
23
29
|
const { type, name, sql } = chunk.groups;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
case "EXEC":
|
|
29
|
-
this[name] = () => db.exec(sql);
|
|
30
|
-
break;
|
|
31
|
-
case "PREP":
|
|
32
|
-
this[name] = db.prepare(sql);
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
30
|
+
|
|
31
|
+
if (type === "INIT") initChunks.push(chunk.groups);
|
|
32
|
+
if (type === "EXEC") execChunks.push(chunk.groups);
|
|
33
|
+
if (type === "PREP") prepChunks.push(chunk.groups);
|
|
35
34
|
}
|
|
35
|
+
|
|
36
|
+
initChunks.forEach((init) => db.exec(init.sql));
|
|
37
|
+
|
|
38
|
+
execChunks.forEach((exec) => {
|
|
39
|
+
this[exec.name] = () => db.exec(exec.sql);
|
|
40
|
+
this.async[exec.name] = async () => db.exec(exec.sql);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
prepChunks.forEach((prep) => {
|
|
44
|
+
this[prep.name] = db.prepare(prep.sql);
|
|
45
|
+
|
|
46
|
+
this.async[prep.name] = {};
|
|
47
|
+
|
|
48
|
+
this.async[prep.name].all = async (params = {}) =>
|
|
49
|
+
this[prep.name].all(params);
|
|
50
|
+
|
|
51
|
+
this.async[prep.name].get = async (params = {}) =>
|
|
52
|
+
this[prep.name].get(params);
|
|
53
|
+
|
|
54
|
+
this.async[prep.name].run = async (params = {}) =>
|
|
55
|
+
this[prep.name].run(params);
|
|
56
|
+
});
|
|
36
57
|
}
|
|
37
58
|
}
|
package/biome.json
CHANGED
package/package.json
CHANGED
package/sql/test.sql
CHANGED
|
@@ -21,5 +21,8 @@ END TRANSACTION;
|
|
|
21
21
|
INSERT INTO employees (name, position, salary)
|
|
22
22
|
VALUES ($name, $position, $salary);
|
|
23
23
|
|
|
24
|
+
-- PREP: getPositions
|
|
25
|
+
SELECT name, position FROM employees;
|
|
26
|
+
|
|
24
27
|
-- PREP: getHighestPaidEmployee
|
|
25
28
|
SELECT name FROM employees ORDER BY salary DESC LIMIT 1;
|
package/test/test.js
CHANGED
|
@@ -12,6 +12,8 @@ const employee = sql.getHighestPaidEmployee.get();
|
|
|
12
12
|
|
|
13
13
|
assert(employee?.name === "John", "The highest paid employee should be John");
|
|
14
14
|
|
|
15
|
+
sql.async.getPositions.all().then((positions) => console.log(positions));
|
|
16
|
+
|
|
15
17
|
console.log(`The highest paid employee is ${employee.name}.`);
|
|
16
18
|
|
|
17
19
|
sql.deleteTable();
|