@gblikas/querykit 0.0.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.
Files changed (118) hide show
  1. package/.cursor/BUGBOT.md +21 -0
  2. package/.cursor/rules/01-project-structure.mdc +77 -0
  3. package/.cursor/rules/02-typescript-standards.mdc +105 -0
  4. package/.cursor/rules/03-testing-standards.mdc +78 -0
  5. package/.cursor/rules/04-query-language.mdc +79 -0
  6. package/.cursor/rules/05-solid-principles.mdc +118 -0
  7. package/.cursor/rules/liqe-readme-docs.mdc +438 -0
  8. package/.devcontainer/devcontainer.json +25 -0
  9. package/.eslintignore +1 -0
  10. package/.eslintrc.js +39 -0
  11. package/.github/dependabot.yml +12 -0
  12. package/.github/workflows/ci.yml +114 -0
  13. package/.github/workflows/publish.yml +61 -0
  14. package/.husky/pre-commit +30 -0
  15. package/.prettierrc +10 -0
  16. package/CONTRIBUTING.md +187 -0
  17. package/LICENSE +674 -0
  18. package/README.md +237 -0
  19. package/dist/adapters/drizzle/index.d.ts +122 -0
  20. package/dist/adapters/drizzle/index.js +166 -0
  21. package/dist/adapters/index.d.ts +7 -0
  22. package/dist/adapters/index.js +25 -0
  23. package/dist/adapters/types.d.ts +60 -0
  24. package/dist/adapters/types.js +8 -0
  25. package/dist/index.d.ts +75 -0
  26. package/dist/index.js +118 -0
  27. package/dist/parser/index.d.ts +2 -0
  28. package/dist/parser/index.js +18 -0
  29. package/dist/parser/parser.d.ts +51 -0
  30. package/dist/parser/parser.js +201 -0
  31. package/dist/parser/types.d.ts +68 -0
  32. package/dist/parser/types.js +5 -0
  33. package/dist/query/builder.d.ts +61 -0
  34. package/dist/query/builder.js +188 -0
  35. package/dist/query/index.d.ts +2 -0
  36. package/dist/query/index.js +18 -0
  37. package/dist/query/types.d.ts +79 -0
  38. package/dist/query/types.js +2 -0
  39. package/dist/security/index.d.ts +2 -0
  40. package/dist/security/index.js +18 -0
  41. package/dist/security/types.d.ts +181 -0
  42. package/dist/security/types.js +43 -0
  43. package/dist/security/validator.d.ts +191 -0
  44. package/dist/security/validator.js +344 -0
  45. package/dist/translators/drizzle/index.d.ts +73 -0
  46. package/dist/translators/drizzle/index.js +260 -0
  47. package/dist/translators/index.d.ts +8 -0
  48. package/dist/translators/index.js +27 -0
  49. package/dist/translators/sql/index.d.ts +108 -0
  50. package/dist/translators/sql/index.js +252 -0
  51. package/dist/translators/types.d.ts +39 -0
  52. package/dist/translators/types.js +8 -0
  53. package/examples/qk-next/README.md +35 -0
  54. package/examples/qk-next/app/favicon.ico +0 -0
  55. package/examples/qk-next/app/globals.css +122 -0
  56. package/examples/qk-next/app/layout.tsx +121 -0
  57. package/examples/qk-next/app/page.tsx +813 -0
  58. package/examples/qk-next/app/providers.tsx +80 -0
  59. package/examples/qk-next/components/aurora-background.tsx +12 -0
  60. package/examples/qk-next/components/github-stars.tsx +51 -0
  61. package/examples/qk-next/components/mode-toggle.tsx +27 -0
  62. package/examples/qk-next/components/reactbits/blocks/Backgrounds/Aurora/Aurora.tsx +217 -0
  63. package/examples/qk-next/components/reactbits/blocks/Backgrounds/LightRays/LightRays.tsx +474 -0
  64. package/examples/qk-next/components/theme-provider.tsx +11 -0
  65. package/examples/qk-next/components/ui/card.tsx +92 -0
  66. package/examples/qk-next/components/ui/command.tsx +184 -0
  67. package/examples/qk-next/components/ui/dialog.tsx +143 -0
  68. package/examples/qk-next/components/ui/drawer.tsx +135 -0
  69. package/examples/qk-next/components/ui/hover-card.tsx +44 -0
  70. package/examples/qk-next/components/ui/icons.tsx +148 -0
  71. package/examples/qk-next/components/ui/sonner.tsx +26 -0
  72. package/examples/qk-next/components/ui/table.tsx +117 -0
  73. package/examples/qk-next/components.json +21 -0
  74. package/examples/qk-next/eslint.config.mjs +21 -0
  75. package/examples/qk-next/jsrepo.json +13 -0
  76. package/examples/qk-next/lib/utils.ts +6 -0
  77. package/examples/qk-next/next.config.ts +8 -0
  78. package/examples/qk-next/package.json +48 -0
  79. package/examples/qk-next/pnpm-lock.yaml +5558 -0
  80. package/examples/qk-next/postcss.config.mjs +5 -0
  81. package/examples/qk-next/public/file.svg +1 -0
  82. package/examples/qk-next/public/globe.svg +1 -0
  83. package/examples/qk-next/public/next.svg +1 -0
  84. package/examples/qk-next/public/vercel.svg +1 -0
  85. package/examples/qk-next/public/window.svg +1 -0
  86. package/examples/qk-next/tsconfig.json +42 -0
  87. package/examples/qk-next/types/sonner.d.ts +3 -0
  88. package/jest.config.js +26 -0
  89. package/package.json +51 -0
  90. package/src/adapters/drizzle/drizzle-adapter.test.ts +115 -0
  91. package/src/adapters/drizzle/index.ts +299 -0
  92. package/src/adapters/index.ts +11 -0
  93. package/src/adapters/types.ts +72 -0
  94. package/src/index.ts +194 -0
  95. package/src/integration.test.ts +202 -0
  96. package/src/parser/index.ts +2 -0
  97. package/src/parser/parser.test.ts +1056 -0
  98. package/src/parser/parser.ts +268 -0
  99. package/src/parser/types.ts +97 -0
  100. package/src/query/builder.test.ts +272 -0
  101. package/src/query/builder.ts +274 -0
  102. package/src/query/index.ts +2 -0
  103. package/src/query/types.ts +107 -0
  104. package/src/security/index.ts +2 -0
  105. package/src/security/types.ts +210 -0
  106. package/src/security/validator.test.ts +459 -0
  107. package/src/security/validator.ts +395 -0
  108. package/src/security.test.ts +366 -0
  109. package/src/translators/drizzle/drizzle-translator.test.ts +128 -0
  110. package/src/translators/drizzle/index.test.ts +45 -0
  111. package/src/translators/drizzle/index.ts +346 -0
  112. package/src/translators/index.ts +14 -0
  113. package/src/translators/sql/index.test.ts +45 -0
  114. package/src/translators/sql/index.ts +331 -0
  115. package/src/translators/sql/sql-translator.test.ts +419 -0
  116. package/src/translators/types.ts +44 -0
  117. package/src/types/sonner.d.ts +3 -0
  118. package/tsconfig.json +34 -0
package/README.md ADDED
@@ -0,0 +1,237 @@
1
+ # QueryKit
2
+
3
+ QueryKit is a modern query toolkit for Lucene-style search, designed to give developers a head-start for dynamic search. QueryKit simplifies how you build and execute fielded searchs across different databases and ORMs. It provides a unified, intuitive SDK for filtering, sorting, and transforming data, and handles the heavy lifting of parsing and translating those queries to your data source.
4
+
5
+ ## What Does QueryKit Do?
6
+
7
+ QueryKit allows developers to define queries in a high-level, readable format and then run those queries anywhere (in the browser, on the server, or via CLI). Instead of writing different query logic for each layer of your stack, you can use QueryKit's consistent API to:
8
+
9
+ - **Filter and sort data with a Lucene-like query language** – For example, `status:done AND in:todos`.
10
+
11
+ - **Translate high-level queries to concrete implementations** – QueryKit takes your schema definition and converts it into the appropriate form for the environment.
12
+
13
+ - **Unify front‑end and back‑end filtering logic** – The same QueryKit query can be run in a front-end app for client-side filtering or on a server for database queries. This ensures consistency in how data is filtered across your application.
14
+
15
+ ## Quick Start
16
+
17
+ Below are various examples of how to use QueryKit.
18
+
19
+ **Drizzle ORM**
20
+
21
+ ```typescript
22
+
23
+ // schema.ts
24
+ import { serial, text, pgTable } from 'drizzle-orm/pg-core';
25
+ import { type InferSelectModel, type InferInsertModel } from 'drizzle-orm'
26
+
27
+ const users = pgTable('users', {
28
+ id: serial('id').primaryKey(),
29
+ name: text('name').notNull(),
30
+ status: text('status').notNull().default('draft')
31
+ });
32
+
33
+ type SelectUser = InferSelectModel<typeof users>;
34
+
35
+ // example.ts
36
+ import { SelectUser } from './schema';
37
+ import { createQueryKit } from 'querykit';
38
+ import { drizzleAdapter } from 'querykit/adapters/drizzle';
39
+
40
+ // Create a QueryKit instance with Drizzle adapter
41
+ const qk = createQueryKit({
42
+ adapter: drizzleAdapter,
43
+ schema: { users },
44
+ });
45
+
46
+ // Build a query using the Lucene-like query syntax
47
+ const query = qk.query('users')
48
+ .where('status:done AND name:"John *"')
49
+ .orderBy('name', 'asc')
50
+ .limit(10);
51
+
52
+ // Execute the query against your database
53
+ const results = await query.execute();
54
+ ```
55
+
56
+ ## Query Syntax
57
+
58
+ QueryKit uses Liqe Query Language (LQL), which is a Lucene-like syntax for filtering data:
59
+
60
+ ```
61
+ # Basic field queries
62
+ status:active # Field equals value (case insensitive)
63
+ status:"Active" # Field equals value (case sensitive)
64
+
65
+ # Comparison operators
66
+ priority:>2 # Greater than
67
+ priority:>=2 # Greater than or equal
68
+ priority:<2 # Less than
69
+ priority:<=2 # Less than or equal
70
+ priority:=2 # Exact equals
71
+
72
+ # Ranges
73
+ dueDate:[2023-01-01 TO 2023-01-31] # Inclusive range
74
+ dueDate:{2023-01-01 TO 2023-01-31} # Exclusive range
75
+
76
+ # Pattern matching
77
+ name:/Todo.*/ # Regular expression
78
+ title:intro* # Wildcard matching
79
+
80
+ # Boolean operators
81
+ status:active AND priority:>2 # AND operator
82
+ status:active OR status:pending # OR operator
83
+ NOT expired:true # NOT operator
84
+ -expired:true # Alternative NOT syntax
85
+
86
+ # Grouping
87
+ (status:active OR status:pending) AND priority:<3
88
+
89
+ # Implicit AND (space between expressions)
90
+ status:active priority:>2
91
+ ```
92
+
93
+ ## Installation
94
+
95
+ ```bash
96
+ npm install querykit
97
+ ```
98
+
99
+ ## Dependencies
100
+
101
+ QueryKit leverages several key dependencies to provide its functionality:
102
+
103
+ - [**Liqe**](https://github.com/gajus/liqe): A lightweight and performant Lucene-like parser, serializer, and search engine. QueryKit uses Liqe for parsing the query syntax into an abstract syntax tree (AST) that can then be translated to various target languages.
104
+
105
+ - [**Drizzle ORM**](https://github.com/drizzle-team/drizzle-orm): A TypeScript ORM that's used for SQL database interactions. QueryKit's Drizzle adapter translates queries into Drizzle ORM queries.
106
+
107
+ Additional dependencies will be added as the project evolves.
108
+
109
+ ## Security Features
110
+
111
+ QueryKit provides configurable security guardrails to protect your database from potentially harmful queries while maintaining flexibility. These features can be configured during initialization:
112
+
113
+ > **IMPORTANT DISCLAIMER**: While QueryKit provides guardrails to help protect against common query-related vulnerabilities, it is not a comprehensive security solution. These features are provided as helpful tools, not guarantees. You are still responsible for implementing proper authentication, authorization, and other security measures in your application. QueryKit does not guarantee protection against all forms of database attacks or query exploits.
114
+
115
+ ```typescript
116
+ import { createQueryKit } from 'querykit';
117
+ import { drizzleAdapter } from 'querykit/adapters/drizzle';
118
+
119
+ const qk = createQueryKit({
120
+ adapter: drizzleAdapter,
121
+ schema: { users },
122
+ security: {
123
+ // Field restrictions
124
+ allowedFields: ['name', 'email', 'priority', 'status'], // Only these fields can be queried
125
+ denyFields: ['password', 'secretKey'], // These fields can never be queried
126
+
127
+ // Query complexity limits
128
+ maxQueryDepth: 5, // Maximum nesting level of expressions
129
+ maxClauseCount: 20, // Maximum number of clauses (AND/OR operations)
130
+
131
+ // Resource protection
132
+ defaultLimit: 100, // Default result limit if none specified
133
+ maxLimit: 1000, // Maximum allowed limit for pagination
134
+
135
+ // Value sanitization
136
+ maxValueLength: 100, // Maximum string length for query values
137
+ sanitizeWildcards: true, // Prevent regex DoS with wildcards in LIKE queries
138
+
139
+ // Performance safeguards
140
+ queryTimeout: 5000, // Timeout in milliseconds for query execution
141
+ }
142
+ });
143
+ ```
144
+
145
+ By default, QueryKit applies sensible security defaults even without explicit configuration:
146
+
147
+ ```typescript
148
+ // Default security configuration
149
+ const DEFAULT_SECURITY = {
150
+ // Field restrictions - by default, all schema fields are allowed
151
+ allowedFields: [], // Empty means "use schema fields"
152
+ denyFields: [], // Empty means no denied fields
153
+
154
+ // Query complexity limits
155
+ maxQueryDepth: 10, // Maximum nesting level of expressions
156
+ maxClauseCount: 50, // Maximum number of clauses (AND/OR operations)
157
+
158
+ // Resource protection
159
+ defaultLimit: 100, // Default result limit if none specified
160
+ maxLimit: 1000, // Maximum allowed limit for pagination
161
+
162
+ // Value sanitization
163
+ maxValueLength: 1000, // Maximum string length for query values
164
+ sanitizeWildcards: true, // Prevent regex DoS with wildcards in LIKE queries
165
+
166
+ // Performance safeguards
167
+ queryTimeout: 30000, // 30 second timeout by default
168
+ }
169
+ ```
170
+
171
+ Security configurations can be stored in a separate file and imported:
172
+
173
+ ```typescript
174
+ // security-config.json
175
+ {
176
+ "allowedFields": ["name", "email", "priority", "status"],
177
+ "maxQueryDepth": 5,
178
+ "maxClauseCount": 20,
179
+ "defaultLimit": 100
180
+ }
181
+
182
+ // In your app
183
+ import securityConfig from './security-config.json';
184
+
185
+ const qk = createQueryKit({
186
+ adapter: drizzleAdapter,
187
+ schema: { users },
188
+ security: securityConfig
189
+ });
190
+ ```
191
+
192
+ ### Additional Security Recommendations
193
+
194
+ When using QueryKit in production, consider these additional security practices:
195
+
196
+ 1. **Implement Authentication and Authorization**: QueryKit doesn't handle auth - integrate with your existing auth system.
197
+ 2. **Use Rate Limiting**: Limit the number of queries a user can make in a given time period.
198
+ 3. **Audit Logging**: Log all queries for security monitoring and debugging.
199
+ 4. **Field-Level Access Control**: Use dynamic allowedFields based on user roles/permissions.
200
+ 5. **Separate Query Context**: Consider separate QueryKit instances with different security settings for different contexts (admin vs. user).
201
+
202
+ ## Roadmap
203
+
204
+ ### Core Parsing Engine and DSL
205
+ - [x] Implement Lucene-style query syntax parser using Liqe
206
+ - [x] Create type-safe query building API
207
+ - [x] Develop internal AST representation
208
+ - [x] Implement consistent syntax for logical operators (AND, OR, NOT)
209
+ - [x] Support standard comparison operators (==, !=, >, >=, <, <=)
210
+
211
+ ### First Adapters
212
+ - [x] Drizzle ORM integration
213
+ - [x] Implement SQL translation layer
214
+ - [ ] In-memory JavaScript filtering
215
+ - [x] Query validation and error handling
216
+ - [x] Support for schema-aware queries
217
+
218
+ ### Advanced Features
219
+ - [ ] CLI tools for testing and debugging
220
+ - [x] Performance optimizations for SQL generation
221
+ - [x] Support for complex nested expressions
222
+ - [ ] Custom function support
223
+ - [ ] Pagination helpers
224
+
225
+ ### Ecosystem Expansion
226
+ - [ ] Frontend query builder components
227
+ - [ ] Additional ORM adapters
228
+ - [ ] Server middleware for Express/Fastify
229
+ - [ ] TypeScript SDK generation
230
+
231
+ ## Contributing
232
+
233
+ See the [CONTRIBUTING.md](CONTRIBUTING.md) file for details on how to get started.
234
+
235
+ ## License
236
+
237
+ This project is licensed under the GPL License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Drizzle ORM Adapter for QueryKit
3
+ *
4
+ * This adapter connects QueryKit to Drizzle ORM for database queries.
5
+ */
6
+ import { IAdapter, IAdapterOptions, IQueryExecutionOptions } from '../types';
7
+ import { QueryExpression } from '../../parser/types';
8
+ import { SQL } from 'drizzle-orm';
9
+ import { QueryKit } from '../../index';
10
+ /**
11
+ * Type for Drizzle ORM database instance
12
+ */
13
+ export interface IDrizzleDatabase {
14
+ select: () => {
15
+ from: (table: unknown) => IDrizzleQueryBuilder;
16
+ };
17
+ }
18
+ /**
19
+ * Type for Drizzle query builder
20
+ */
21
+ export interface IDrizzleQueryBuilder {
22
+ where: (condition: SQL) => IDrizzleQueryBuilder;
23
+ orderBy: (...clauses: SQL[]) => IDrizzleQueryBuilder;
24
+ limit: (limit: number) => IDrizzleQueryBuilder;
25
+ offset: (offset: number) => IDrizzleQueryBuilder;
26
+ [Symbol.toStringTag]: string;
27
+ then<TResult1 = unknown, TResult2 = never>(onfulfilled?: ((value: unknown[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
28
+ }
29
+ /**
30
+ * Options specific to the Drizzle adapter
31
+ */
32
+ export interface IDrizzleAdapterOptions<TSchema extends Record<string, unknown> = Record<string, unknown>> extends IAdapterOptions {
33
+ /**
34
+ * The Drizzle ORM database instance
35
+ */
36
+ db: IDrizzleDatabase | unknown;
37
+ /**
38
+ * Schema information with Drizzle table definitions
39
+ */
40
+ schema: TSchema;
41
+ /**
42
+ * Whether to normalize field names (e.g., lowercase them)
43
+ */
44
+ normalizeFieldNames?: boolean;
45
+ }
46
+ /**
47
+ * Options for Drizzle query execution
48
+ */
49
+ export interface IDrizzleQueryExecutionOptions extends IQueryExecutionOptions {
50
+ /**
51
+ * Sort fields in the format: { field: 'asc' | 'desc' }
52
+ */
53
+ orderBy?: Record<string, 'asc' | 'desc'>;
54
+ /**
55
+ * Maximum number of records to return
56
+ */
57
+ limit?: number;
58
+ /**
59
+ * Number of records to skip
60
+ */
61
+ offset?: number;
62
+ }
63
+ /**
64
+ * Error thrown when adapter operations fail
65
+ */
66
+ export declare class DrizzleAdapterError extends Error {
67
+ constructor(message: string);
68
+ }
69
+ /**
70
+ * Adapter for Drizzle ORM
71
+ */
72
+ export declare class DrizzleAdapter<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IAdapter<IDrizzleAdapterOptions<TSchema>> {
73
+ private db;
74
+ private schema;
75
+ private translator;
76
+ private initialized;
77
+ /**
78
+ * Optionally initialize via constructor for convenience
79
+ */
80
+ constructor(options?: IDrizzleAdapterOptions<TSchema>);
81
+ /**
82
+ * Initialize the adapter with options
83
+ */
84
+ initialize(options: IDrizzleAdapterOptions<TSchema>): void;
85
+ /**
86
+ * Execute a QueryKit expression using Drizzle ORM
87
+ */
88
+ execute<TResult = unknown>(tableName: string, expression: QueryExpression, options?: IDrizzleQueryExecutionOptions): Promise<TResult[]>;
89
+ /**
90
+ * Check if an expression can be executed by this adapter
91
+ */
92
+ canExecute(expression: QueryExpression): boolean;
93
+ /**
94
+ * Get a table from the schema
95
+ */
96
+ private getTable;
97
+ /**
98
+ * Get a field from the schema
99
+ */
100
+ private getSchemaField;
101
+ /**
102
+ * Ensure the adapter is initialized
103
+ */
104
+ private ensureInitialized;
105
+ }
106
+ /**
107
+ * Convenience factory to create a pre-initialized Drizzle adapter
108
+ */
109
+ export declare function drizzleAdapter<TSchema extends Record<string, unknown>>(options: IDrizzleAdapterOptions<TSchema>): DrizzleAdapter<TSchema>;
110
+ export type RowTypeFromDrizzleTable<TTable> = TTable extends {
111
+ $inferSelect: infer R;
112
+ } ? R : unknown;
113
+ export type RowMapFromDrizzleSchema<TSchema extends Record<string, unknown>> = {
114
+ [K in keyof TSchema]: RowTypeFromDrizzleTable<TSchema[K]>;
115
+ };
116
+ export declare function createDrizzleQueryKit<TSchema extends Record<string, object>>(args: {
117
+ db: unknown;
118
+ schema: TSchema;
119
+ normalizeFieldNames?: boolean;
120
+ fieldMappings?: Record<string, string>;
121
+ security?: import('../../security').ISecurityOptions;
122
+ }): QueryKit<TSchema, RowMapFromDrizzleSchema<TSchema>>;
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * Drizzle ORM Adapter for QueryKit
4
+ *
5
+ * This adapter connects QueryKit to Drizzle ORM for database queries.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.DrizzleAdapter = exports.DrizzleAdapterError = void 0;
9
+ exports.drizzleAdapter = drizzleAdapter;
10
+ exports.createDrizzleQueryKit = createDrizzleQueryKit;
11
+ const drizzle_1 = require("../../translators/drizzle");
12
+ const drizzle_orm_1 = require("drizzle-orm");
13
+ const index_1 = require("../../index");
14
+ /**
15
+ * Error thrown when adapter operations fail
16
+ */
17
+ class DrizzleAdapterError extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = 'DrizzleAdapterError';
21
+ }
22
+ }
23
+ exports.DrizzleAdapterError = DrizzleAdapterError;
24
+ /**
25
+ * Adapter for Drizzle ORM
26
+ */
27
+ class DrizzleAdapter {
28
+ /**
29
+ * Optionally initialize via constructor for convenience
30
+ */
31
+ constructor(options) {
32
+ this.initialized = false;
33
+ if (options) {
34
+ this.initialize(options);
35
+ }
36
+ }
37
+ /**
38
+ * Initialize the adapter with options
39
+ */
40
+ initialize(options) {
41
+ if (!options.db) {
42
+ throw new DrizzleAdapterError('Drizzle db instance is required');
43
+ }
44
+ if (!options.schema) {
45
+ throw new DrizzleAdapterError('Schema definition is required');
46
+ }
47
+ this.db = options.db;
48
+ this.schema = options.schema;
49
+ this.translator = new drizzle_1.DrizzleTranslator({
50
+ normalizeFieldNames: options.normalizeFieldNames,
51
+ fieldMappings: options.fieldMappings,
52
+ schema: options.schema
53
+ });
54
+ this.initialized = true;
55
+ }
56
+ /**
57
+ * Execute a QueryKit expression using Drizzle ORM
58
+ */
59
+ async execute(tableName, expression, options) {
60
+ this.ensureInitialized();
61
+ const table = this.getTable(tableName);
62
+ if (!table) {
63
+ throw new DrizzleAdapterError(`Table ${tableName} not found in schema`);
64
+ }
65
+ try {
66
+ // Start with a base query
67
+ let query = this.db.select().from(table);
68
+ // Add where condition if expression is provided
69
+ if (expression) {
70
+ const condition = this.translator.translate(expression);
71
+ query = query.where(condition);
72
+ }
73
+ // Add ordering if specified
74
+ if (options?.orderBy) {
75
+ const orderClauses = [];
76
+ Object.entries(options.orderBy).forEach(([field, direction]) => {
77
+ // Try to find the field in the schema
78
+ const schemaField = this.getSchemaField(tableName, field);
79
+ if (schemaField) {
80
+ // If field exists in schema, use it directly
81
+ orderClauses.push(direction === 'asc' ? (0, drizzle_orm_1.asc)(schemaField) : (0, drizzle_orm_1.desc)(schemaField));
82
+ }
83
+ else {
84
+ // Otherwise use raw SQL
85
+ orderClauses.push((0, drizzle_orm_1.sql) `${drizzle_orm_1.sql.identifier(field)} ${drizzle_orm_1.sql.raw(direction.toUpperCase())}`);
86
+ }
87
+ });
88
+ if (orderClauses.length > 0) {
89
+ query = query.orderBy(...orderClauses);
90
+ }
91
+ }
92
+ // Add limit if specified
93
+ if (options?.limit !== undefined) {
94
+ query = query.limit(options.limit);
95
+ }
96
+ // Add offset if specified
97
+ if (options?.offset !== undefined) {
98
+ query = query.offset(options.offset);
99
+ }
100
+ // Execute the query
101
+ const result = await query;
102
+ return result;
103
+ }
104
+ catch (error) {
105
+ throw new DrizzleAdapterError(`Failed to execute query: ${error instanceof Error ? error.message : String(error)}`);
106
+ }
107
+ }
108
+ /**
109
+ * Check if an expression can be executed by this adapter
110
+ */
111
+ canExecute(expression) {
112
+ try {
113
+ this.ensureInitialized();
114
+ return this.translator.canTranslate(expression);
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ }
120
+ /**
121
+ * Get a table from the schema
122
+ */
123
+ getTable(tableName) {
124
+ return this.schema[tableName];
125
+ }
126
+ /**
127
+ * Get a field from the schema
128
+ */
129
+ getSchemaField(tableName, fieldName) {
130
+ const schemaAsColumns = this.schema;
131
+ const table = schemaAsColumns[tableName];
132
+ if (table && fieldName in table) {
133
+ return table[fieldName];
134
+ }
135
+ return null;
136
+ }
137
+ /**
138
+ * Ensure the adapter is initialized
139
+ */
140
+ ensureInitialized() {
141
+ if (!this.initialized) {
142
+ throw new DrizzleAdapterError('Adapter has not been initialized');
143
+ }
144
+ }
145
+ }
146
+ exports.DrizzleAdapter = DrizzleAdapter;
147
+ /**
148
+ * Convenience factory to create a pre-initialized Drizzle adapter
149
+ */
150
+ function drizzleAdapter(options) {
151
+ return new DrizzleAdapter(options);
152
+ }
153
+ function createDrizzleQueryKit(args) {
154
+ const adapter = new DrizzleAdapter();
155
+ adapter.initialize({
156
+ db: args.db,
157
+ schema: args.schema,
158
+ normalizeFieldNames: args.normalizeFieldNames,
159
+ fieldMappings: args.fieldMappings
160
+ });
161
+ return (0, index_1.createQueryKit)({
162
+ adapter,
163
+ schema: args.schema,
164
+ security: args.security
165
+ });
166
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * QueryKit Adapters
3
+ *
4
+ * Exports all adapter implementations for different database systems.
5
+ */
6
+ export * from './types';
7
+ export * from './drizzle';
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * QueryKit Adapters
4
+ *
5
+ * Exports all adapter implementations for different database systems.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ // Export base types
23
+ __exportStar(require("./types"), exports);
24
+ // Export Drizzle adapter
25
+ __exportStar(require("./drizzle"), exports);
@@ -0,0 +1,60 @@
1
+ /**
2
+ * QueryKit Adapter Types
3
+ *
4
+ * These are the core interfaces for adapters, which connect QueryKit to
5
+ * external systems or libraries like Drizzle ORM.
6
+ */
7
+ import { QueryExpression } from '../parser/types';
8
+ /**
9
+ * Options for configuring an adapter
10
+ */
11
+ export interface IAdapterOptions {
12
+ /**
13
+ * Schema information for type safety and validation
14
+ */
15
+ schema?: Record<string, unknown>;
16
+ /**
17
+ * Field mappings from QueryKit fields to target database fields
18
+ */
19
+ fieldMappings?: Record<string, string>;
20
+ }
21
+ /**
22
+ * Options for a query execution
23
+ */
24
+ export interface IQueryExecutionOptions {
25
+ /**
26
+ * Optional transaction object
27
+ */
28
+ transaction?: unknown;
29
+ /**
30
+ * Additional parameters specific to the adapter
31
+ */
32
+ [key: string]: unknown;
33
+ }
34
+ /**
35
+ * Interface for a query adapter
36
+ */
37
+ export interface IAdapter<TOptions extends IAdapterOptions = IAdapterOptions> {
38
+ /**
39
+ * Initialize the adapter with options
40
+ *
41
+ * @param options Adapter-specific options
42
+ */
43
+ initialize(options: TOptions): void;
44
+ /**
45
+ * Execute a QueryKit expression and return results
46
+ *
47
+ * @param tableName The table/collection name to query
48
+ * @param expression The QueryKit expression to execute
49
+ * @param options Optional execution options
50
+ * @returns The query results
51
+ */
52
+ execute<T = unknown>(tableName: string, expression: QueryExpression, options?: IQueryExecutionOptions): Promise<T[]>;
53
+ /**
54
+ * Check if an expression can be executed by this adapter
55
+ *
56
+ * @param expression The QueryKit expression to check
57
+ * @returns true if the expression can be executed, false otherwise
58
+ */
59
+ canExecute(expression: QueryExpression): boolean;
60
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * QueryKit Adapter Types
4
+ *
5
+ * These are the core interfaces for adapters, which connect QueryKit to
6
+ * external systems or libraries like Drizzle ORM.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });