sqyrl 0.0.2 → 0.1.1
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 +17 -3
- package/dist/index.d.mts +201 -39
- package/dist/index.mjs +5337 -1061
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -15,15 +15,17 @@ npm install sqyrl
|
|
|
15
15
|
```ts
|
|
16
16
|
import { sqyrl } from "sqyrl";
|
|
17
17
|
|
|
18
|
-
const sql = sqyrl(`SELECT id, name FROM
|
|
19
|
-
schema: "public",
|
|
18
|
+
const sql = sqyrl(`SELECT id, name FROM users WHERE status = 'active' LIMIT 10`, {
|
|
20
19
|
table: "users",
|
|
21
20
|
column: "tenant_id",
|
|
22
21
|
value: "acme",
|
|
23
22
|
});
|
|
24
23
|
|
|
25
24
|
console.log(sql);
|
|
26
|
-
// SELECT id, name
|
|
25
|
+
// SELECT id, name
|
|
26
|
+
// FROM public.users
|
|
27
|
+
// WHERE users.tenant_id = 'acme'
|
|
28
|
+
// AND status = 'active' LIMIT 10
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
`sqyrl` parses the SQL, enforces a mandatory equality filter on the given column as the outermost `AND` condition (so it cannot be short-circuited by agent-supplied `OR` clauses), and returns the sanitised SQL string.
|
|
@@ -35,12 +37,24 @@ console.log(sql);
|
|
|
35
37
|
|
|
36
38
|
## Development
|
|
37
39
|
|
|
40
|
+
First install [Vite+](https://viteplus.dev/guide/):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
curl -fsSL https://vite.plus | bash
|
|
44
|
+
```
|
|
45
|
+
|
|
38
46
|
Install dependencies:
|
|
39
47
|
|
|
40
48
|
```bash
|
|
41
49
|
vp install
|
|
42
50
|
```
|
|
43
51
|
|
|
52
|
+
Format, lint, typecheck:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
vp check --fix
|
|
56
|
+
```
|
|
57
|
+
|
|
44
58
|
Run the unit tests:
|
|
45
59
|
|
|
46
60
|
```bash
|
package/dist/index.d.mts
CHANGED
|
@@ -1,44 +1,217 @@
|
|
|
1
1
|
//#region src/ast.d.ts
|
|
2
2
|
interface SelectStatement {
|
|
3
|
-
type: "select";
|
|
3
|
+
readonly type: "select";
|
|
4
|
+
distinct: Distinct | null;
|
|
4
5
|
columns: Column[];
|
|
5
|
-
from:
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
from: SelectFrom;
|
|
7
|
+
joins: JoinClause[];
|
|
8
|
+
where: WhereRoot | null;
|
|
9
|
+
groupBy: GroupByClause | null;
|
|
10
|
+
having: HavingClause | null;
|
|
11
|
+
orderBy: OrderByClause | null;
|
|
12
|
+
limit: LimitClause | null;
|
|
13
|
+
offset: OffsetClause | null;
|
|
8
14
|
}
|
|
9
|
-
|
|
15
|
+
interface Distinct {
|
|
16
|
+
readonly type: "distinct";
|
|
17
|
+
}
|
|
18
|
+
interface GroupByClause {
|
|
19
|
+
readonly type: "group_by";
|
|
20
|
+
items: WhereValue[];
|
|
21
|
+
}
|
|
22
|
+
interface HavingClause {
|
|
23
|
+
readonly type: "having";
|
|
24
|
+
expr: WhereExpr;
|
|
25
|
+
}
|
|
26
|
+
interface OrderByClause {
|
|
27
|
+
readonly type: "order_by";
|
|
28
|
+
items: OrderByItem[];
|
|
29
|
+
}
|
|
30
|
+
type SortDirection = "asc" | "desc";
|
|
31
|
+
type NullsOrder = "nulls_first" | "nulls_last";
|
|
32
|
+
interface OrderByItem {
|
|
33
|
+
readonly type: "order_by_item";
|
|
34
|
+
expr: WhereValue;
|
|
35
|
+
direction?: SortDirection;
|
|
36
|
+
nulls?: NullsOrder;
|
|
37
|
+
}
|
|
38
|
+
interface OffsetClause {
|
|
39
|
+
readonly type: "offset";
|
|
40
|
+
value: number;
|
|
41
|
+
}
|
|
42
|
+
type JoinType = "inner" | "inner_outer" | "left" | "left_outer" | "right" | "right_outer" | "full" | "full_outer" | "cross" | "natural";
|
|
43
|
+
type JoinCondition = {
|
|
44
|
+
readonly type: "join_on";
|
|
45
|
+
expr: WhereExpr;
|
|
46
|
+
} | {
|
|
47
|
+
readonly type: "join_using";
|
|
48
|
+
columns: string[];
|
|
49
|
+
};
|
|
50
|
+
interface JoinClause {
|
|
51
|
+
readonly type: "join";
|
|
52
|
+
joinType: JoinType;
|
|
53
|
+
table: TableRef;
|
|
54
|
+
condition: JoinCondition | null;
|
|
55
|
+
}
|
|
56
|
+
type SelectFrom = {
|
|
57
|
+
readonly type: "select_from";
|
|
58
|
+
table: TableRef;
|
|
59
|
+
};
|
|
60
|
+
type LimitClause = {
|
|
61
|
+
readonly type: "limit";
|
|
62
|
+
value: number;
|
|
63
|
+
};
|
|
64
|
+
type WhereRoot = {
|
|
65
|
+
readonly type: "where_root";
|
|
66
|
+
inner: WhereExpr;
|
|
67
|
+
};
|
|
68
|
+
type WhereExpr = WhereAnd | WhereOr | WhereNot | WhereComparison | WhereIsNull | WhereIsBool | WhereBetween | WhereIn | WhereLike;
|
|
10
69
|
interface WhereAnd {
|
|
11
|
-
type: "
|
|
70
|
+
readonly type: "where_and";
|
|
12
71
|
left: WhereExpr;
|
|
13
72
|
right: WhereExpr;
|
|
14
73
|
}
|
|
15
74
|
interface WhereOr {
|
|
16
|
-
type: "
|
|
75
|
+
readonly type: "where_or";
|
|
17
76
|
left: WhereExpr;
|
|
18
77
|
right: WhereExpr;
|
|
19
78
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
79
|
+
type ComparisonOperator = "=" | "<>" | "!=" | "<" | ">" | "<=" | ">=";
|
|
80
|
+
interface WhereNot {
|
|
81
|
+
readonly type: "where_not";
|
|
82
|
+
expr: WhereExpr;
|
|
83
|
+
}
|
|
84
|
+
interface WhereIsNull {
|
|
85
|
+
readonly type: "where_is_null";
|
|
86
|
+
not: boolean;
|
|
87
|
+
expr: WhereValue;
|
|
88
|
+
}
|
|
89
|
+
type IsBoolTarget = boolean | "unknown";
|
|
90
|
+
interface WhereIsBool {
|
|
91
|
+
readonly type: "where_is_bool";
|
|
92
|
+
not: boolean;
|
|
93
|
+
expr: WhereValue;
|
|
94
|
+
target: IsBoolTarget;
|
|
95
|
+
}
|
|
96
|
+
interface WhereBetween {
|
|
97
|
+
readonly type: "where_between";
|
|
98
|
+
not: boolean;
|
|
99
|
+
expr: WhereValue;
|
|
100
|
+
low: WhereValue;
|
|
101
|
+
high: WhereValue;
|
|
102
|
+
}
|
|
103
|
+
interface WhereIn {
|
|
104
|
+
readonly type: "where_in";
|
|
105
|
+
not: boolean;
|
|
106
|
+
expr: WhereValue;
|
|
107
|
+
list: WhereValue[];
|
|
108
|
+
}
|
|
109
|
+
type LikeOp = "like";
|
|
110
|
+
interface WhereLike {
|
|
111
|
+
readonly type: "where_like";
|
|
112
|
+
not: boolean;
|
|
113
|
+
op: LikeOp;
|
|
114
|
+
expr: WhereValue;
|
|
115
|
+
pattern: WhereValue;
|
|
116
|
+
}
|
|
117
|
+
type ArithOp = "+" | "-" | "*" | "/" | "%" | "||";
|
|
118
|
+
interface WhereArith {
|
|
119
|
+
readonly type: "where_arith";
|
|
120
|
+
op: ArithOp;
|
|
121
|
+
left: WhereValue;
|
|
122
|
+
right: WhereValue;
|
|
123
|
+
}
|
|
124
|
+
interface WhereUnaryMinus {
|
|
125
|
+
readonly type: "where_unary_minus";
|
|
126
|
+
expr: WhereValue;
|
|
127
|
+
}
|
|
128
|
+
interface CaseWhen {
|
|
129
|
+
condition: WhereValue;
|
|
130
|
+
result: WhereValue;
|
|
131
|
+
}
|
|
132
|
+
interface CaseExpr {
|
|
133
|
+
readonly type: "case_expr";
|
|
134
|
+
subject: WhereValue | null;
|
|
135
|
+
whens: CaseWhen[];
|
|
136
|
+
else: WhereValue | null;
|
|
137
|
+
}
|
|
138
|
+
interface CastExpr {
|
|
139
|
+
readonly type: "cast_expr";
|
|
140
|
+
expr: WhereValue;
|
|
141
|
+
typeName: string;
|
|
142
|
+
}
|
|
143
|
+
type WhereValue = {
|
|
144
|
+
readonly type: "where_value";
|
|
145
|
+
kind: "string";
|
|
24
146
|
value: string;
|
|
147
|
+
} | {
|
|
148
|
+
readonly type: "where_value";
|
|
149
|
+
kind: "integer";
|
|
150
|
+
value: number;
|
|
151
|
+
} | {
|
|
152
|
+
readonly type: "where_value";
|
|
153
|
+
kind: "float";
|
|
154
|
+
value: number;
|
|
155
|
+
} | {
|
|
156
|
+
readonly type: "where_value";
|
|
157
|
+
kind: "bool";
|
|
158
|
+
value: boolean;
|
|
159
|
+
} | {
|
|
160
|
+
readonly type: "where_value";
|
|
161
|
+
kind: "null";
|
|
162
|
+
} | {
|
|
163
|
+
readonly type: "where_value";
|
|
164
|
+
kind: "column_ref";
|
|
165
|
+
ref: ColumnRef;
|
|
166
|
+
} | {
|
|
167
|
+
readonly type: "where_value";
|
|
168
|
+
kind: "func_call";
|
|
169
|
+
func: FuncCall;
|
|
170
|
+
} | WhereArith | WhereUnaryMinus | CaseExpr | CastExpr;
|
|
171
|
+
interface WhereComparison {
|
|
172
|
+
readonly type: "where_comparison";
|
|
173
|
+
operator: ComparisonOperator;
|
|
174
|
+
left: WhereValue;
|
|
175
|
+
right: WhereValue;
|
|
25
176
|
}
|
|
26
|
-
interface
|
|
27
|
-
type: "column_ref";
|
|
177
|
+
interface ColumnRef {
|
|
178
|
+
readonly type: "column_ref";
|
|
179
|
+
schema?: string;
|
|
28
180
|
table?: string;
|
|
29
181
|
name: string;
|
|
30
182
|
}
|
|
31
|
-
|
|
32
|
-
|
|
183
|
+
type FuncCallArg = {
|
|
184
|
+
kind: "wildcard";
|
|
185
|
+
} | {
|
|
186
|
+
kind: "args";
|
|
187
|
+
distinct: boolean;
|
|
188
|
+
args: WhereValue[];
|
|
189
|
+
};
|
|
190
|
+
interface FuncCall {
|
|
191
|
+
readonly type: "func_call";
|
|
192
|
+
name: string;
|
|
193
|
+
args: FuncCallArg;
|
|
194
|
+
}
|
|
195
|
+
interface ColumnExpr {
|
|
196
|
+
readonly type: "column_expr";
|
|
197
|
+
kind: "wildcard" | "qualified_wildcard" | "expr";
|
|
33
198
|
table?: string;
|
|
34
|
-
|
|
35
|
-
|
|
199
|
+
expr?: WhereValue;
|
|
200
|
+
}
|
|
201
|
+
interface Column {
|
|
202
|
+
readonly type: "column";
|
|
203
|
+
expr: ColumnExpr;
|
|
204
|
+
alias?: Alias;
|
|
205
|
+
}
|
|
206
|
+
interface Alias {
|
|
207
|
+
readonly type: "alias";
|
|
208
|
+
name: string;
|
|
36
209
|
}
|
|
37
210
|
interface TableRef {
|
|
38
|
-
type: "
|
|
211
|
+
readonly type: "table_ref";
|
|
39
212
|
schema?: string;
|
|
40
213
|
name: string;
|
|
41
|
-
alias?:
|
|
214
|
+
alias?: Alias;
|
|
42
215
|
}
|
|
43
216
|
//#endregion
|
|
44
217
|
//#region src/output.d.ts
|
|
@@ -48,31 +221,20 @@ declare function outputSql(ast: SelectStatement): string;
|
|
|
48
221
|
declare function parseSql(expr: string): SelectStatement;
|
|
49
222
|
//#endregion
|
|
50
223
|
//#region src/sanitise.d.ts
|
|
51
|
-
|
|
52
|
-
|
|
224
|
+
interface WhereGuard {
|
|
225
|
+
schema?: string;
|
|
226
|
+
table: string;
|
|
227
|
+
col: string;
|
|
228
|
+
value: string | number;
|
|
229
|
+
}
|
|
230
|
+
declare function sanitiseSql(ast: SelectStatement, {
|
|
53
231
|
schema,
|
|
54
232
|
table,
|
|
55
233
|
col,
|
|
56
234
|
value
|
|
57
|
-
}:
|
|
58
|
-
ast: SelectStatement;
|
|
59
|
-
schema: string;
|
|
60
|
-
table: string;
|
|
61
|
-
col: string;
|
|
62
|
-
value: string;
|
|
63
|
-
}): SelectStatement;
|
|
235
|
+
}: WhereGuard): SelectStatement;
|
|
64
236
|
//#endregion
|
|
65
237
|
//#region src/index.d.ts
|
|
66
|
-
declare function sqyrl(expr: string,
|
|
67
|
-
schema,
|
|
68
|
-
table,
|
|
69
|
-
column,
|
|
70
|
-
value
|
|
71
|
-
}: {
|
|
72
|
-
schema: string;
|
|
73
|
-
table: string;
|
|
74
|
-
column: string;
|
|
75
|
-
value: string;
|
|
76
|
-
}): string;
|
|
238
|
+
declare function sqyrl(expr: string, whereGuard: WhereGuard): string;
|
|
77
239
|
//#endregion
|
|
78
240
|
export { outputSql, parseSql, sanitiseSql, sqyrl };
|