@@ -9,6 +9,7 @@ import { QueryNode, DataNode, QueryNodeSql } from './types'
99type DataNodeQueryInfo = {
1010 whereClause ?: string
1111 orderByLimitOffset ?: string
12+ values : any [ ]
1213}
1314
1415const isQueryNodeRangeConstrained = ( queryNode : QueryNode ) => {
@@ -26,11 +27,14 @@ const isQueryNodeRangeConstrained = (queryNode: QueryNode) => {
2627 *
2728 * If the data node does not have any filter, this will return `null`.
2829 */
29- const createWhereClauseOfDataNode = ( dataNode : DataNode < false > ) : string | null => {
30+ const createWhereClauseOfDataNode = ( dataNode : DataNode < false > , parameterStartIndex : number ) : { sql : string | null , values : any [ ] } | null => {
3031 const dataFilterNodeOrGroup = dataNode . options . filter
3132 return dataFilterNodeOrGroup != null
3233 ? createDataFilter ( dataFilterNodeOrGroup )
33- . toSql ( { transformer : node => ( { left : dataNode . fieldsInfo . fieldToFullyQualifiedColumnName [ node . field ] } ) } )
34+ . toSql ( {
35+ transformer : node => ( { left : dataNode . fieldsInfo . fieldToFullyQualifiedColumnName [ node . field ] } ) ,
36+ parameterStartIndex,
37+ } )
3438 : null
3539}
3640
@@ -44,48 +48,64 @@ const createWhereClauseOfDataNode = (dataNode: DataNode<false>): string | null =
4448 * If the data node has a query, but is missing certain parts of the data query, then the where
4549 * clause and/or the order-by-limit-offset statement can be null.
4650 */
47- const createQueryInfoOfDataNode = ( dataNode : DataNode < true > ) : DataNodeQueryInfo | null => {
51+ const createQueryInfoOfDataNode = ( dataNode : DataNode < true > , parameterStartIndex : number ) : DataNodeQueryInfo | null => {
4852 const dataQueryRecord = dataNode . options . query
4953 if ( dataQueryRecord != null ) {
5054 const dataQuerySql = createDataQuery ( dataQueryRecord ) . toSql ( {
5155 sortingTransformer : node => ( { left : dataNode . fieldsInfo . fieldToFullyQualifiedColumnName [ node . field ] } ) ,
5256 filterTransformer : node => ( { left : dataNode . fieldsInfo . fieldToFullyQualifiedColumnName [ node . field ] } ) ,
5357 includeWhereWord : false ,
58+ parameterStartIndex,
5459 } )
5560 return {
5661 whereClause : dataQuerySql . where ,
5762 orderByLimitOffset : dataQuerySql . orderByLimitOffset ,
63+ values : dataQuerySql . values ,
5864 }
5965 }
6066 return null
6167}
6268
63- const createDataNodeQueryInfo = ( dataNode : DataNode ) : DataNodeQueryInfo | null => (
64- dataNode . isPlural
65- ? createQueryInfoOfDataNode ( dataNode as DataNode < true > )
66- : {
67- whereClause : createWhereClauseOfDataNode ( dataNode as DataNode < false > ) ,
68- orderByLimitOffset : 'limit 1' ,
69- }
70- )
69+ const createDataNodeQueryInfo = ( dataNode : DataNode , parameterStartIndex : number ) : DataNodeQueryInfo | null => {
70+ if ( dataNode . isPlural )
71+ return createQueryInfoOfDataNode ( dataNode as DataNode < true > , parameterStartIndex )
72+
73+ const whereClause = createWhereClauseOfDataNode ( dataNode as DataNode < false > , parameterStartIndex )
74+
75+ return {
76+ whereClause : whereClause ?. sql ,
77+ orderByLimitOffset : 'limit 1' ,
78+ values : whereClause ?. values ?? [ ] ,
79+ }
80+ }
7181
7282/**
7383 * Converts all of the non-root (therefore *non-plural*) data nodes within `queryNode` into a
7484 * series of new-line-separated `left join` sql statements, with each data node's filter applied
7585 * alongside each left join as a where clause (minus the actual "where" word since joins just
7686 * need an " and " separator).
7787 */
78- const createLeftJoinsSql = ( queryNode : QueryNode ) => (
79- Object . values ( queryNode . nonRootDataNodes ) . map ( dataNode => {
88+ const createLeftJoinsSql = ( queryNode : QueryNode , parameterStartIndex : number ) : { sql : string , values : any [ ] } => {
89+ const values : any [ ] = [ ]
90+ let _parameterStartIndex = parameterStartIndex
91+
92+ const sql = Object . values ( queryNode . nonRootDataNodes ) . map ( dataNode => {
8093 const linkedColumnName = dataNode . dataFormat . sql . cols [ dataNode . fieldRef . field ]
8194 const parentLinkedColumnName = dataNode . parent . dataFormat . sql . cols [ dataNode . parentFieldRef . field ]
82- const whereClause = createWhereClauseOfDataNode ( dataNode )
95+ const whereClause = createWhereClauseOfDataNode ( dataNode , _parameterStartIndex )
96+ if ( whereClause != null ) {
97+ _parameterStartIndex += whereClause . values . length
98+ values . push ( ...whereClause . values )
99+ }
83100 // E.g. left join "userImage" "1" on "1"."user_id" = "0"."id" and "1"."date_deleted" is not null\n
84101 return filterForNotNullAndEmpty ( [
85102 `left join ${ dataNode . dataFormat . sql . tableName } ${ dataNode . tableAlias } on ${ dataNode . tableAlias } .${ linkedColumnName } = ${ dataNode . parent . tableAlias } .${ parentLinkedColumnName } ` ,
86- whereClause ,
103+ whereClause ?. sql ,
87104 ] ) . join ( ' and ' )
88- } ) . join ( '\n' ) )
105+ } ) . join ( '\n' )
106+
107+ return { sql, values }
108+ }
89109
90110const createLinkedFieldWhereClause = (
91111 queryNode : QueryNode ,
@@ -141,6 +161,8 @@ const createLinkedFieldWhereClause = (
141161export const toSql = ( queryNode : QueryNode , linkedFieldValues : any [ ] ) => {
142162 const isManyToMany = queryNode . rootDataNode . relation ?. type === RelationType . MANY_TO_MANY
143163 const isRangeConstrained = isQueryNodeRangeConstrained ( queryNode ) && linkedFieldValues ?. length > 0
164+ const values : any [ ] = [ ]
165+ let parameterStartIndex = 1
144166
145167 const sqlParts : string [ ] = [ 'select' ]
146168
@@ -272,12 +294,17 @@ export const toSql = (queryNode: QueryNode, linkedFieldValues: any[]) => {
272294 }
273295
274296 // -- Root data node query SQL
275- const rootDataNodeQueryInfo = createDataNodeQueryInfo ( rootDataNode )
297+ const rootDataNodeQueryInfo = createDataNodeQueryInfo ( rootDataNode , parameterStartIndex )
276298 if ( rootDataNodeQueryInfo ?. whereClause != null )
277299 sqlParts . push ( `and ${ rootDataNodeQueryInfo . whereClause } ` )
278300 if ( rootDataNodeQueryInfo ?. orderByLimitOffset != null )
279301 sqlParts . push ( rootDataNodeQueryInfo . orderByLimitOffset )
280302
303+ if ( rootDataNodeQueryInfo != null ) {
304+ parameterStartIndex += rootDataNodeQueryInfo . values . length
305+ values . push ( ...rootDataNodeQueryInfo . values )
306+ }
307+
281308 // -- As ... sql
282309 let asSql : string
283310 if ( isManyToMany )
@@ -291,9 +318,12 @@ export const toSql = (queryNode: QueryNode, linkedFieldValues: any[]) => {
291318 // ----------------------------------------------------------------------------------
292319 // -- To-one related data left joins
293320 // ----------------------------------------------------------------------------------
294- const leftJoinsSql = createLeftJoinsSql ( queryNode )
295- if ( leftJoinsSql != null && leftJoinsSql . length > 0 )
296- sqlParts . push ( leftJoinsSql )
321+ const leftJoinsSql = createLeftJoinsSql ( queryNode , parameterStartIndex )
322+ if ( leftJoinsSql != null && leftJoinsSql . sql . length > 0 )
323+ sqlParts . push ( leftJoinsSql . sql )
324+
325+ parameterStartIndex += leftJoinsSql . values . length
326+ values . push ( ...leftJoinsSql . values )
297327
298328 // ----------------------------------------------------------------------------------
299329 // -- Linked field values where clause and (possibly) root data node query
@@ -304,7 +334,7 @@ export const toSql = (queryNode: QueryNode, linkedFieldValues: any[]) => {
304334 sqlParts . push ( `where ${ linkedFieldValuesWhereClause } ` )
305335 }
306336 else {
307- const rootDataNodeQueryInfo = createDataNodeQueryInfo ( rootDataNode )
337+ const rootDataNodeQueryInfo = createDataNodeQueryInfo ( rootDataNode , parameterStartIndex )
308338 const rootDataNodeTotalWhereClauseSegments = [ linkedFieldValuesWhereClause , rootDataNodeQueryInfo ?. whereClause ] . filter ( s => s != null )
309339 if ( rootDataNodeTotalWhereClauseSegments . length > 0 ) {
310340 const rootDataNodeTotalWhereClause = rootDataNodeTotalWhereClauseSegments . join ( ' and ' )
@@ -313,9 +343,14 @@ export const toSql = (queryNode: QueryNode, linkedFieldValues: any[]) => {
313343
314344 if ( rootDataNodeQueryInfo ?. orderByLimitOffset != null )
315345 sqlParts . push ( rootDataNodeQueryInfo . orderByLimitOffset )
346+
347+ if ( rootDataNodeQueryInfo != null ) {
348+ parameterStartIndex += rootDataNodeQueryInfo . values . length
349+ values . push ( ...rootDataNodeQueryInfo . values )
350+ }
316351 }
317352
318- return sqlParts . join ( '\n' )
353+ return { sql : sqlParts . join ( '\n' ) , values }
319354}
320355
321356export const queryNodeToSql = < TIsPlural extends boolean = boolean > (
@@ -325,27 +360,39 @@ export const queryNodeToSql = <TIsPlural extends boolean = boolean>(
325360 let queryNodeSql : QueryNodeSql
326361 let currentLinkedFieldValues = linkedFieldValues
327362
363+ const initialSql = toSql ( queryNode , currentLinkedFieldValues )
364+
365+ const updateSql = ( ) => {
366+ const newSql = toSql ( queryNode , currentLinkedFieldValues )
367+ queryNodeSql . sql = newSql . sql
368+ queryNodeSql . values = newSql . values
369+ }
370+
328371 return queryNodeSql = {
329- sql : toSql ( queryNode , currentLinkedFieldValues ) ,
372+ sql : initialSql . sql ,
373+ values : initialSql . values ,
330374 updateLinkedFieldValues : ( newLinkedFieldValues : any [ ] | null ) => {
331375 currentLinkedFieldValues = newLinkedFieldValues
332- queryNodeSql . sql = toSql ( queryNode , currentLinkedFieldValues )
376+
377+ updateSql ( )
333378 } ,
334379 modifyRootDataNodeDataFilter : newDataFilter => {
335380 if ( queryNode . rootDataNode . isPlural )
336381 throw new Error ( 'Cannot update root data node data filter, it is plural. Try calling modifyRootDataNodeDataQuery().' )
337382
338383 const _nonPluralRootDataNode = queryNode . rootDataNode as DataNode < false >
339384 _nonPluralRootDataNode . options . filter = newDataFilter
340- queryNodeSql . sql = toSql ( queryNode , currentLinkedFieldValues )
385+
386+ updateSql ( )
341387 } ,
342388 modifyRootDataNodeDataQuery : newDataQuery => {
343389 if ( ! queryNode . rootDataNode . isPlural )
344390 throw new Error ( 'Cannot update root data node data query, it is non-plural. Try calling modifyRootDataNodeDataFilter().' )
345391
346392 const _pluralRootDataNode = queryNode . rootDataNode as DataNode < true >
347393 _pluralRootDataNode . options . query = newDataQuery
348- queryNodeSql . sql = toSql ( queryNode , currentLinkedFieldValues )
394+
395+ updateSql ( )
349396 } ,
350397 }
351398}
0 commit comments