@gblikas/querykit 0.4.0 → 0.5.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 +192 -0
- package/dist/parser/types.d.ts +17 -1
- package/dist/security/validator.js +14 -5
- package/dist/translators/drizzle/index.js +11 -0
- package/dist/virtual-fields/helpers.d.ts +32 -0
- package/dist/virtual-fields/helpers.js +74 -0
- package/dist/virtual-fields/index.d.ts +1 -0
- package/dist/virtual-fields/index.js +1 -0
- package/dist/virtual-fields/resolver.js +4 -0
- package/dist/virtual-fields/types.d.ts +20 -3
- package/package.json +1 -1
- package/src/parser/types.ts +21 -1
- package/src/security/validator.ts +15 -5
- package/src/translators/drizzle/index.ts +18 -0
- package/src/virtual-fields/helpers.ts +81 -0
- package/src/virtual-fields/index.ts +1 -0
- package/src/virtual-fields/raw-sql.test.ts +978 -0
- package/src/virtual-fields/resolver.ts +5 -0
- package/src/virtual-fields/types.ts +22 -2
- package/src/virtual-fields/user-example-integration.test.ts +182 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper utilities for creating raw SQL expressions in virtual fields
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { sql } from 'drizzle-orm';
|
|
6
|
+
import { IRawSqlExpression } from '../parser/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validates field name to prevent SQL injection.
|
|
10
|
+
* Only allows alphanumeric characters, dots, and underscores.
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
function validateFieldName(field: string): void {
|
|
14
|
+
if (!/^[a-zA-Z][a-zA-Z0-9._]*$/.test(field)) {
|
|
15
|
+
throw new Error(`Invalid field name: ${field}`);
|
|
16
|
+
}
|
|
17
|
+
if (field.length > 64) {
|
|
18
|
+
throw new Error(`Field name too long: ${field}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a JSONB array contains expression (PostgreSQL).
|
|
24
|
+
* Checks if the JSONB array field contains the given value.
|
|
25
|
+
*
|
|
26
|
+
* @param field - The JSONB field name (e.g., 'assigned_to')
|
|
27
|
+
* @param value - The value to check for in the array
|
|
28
|
+
* @returns A raw SQL expression for JSONB contains check
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Check if assignedTo contains the current user ID
|
|
32
|
+
* jsonbContains('assigned_to', ctx.currentUserId)
|
|
33
|
+
* // Generates: assigned_to @> '["user123"]'::jsonb
|
|
34
|
+
*/
|
|
35
|
+
export function jsonbContains(
|
|
36
|
+
field: string,
|
|
37
|
+
value: unknown
|
|
38
|
+
): IRawSqlExpression {
|
|
39
|
+
validateFieldName(field);
|
|
40
|
+
return {
|
|
41
|
+
type: 'raw',
|
|
42
|
+
toSql: () =>
|
|
43
|
+
sql`${sql.identifier(field)} @> ${sql.raw("'" + JSON.stringify(Array.isArray(value) ? value : [value]).replace(/'/g, "''") + "'::jsonb")}`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validates days parameter to ensure it's a positive finite number.
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
function validateDaysParameter(days: number): void {
|
|
52
|
+
if (!Number.isFinite(days)) {
|
|
53
|
+
throw new Error(`Invalid days parameter: ${days}. Must be a finite number.`);
|
|
54
|
+
}
|
|
55
|
+
if (days <= 0) {
|
|
56
|
+
throw new Error(`Invalid days parameter: ${days}. Must be a positive number.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a date range expression.
|
|
62
|
+
* Checks if a timestamp field is within the specified number of days from now.
|
|
63
|
+
*
|
|
64
|
+
* @param field - The timestamp field name (e.g., 'created_at')
|
|
65
|
+
* @param days - Number of days from now (must be a positive finite number)
|
|
66
|
+
* @returns A raw SQL expression for date range check
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // Check if created within last day
|
|
70
|
+
* dateWithinDays('created_at', 1)
|
|
71
|
+
* // Generates: created_at >= NOW() - INTERVAL '1 days'
|
|
72
|
+
*/
|
|
73
|
+
export function dateWithinDays(field: string, days: number): IRawSqlExpression {
|
|
74
|
+
validateFieldName(field);
|
|
75
|
+
validateDaysParameter(days);
|
|
76
|
+
return {
|
|
77
|
+
type: 'raw',
|
|
78
|
+
toSql: () =>
|
|
79
|
+
sql`${sql.identifier(field)} >= NOW() - INTERVAL '${sql.raw(days.toString())} days'`
|
|
80
|
+
};
|
|
81
|
+
}
|