@@ -68,169 +68,141 @@ macro selectAll*(tableName: untyped): untyped =
6868 checkTableExists ($ tableName)
6969 result = newCall (bindSym " ozarkSelectResult" , newLit (" SELECT * FROM " & $ tableName))
7070
71- macro where * (sql: untyped , col: static string , val: untyped ): untyped =
72- # # Define WHERE clause
71+
72+ #
73+ # WHERE clause macros
74+ #
75+
76+ # - WHERE caluse Writers
77+ proc writeWhereLikeStatements (op: static string , sql: NimNode ,
78+ infix: NimNode , col: string ): NimNode {.compileTime .} =
79+ # Writer macro for both `whereLike` and `whereNotLike` to avoid code duplication.
80+ # This macro generates the SQL string for the WHERE LIKE/NOT LIKE clause and
81+ # also constructs the appropriate infix expression for the value with wildcards
7382 if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
74- error (" The first argument to `where` must be the result of a `select` macro." )
83+ error (" The first argument to `where` statement must be the result of a `select` macro." )
7584 if col.validIdentifier:
7685 # todo check if column exists in model
7786 discard
7887 else :
7988 raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
8089 let selectSql = sql[1 ].strVal
8190 result = newCall (bindSym " ozarkWhereResult" ,
82- newLit (selectSql & " WHERE " & col & " = $1" ),
83- val
91+ newLit (selectSql & " WHERE " & col & " " & op & " $1" ),
92+ infix
8493 )
8594
86- macro whereNot * (sql: untyped , col: static string , val: untyped ): untyped =
87- # # Define WHERE clause with NOT
95+ proc writeWhereInWhereNotIn (op: static string ,
96+ sql: NimNode , col: string , vals: NimNode ): NimNode {.compileTime .} =
97+ # Writer macro for both `whereIn` and `whereNotIn` to avoid code duplication.
98+ # This macro generates the SQL string for the WHERE IN/NOT IN clause and
99+ # also adds the values as additional arguments to the macro result for later use in code generation
88100 if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
89- error (" The first argument to `whereNot` must be the result of a `select` macro." )
101+ error (" The first argument to must be the result of a `select` macro." )
90102 if col.validIdentifier:
91103 # todo check if column exists in model
92104 discard
93105 else :
94106 raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
95107 let selectSql = sql[1 ].strVal
96- result = newCall (bindSym " ozarkWhereResult" ,
97- newLit (selectSql & " WHERE " & col & " != $1" ),
98- val
108+ var placeholders = newSeq [string ](vals.len)
109+ for i in 0 ..< vals.len:
110+ placeholders[i] = " $" & $ (i + 1 )
111+ result = newCall (
112+ bindSym " ozarkWhereInResult" ,
113+ newLit (selectSql & " WHERE " & col & " " & op & " (" & placeholders.join (" ," ) & " )" ),
99114 )
115+ for i in 0 ..< vals.len:
116+ # add the values as additional arguments to the
117+ # macro result for later use in code generation
118+ result .add (vals[i])
100119
101- macro orWhere * ( sql: untyped , col: static string , val: untyped ): untyped =
102- # # Define OR in WHERE clause
103- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkWhereResult " :
104- error (" The first argument to `orWhere ` must be the result of a `where ` macro." )
120+ proc writeWhereStatement (op: static string , sql: NimNode , col: string , val: NimNode ): NimNode {. compileTime .} =
121+ # Writer macro for simple WHERE clauses (e.g. `where`, `whereNot`) to avoid code duplication.
122+ if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult " :
123+ error (" The first argument to `where ` must be the result of a `select ` macro." )
105124 if col.validIdentifier:
106125 # todo check if column exists in model
107126 discard
108127 else :
109128 raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
110- let whereSql = sql[1 ].strVal
129+ let selectSql = sql[1 ].strVal
111130 result = newCall (bindSym " ozarkWhereResult" ,
112- newLit (whereSql & " OR " & col & " = $1" ),
131+ newLit (selectSql & " WHERE " & col & " " & op & " $1" ),
113132 val
114133 )
115134
116- macro whereStartsLike * (sql: untyped , col: static string , val: untyped ): untyped =
117- # # Define WHERE clause with LIKE for prefix matching
118- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
119- error (" The first argument to `whereLike` must be the result of a `select` macro." )
135+ proc writeOrWhereStatement (op: static string , sql: NimNode , col: string , val: NimNode ): NimNode {.compileTime .} =
136+ # Writer macro for `orWhere` to avoid code duplication with `writeWhereStatement`.
137+ # This macro checks that the first argument is a valid `where` result and then
138+ # appends the new condition with an OR to the existing SQL string.
139+ if sql.kind != nnkCall or sql[0 ].strVal != " ozarkWhereResult" :
140+ error (" The first argument to `orWhere` must be the result of a `where` macro." )
120141 if col.validIdentifier:
121142 # todo check if column exists in model
122143 discard
123144 else :
124145 raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
125- let selectSql = sql[1 ].strVal
146+ let whereSql = sql[1 ].strVal
126147 result = newCall (bindSym " ozarkWhereResult" ,
127- newLit (selectSql & " WHERE " & col & " LIKE $1" ),
128- nnkInfix. newTree ( ident " & " , val, newLit ( " % " ))
148+ newLit (whereSql & " OR " & col & " " & op & " $1" ),
149+ val
129150 )
130151
152+ # WHERE clause public macros
153+ macro where * (sql: untyped , col: static string , val: untyped ): untyped =
154+ # # Define WHERE clause
155+ writeWhereStatement (" =" , sql, col, val)
156+
157+ macro whereNot * (sql: untyped , col: static string , val: untyped ): untyped =
158+ # # Define WHERE clause with NOT
159+ writeWhereStatement (" !=" , sql, col, val)
160+
161+ macro orWhere * (sql: untyped , col: static string , val: untyped ): untyped =
162+ # # Define OR in WHERE clause
163+ writeOrWhereStatement (" =" , sql, col, val)
164+
165+ macro orWhereNot * (sql: untyped , col: static string , val: untyped ): untyped =
166+ # # Define OR with NOT in WHERE clause
167+ writeOrWhereStatement (" !=" , sql, col, val)
168+
169+ macro whereStartsLike * (sql: untyped , col: static string , val: untyped ): untyped =
170+ # # Define WHERE clause with LIKE for prefix matching
171+ writeWhereLikeStatements (" LIKE" , sql,
172+ nnkInfix.newTree (ident " &" , val, newLit (" %" )), col)
173+
131174macro whereEndsLike * (sql: untyped , col: static string , val: untyped ): untyped =
132175 # # Define WHERE clause with LIKE for suffix matching
133- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
134- error (" The first argument to `whereLike` must be the result of a `select` macro." )
135- if col.validIdentifier:
136- # todo check if column exists in model
137- discard
138- else :
139- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
140- let selectSql = sql[1 ].strVal
141- result = newCall (bindSym " ozarkWhereResult" ,
142- newLit (selectSql & " WHERE " & col & " LIKE $1" ),
143- nnkInfix.newTree (ident " &" , newLit (" %" ), val)
144- )
176+ writeWhereLikeStatements (" LIKE" , sql,
177+ nnkInfix.newTree (ident " &" , newLit (" %" ), val), col)
145178
146179macro whereLike * (sql: untyped , col: static string , val: untyped ): untyped =
147180 # # Define WHERE clause with LIKE for any position
148- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
149- error (" The first argument to `whereLikeAny` must be the result of a `select` macro." )
150- if col.validIdentifier:
151- # todo check if column exists in model
152- discard
153- else :
154- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
155- let selectSql = sql[1 ].strVal
156- result = newCall (bindSym " ozarkWhereResult" ,
157- newLit (selectSql & " WHERE " & col & " LIKE $1" ),
158- nnkInfix.newTree (
159- ident " &" ,
160- val,
161- newLit (" %" )
162- )
163- )
181+ writeWhereLikeStatements (" LIKE" , sql,
182+ nnkInfix.newTree (ident " &" , val, newLit (" %" )), col)
164183
165184macro whereNotLike * (sql: untyped , col: static string , val: untyped ): untyped =
166185 # # Define WHERE clause with NOT LIKE for any position
167- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
168- error (" The first argument to `whereNotLike` must be the result of a `select` macro." )
169- if col.validIdentifier:
170- # todo check if column exists in model
171- discard
172- else :
173- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
174- let selectSql = sql[1 ].strVal
175- result = newCall (bindSym " ozarkWhereResult" ,
176- newLit (selectSql & " WHERE " & col & " NOT LIKE $1;" ),
177- nnkInfix.newTree (
178- ident " &" ,
179- val,
180- newLit (" %" )
181- )
182- )
186+ writeWhereLikeStatements (" NOT LIKE" , sql,
187+ nnkInfix.newTree (ident " &" , val, newLit (" %" )), col)
183188
184189macro whereNotStartsLike * (sql: untyped , col: static string , val: untyped ): untyped =
185- # # Define WHERE clause with NOT LIKE for prefix matching
186- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
187- error (" The first argument to `whereNotStartsLike` must be the result of a `select` macro." )
188- if col.validIdentifier:
189- # todo check if column exists in model
190- discard
191- else :
192- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
193- let selectSql = sql[1 ].strVal
194- result = newCall (bindSym " ozarkWhereResult" ,
195- newLit (selectSql & " WHERE " & col & " NOT LIKE $1;" ),
196- nnkInfix.newTree (ident " &" , val, newLit (" %" ))
197- )
190+ # # Define WHERE clause with `NOT LIKE` for prefix matching
191+ writeWhereLikeStatements (" NOT LIKE" , sql,
192+ nnkInfix.newTree (ident " &" , val, newLit (" %" )), col)
198193
199194macro whereNotEndsLike * (sql: untyped , col: static string , val: untyped ): untyped =
200- # # Define WHERE clause with NOT LIKE for suffix matching
201- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
202- error (" The first argument to `whereNotEndsLike` must be the result of a `select` macro." )
203- if col.validIdentifier:
204- # todo check if column exists in model
205- discard
206- else :
207- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
208- let selectSql = sql[1 ].strVal
209- result = newCall (bindSym " ozarkWhereResult" ,
210- newLit (selectSql & " WHERE " & col & " NOT LIKE $1;" ),
211- nnkInfix.newTree (ident " &" , newLit (" %" ), val)
212- )
195+ # # Define WHERE clause with `NOT LIKE` for suffix matching
196+ writeWhereLikeStatements (" NOT LIKE" , sql,
197+ nnkInfix.newTree (ident " &" , newLit (" %" ), val), col)
213198
214199macro whereIn * (sql: untyped , col: static string , vals: openArray [untyped ]): untyped =
215200 # # Define WHERE clause with IN operator
216- if sql.kind != nnkCall or sql[0 ].strVal != " ozarkSelectResult" :
217- error (" The first argument to `whereIn` must be the result of a `select` macro." )
218- if col.validIdentifier:
219- # todo check if column exists in model
220- discard
221- else :
222- raise newException (OzarkModelDefect , " Invalid column name `" & col & " `" )
223- let selectSql = sql[1 ].strVal
224- var placeholders = newSeq [string ](vals.len)
225- for i in 0 ..< vals.len:
226- placeholders[i] = " $" & $ (i + 1 )
227- result = newCall (
228- bindSym " ozarkWhereInResult" ,
229- newLit (selectSql & " WHERE " & col & " IN (" & placeholders.join (" ," ) & " )" ),
230- )
231- for i in 0 ..< vals.len:
232- # add the values as additional arguments to the macro result for later use in code generation
233- result .add (vals[i])
201+ writeWhereInWhereNotIn (" IN" , sql, col, vals)
202+
203+ macro whereNotIn * (sql: untyped , col: static string , vals: openArray [untyped ]): untyped =
204+ # # Define WHERE clause with NOT IN operator
205+ writeWhereInWhereNotIn (" NOT IN" , sql, col, vals)
234206
235207template parseSqlQuery (getRowProcName: string , args: seq [NimNode ] = @ []) {.dirty .} =
236208 try :
0 commit comments