@rwillians/qx 0.1.2 → 0.1.4
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/dist/cjs/bun-sqlite.js +483 -0
- package/dist/cjs/index.js +666 -0
- package/dist/cjs/pretty-logger.js +14 -0
- package/dist/cjs/standard-schema.js +236 -0
- package/dist/cjs/utils.js +76 -0
- package/dist/esm/bun-sqlite.js +483 -0
- package/dist/esm/index.js +660 -0
- package/dist/esm/pretty-logger.js +11 -0
- package/dist/esm/standard-schema.js +233 -0
- package/dist/esm/utils.js +65 -0
- package/dist/types/bun-sqlite.d.ts +47 -0
- package/dist/types/index.d.ts +1174 -0
- package/dist/types/pretty-logger.d.ts +7 -0
- package/dist/types/standard-schema.d.ts +157 -0
- package/dist/types/utils.d.ts +50 -0
- package/package.json +4 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import * as std from '@standard-schema/spec';
|
|
2
|
+
// // // // // // // // // // // // // // // // // // // // // // // //
|
|
3
|
+
// STANDARD SCHEMA API //
|
|
4
|
+
// // // // // // // // // // // // // // // // // // // // // // // //
|
|
5
|
+
/**
|
|
6
|
+
* @public The Standard Schema interface.
|
|
7
|
+
* @since 0.1.0
|
|
8
|
+
* @version 1
|
|
9
|
+
*/
|
|
10
|
+
export {} from '@standard-schema/spec';
|
|
11
|
+
/**
|
|
12
|
+
* @public Use any standard schema to parse a value.
|
|
13
|
+
* @since 0.1.0
|
|
14
|
+
* @version 1
|
|
15
|
+
*/
|
|
16
|
+
export const parse = (schema, value) => {
|
|
17
|
+
const parsed = schema['~standard'].validate(value);
|
|
18
|
+
if (parsed instanceof Promise) {
|
|
19
|
+
throw new Error('async standard schema validators are not supported');
|
|
20
|
+
}
|
|
21
|
+
return parsed;
|
|
22
|
+
};
|
|
23
|
+
// // // // // // // // // // // // // // // // // // // // // // // //
|
|
24
|
+
// UTILS //
|
|
25
|
+
// // // // // // // // // // // // // // // // // // // // // // // //
|
|
26
|
+
const prependPath = (path) => (issue) => ({
|
|
27
|
+
...issue,
|
|
28
|
+
path: [path, ...(issue.path ?? [])],
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* @public Defines an array of a given standard schema.
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
* @version 1
|
|
34
|
+
*/
|
|
35
|
+
export const array = (schema) => ({
|
|
36
|
+
'~standard': {
|
|
37
|
+
version: 1,
|
|
38
|
+
vendor: 'qx',
|
|
39
|
+
validate: (input) => {
|
|
40
|
+
if (!Array.isArray(input)) {
|
|
41
|
+
return { issues: [{ message: 'must be an array' }] };
|
|
42
|
+
}
|
|
43
|
+
const issues = [];
|
|
44
|
+
const value = [];
|
|
45
|
+
for (let i = 0; i < input.length; i++) {
|
|
46
|
+
const parsed = parse(schema, input[i]);
|
|
47
|
+
parsed.issues
|
|
48
|
+
? issues.push(...parsed.issues.map(prependPath(i)))
|
|
49
|
+
: value.push(parsed.value);
|
|
50
|
+
}
|
|
51
|
+
return issues.length > 0
|
|
52
|
+
? { issues }
|
|
53
|
+
: { value: value };
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* @public Defines a standard schema for boolean values.
|
|
59
|
+
* @since 0.1.0
|
|
60
|
+
* @version 1
|
|
61
|
+
*/
|
|
62
|
+
export const boolean = () => ({
|
|
63
|
+
'~standard': {
|
|
64
|
+
version: 1,
|
|
65
|
+
vendor: 'qx',
|
|
66
|
+
validate: (input) => typeof input !== 'boolean'
|
|
67
|
+
? { issues: [{ message: 'must be a boolean' }] }
|
|
68
|
+
: { value: input },
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* @public Defines a standard schema for Date values that can be
|
|
73
|
+
* coerced from ISO 8601 strings or epoch timestamps in
|
|
74
|
+
* milliseconds.
|
|
75
|
+
* @since 0.1.0
|
|
76
|
+
* @version 1
|
|
77
|
+
*/
|
|
78
|
+
export const date = () => ({
|
|
79
|
+
'~standard': {
|
|
80
|
+
version: 1,
|
|
81
|
+
vendor: 'qx',
|
|
82
|
+
validate: (input) => {
|
|
83
|
+
if (input instanceof Date)
|
|
84
|
+
return isNaN(input.getTime())
|
|
85
|
+
? { issues: [{ message: 'must be a valid date' }] }
|
|
86
|
+
: { value: input };
|
|
87
|
+
if (typeof input !== 'string' &&
|
|
88
|
+
typeof input !== 'number')
|
|
89
|
+
return { issues: [{ message: 'must be a valid ISO 8601 string or epoch timestamp in milliseconds' }] };
|
|
90
|
+
const date = new Date(input);
|
|
91
|
+
if (isNaN(date.getTime()))
|
|
92
|
+
return { issues: [{ message: 'must be a valid ISO 8601 string or epoch timestamp in milliseconds' }] };
|
|
93
|
+
return { value: date };
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* @public Defines a standard schema that validates instances of a
|
|
99
|
+
* given class.
|
|
100
|
+
* @since 0.1.0
|
|
101
|
+
* @version 1
|
|
102
|
+
*/
|
|
103
|
+
export const instanceOf = (ctor) => ({
|
|
104
|
+
'~standard': {
|
|
105
|
+
version: 1,
|
|
106
|
+
vendor: 'qx',
|
|
107
|
+
validate: (input) => !(input instanceof ctor)
|
|
108
|
+
? { issues: [{ message: `must be an instance of ${ctor.name}` }] }
|
|
109
|
+
: { value: input },
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
/**
|
|
113
|
+
* @public Defines a standard schema for integers with optional min and max constraints.
|
|
114
|
+
* @since 0.1.0
|
|
115
|
+
* @version 1
|
|
116
|
+
*/
|
|
117
|
+
export const integer = ({ min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER } = {}) => ({
|
|
118
|
+
'~standard': {
|
|
119
|
+
version: 1,
|
|
120
|
+
vendor: 'qx',
|
|
121
|
+
validate: (input) => {
|
|
122
|
+
if (typeof input !== 'number')
|
|
123
|
+
return { issues: [{ message: 'must be a integer' }] };
|
|
124
|
+
if (Number.isNaN(input) || !Number.isFinite(input))
|
|
125
|
+
return { issues: [{ message: 'must be a integer' }] };
|
|
126
|
+
if (!Number.isInteger(input))
|
|
127
|
+
return { issues: [{ message: 'must be a integer' }] };
|
|
128
|
+
if (input < min)
|
|
129
|
+
return { issues: [{ message: `must be greater than or equal to ${min}` }] };
|
|
130
|
+
if (input > max)
|
|
131
|
+
return { issues: [{ message: `must be less than or equal to ${max}` }] };
|
|
132
|
+
return { value: input };
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* @public Makes any standard schema accepts `null` as a valid value.
|
|
138
|
+
* @since 0.1.0
|
|
139
|
+
* @version 1
|
|
140
|
+
*/
|
|
141
|
+
export const nullable = (schema) => ({
|
|
142
|
+
'~standard': {
|
|
143
|
+
version: 1,
|
|
144
|
+
vendor: 'qx',
|
|
145
|
+
validate: (value) => value === null
|
|
146
|
+
? { value }
|
|
147
|
+
: parse(schema, value),
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* @public Defines a standard schema for numbers with optional min
|
|
152
|
+
* and max constraints.
|
|
153
|
+
* @since 0.1.0
|
|
154
|
+
* @version 1
|
|
155
|
+
*/
|
|
156
|
+
export const number = ({ min = Number.MIN_VALUE, max = Number.MAX_VALUE } = {}) => ({
|
|
157
|
+
'~standard': {
|
|
158
|
+
version: 1,
|
|
159
|
+
vendor: 'qx',
|
|
160
|
+
validate: (input) => {
|
|
161
|
+
if (typeof input !== 'number')
|
|
162
|
+
return { issues: [{ message: 'must be a number' }] };
|
|
163
|
+
if (Number.isNaN(input) || !Number.isFinite(input))
|
|
164
|
+
return { issues: [{ message: 'must be a number' }] };
|
|
165
|
+
if (input < min)
|
|
166
|
+
return { issues: [{ message: `must be greater than or equal to ${min}` }] };
|
|
167
|
+
if (input > max)
|
|
168
|
+
return { issues: [{ message: `must be less than or equal to ${max}` }] };
|
|
169
|
+
return { value: input };
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
/**
|
|
174
|
+
* @public Defines an object schema that does not allow extra fields.
|
|
175
|
+
* @since 0.1.0
|
|
176
|
+
* @version 1
|
|
177
|
+
*/
|
|
178
|
+
export const strictObject = (shape) => ({
|
|
179
|
+
'~standard': {
|
|
180
|
+
version: 1,
|
|
181
|
+
vendor: 'qx',
|
|
182
|
+
validate: (input) => {
|
|
183
|
+
if (typeof input !== 'object' || input === null) {
|
|
184
|
+
return { issues: [{ message: 'must be an object' }] };
|
|
185
|
+
}
|
|
186
|
+
const issues = [];
|
|
187
|
+
const inputKeys = new Set(Object.keys(input));
|
|
188
|
+
const shapeKeys = new Set(Object.keys(shape));
|
|
189
|
+
// one issue for each key of `input` that doesn't exist in `shape`
|
|
190
|
+
for (const key of inputKeys.difference(shapeKeys)) {
|
|
191
|
+
issues.push({ path: [key], message: 'unknown field' });
|
|
192
|
+
}
|
|
193
|
+
// one issue for each key of `shape` that doesn't exist in `input`
|
|
194
|
+
for (const key of shapeKeys.difference(inputKeys)) {
|
|
195
|
+
issues.push({ path: [key], message: 'is required' });
|
|
196
|
+
}
|
|
197
|
+
const record = {};
|
|
198
|
+
for (const [key, value] of Object.entries(input)) {
|
|
199
|
+
const parsed = shape[key]['~standard'].validate(value);
|
|
200
|
+
if (parsed instanceof Promise) {
|
|
201
|
+
throw new Error('async validators are not supported');
|
|
202
|
+
}
|
|
203
|
+
parsed.issues
|
|
204
|
+
? issues.push(...parsed.issues.map(prependPath(key)))
|
|
205
|
+
: record[key] = parsed.value;
|
|
206
|
+
}
|
|
207
|
+
return issues.length > 0
|
|
208
|
+
? { issues }
|
|
209
|
+
: { value: record };
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
/**
|
|
214
|
+
* @public Defines a standard schema for strings with optional min
|
|
215
|
+
* and max length constraints.
|
|
216
|
+
* @since 0.1.0
|
|
217
|
+
* @version 1
|
|
218
|
+
*/
|
|
219
|
+
export const string = ({ min, max } = {}) => ({
|
|
220
|
+
'~standard': {
|
|
221
|
+
version: 1,
|
|
222
|
+
vendor: 'qx',
|
|
223
|
+
validate: (input) => {
|
|
224
|
+
if (typeof input !== 'string')
|
|
225
|
+
return { issues: [{ message: 'must be a string' }] };
|
|
226
|
+
if (min !== undefined && input.length < min)
|
|
227
|
+
return { issues: [{ message: `must be at least ${min} characters long` }] };
|
|
228
|
+
if (max !== undefined && input.length > max)
|
|
229
|
+
return { issues: [{ message: `must be at most ${max} characters long` }] };
|
|
230
|
+
return { value: input };
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @private Converts a snake_case string to camelCase.
|
|
3
|
+
* @since 0.1.0
|
|
4
|
+
* @version 1
|
|
5
|
+
*/
|
|
6
|
+
export const camelCase = (str) => str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
7
|
+
/**
|
|
8
|
+
* @private Simplified check for plain objects.
|
|
9
|
+
* @since 0.1.0
|
|
10
|
+
* @version 1
|
|
11
|
+
*/
|
|
12
|
+
export const isPlainObject = (value) => {
|
|
13
|
+
if (typeof value !== 'object' || value === null)
|
|
14
|
+
return false;
|
|
15
|
+
let proto = Object.getPrototypeOf(value);
|
|
16
|
+
if (proto === null)
|
|
17
|
+
return true;
|
|
18
|
+
return proto === Object.prototype;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* @private Throws an error if the given number is greater than the
|
|
22
|
+
* specified maximum.
|
|
23
|
+
* @since 0.1.0
|
|
24
|
+
* @version 1
|
|
25
|
+
*/
|
|
26
|
+
export const lte = (n, max) => {
|
|
27
|
+
if (n > max)
|
|
28
|
+
throw new Error(`Must be at most ${max}, got ${n}`);
|
|
29
|
+
return n;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* @public Maps over the keys of an object.
|
|
33
|
+
* @since 0.1.0
|
|
34
|
+
* @version 1
|
|
35
|
+
*/
|
|
36
|
+
export const mapKeys = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [fn(key), value]));
|
|
37
|
+
/**
|
|
38
|
+
* @private Maps over the values of an object.
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @version 1
|
|
41
|
+
*/
|
|
42
|
+
export const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value, key)]));
|
|
43
|
+
/**
|
|
44
|
+
* @private Resolves the given value or function to a value.
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
* @version 1
|
|
47
|
+
*/
|
|
48
|
+
export const resolve = (value) => typeof value === 'function'
|
|
49
|
+
? value()
|
|
50
|
+
: value;
|
|
51
|
+
/**
|
|
52
|
+
* @private Converts a camelCase string to snake_case.
|
|
53
|
+
* @since 0.1.0
|
|
54
|
+
* @version 1
|
|
55
|
+
*/
|
|
56
|
+
export const snakeCase = (str) => str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
57
|
+
/**
|
|
58
|
+
* @public Wraps the given value in an array, unless it's already an
|
|
59
|
+
* array.
|
|
60
|
+
* @since 0.1.0
|
|
61
|
+
* @version 1
|
|
62
|
+
*/
|
|
63
|
+
export const wrap = (value) => Array.isArray(value)
|
|
64
|
+
? value
|
|
65
|
+
: [value];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { type CreateTableStatement, type IDatabase, type ILogger, type InsertStatement, type SelectStatement } from './index';
|
|
3
|
+
/**
|
|
4
|
+
* @private Bun SQLite database adapter implementation.
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
* @version 1
|
|
7
|
+
*/
|
|
8
|
+
declare class BunSQLite implements IDatabase {
|
|
9
|
+
private conn;
|
|
10
|
+
private loggers;
|
|
11
|
+
constructor(conn: Database, loggers?: ILogger[]);
|
|
12
|
+
/**
|
|
13
|
+
* @public Attaches a logger to the database instance.
|
|
14
|
+
* @since 0.1.0
|
|
15
|
+
* @version 1
|
|
16
|
+
*/
|
|
17
|
+
attachLogger(logger: ILogger): this;
|
|
18
|
+
/**
|
|
19
|
+
* @public Executes a create table statement.
|
|
20
|
+
* @since 0.1.0
|
|
21
|
+
* @version 1
|
|
22
|
+
*/
|
|
23
|
+
createTable(op: CreateTableStatement): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* @public Executes an insert statement.
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
* @version 1
|
|
28
|
+
*/
|
|
29
|
+
insert(op: InsertStatement): Promise<{
|
|
30
|
+
[k: string]: any;
|
|
31
|
+
}[]>;
|
|
32
|
+
/**
|
|
33
|
+
* @public Executes a select statement.
|
|
34
|
+
* @since 0.1.0
|
|
35
|
+
* @version 1
|
|
36
|
+
*/
|
|
37
|
+
query(op: SelectStatement): Promise<{
|
|
38
|
+
[k: string]: any;
|
|
39
|
+
}[]>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* @public Creates a connection to the database.
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
* @version 1
|
|
45
|
+
*/
|
|
46
|
+
declare const connect: (...args: ConstructorParameters<typeof Database>) => BunSQLite;
|
|
47
|
+
export { connect, };
|