@@ -12,10 +12,24 @@ import knex, { Knex } from 'knex';
1212/**
1313 * SQL Driver for ObjectQL
1414 *
15- * Implements the Driver interface from @objectql/types with optional
16- * ObjectStack-compatible properties for integration with @objectstack/objectql.
15+ * Implements both the legacy Driver interface from @objectql/types and
16+ * the standard DriverInterface from @objectstack/spec for compatibility
17+ * with the new kernel-based plugin system.
18+ *
19+ * The driver internally converts QueryAST format to Knex query builder calls.
1720 */
1821export class SqlDriver implements Driver {
22+ // Driver metadata (ObjectStack-compatible)
23+ public readonly name = 'SqlDriver' ;
24+ public readonly version = '3.0.1' ;
25+ public readonly supports = {
26+ transactions : true ,
27+ joins : true ,
28+ fullTextSearch : false ,
29+ jsonFields : true ,
30+ arrayFields : true
31+ } ;
32+
1933 private knex : Knex ;
2034 private config : any ;
2135 private jsonFields : Record < string , string [ ] > = { } ;
@@ -107,21 +121,52 @@ export class SqlDriver implements Driver {
107121 return field ;
108122 }
109123
124+ /**
125+ * Normalizes query format to support both legacy UnifiedQuery and QueryAST formats.
126+ * This ensures backward compatibility while supporting the new @objectstack/spec interface.
127+ *
128+ * QueryAST format uses 'top' for limit, while UnifiedQuery uses 'limit'.
129+ * QueryAST sort is array of {field, order}, while UnifiedQuery is array of [field, order].
130+ */
131+ private normalizeQuery ( query : any ) : any {
132+ if ( ! query ) return { } ;
133+
134+ const normalized : any = { ...query } ;
135+
136+ // Normalize limit/top
137+ if ( normalized . top !== undefined && normalized . limit === undefined ) {
138+ normalized . limit = normalized . top ;
139+ }
140+
141+ // Normalize sort format
142+ if ( normalized . sort && Array . isArray ( normalized . sort ) ) {
143+ // Check if it's already in the array format [field, order]
144+ const firstSort = normalized . sort [ 0 ] ;
145+ if ( firstSort && typeof firstSort === 'object' && ! Array . isArray ( firstSort ) ) {
146+ // Convert from QueryAST format {field, order} to internal format [field, order]
147+ // Keep the object format as the applySort logic already handles it
148+ }
149+ }
150+
151+ return normalized ;
152+ }
153+
110154 async find ( objectName : string , query : any , options ?: any ) : Promise < any [ ] > {
155+ const normalizedQuery = this . normalizeQuery ( query ) ;
111156 const builder = this . getBuilder ( objectName , options ) ;
112157
113- if ( query . fields ) {
114- builder . select ( query . fields . map ( ( f : string ) => this . mapSortField ( f ) ) ) ;
158+ if ( normalizedQuery . fields ) {
159+ builder . select ( normalizedQuery . fields . map ( ( f : string ) => this . mapSortField ( f ) ) ) ;
115160 } else {
116161 builder . select ( '*' ) ;
117162 }
118163
119- if ( query . filters ) {
120- this . applyFilters ( builder , query . filters ) ;
164+ if ( normalizedQuery . filters ) {
165+ this . applyFilters ( builder , normalizedQuery . filters ) ;
121166 }
122167
123- if ( query . sort && Array . isArray ( query . sort ) ) {
124- for ( const item of query . sort ) {
168+ if ( normalizedQuery . sort && Array . isArray ( normalizedQuery . sort ) ) {
169+ for ( const item of normalizedQuery . sort ) {
125170 let field : string | undefined ;
126171 let dir : string | undefined ;
127172
@@ -139,8 +184,8 @@ export class SqlDriver implements Driver {
139184 }
140185 }
141186
142- if ( query . skip ) builder . offset ( query . skip ) ;
143- if ( query . limit ) builder . limit ( query . limit ) ;
187+ if ( normalizedQuery . skip ) builder . offset ( normalizedQuery . skip ) ;
188+ if ( normalizedQuery . limit ) builder . limit ( normalizedQuery . limit ) ;
144189
145190 const results = await builder ;
146191
0 commit comments