1
1
package httpapi
2
2
3
3
import (
4
+ "database/sql"
4
5
"errors"
5
6
"fmt"
6
7
"net/url"
@@ -104,6 +105,27 @@ func (p *QueryParamParser) PositiveInt32(vals url.Values, def int32, queryParam
104
105
return v
105
106
}
106
107
108
+ // NullableBoolean will return a null sql value if no input is provided.
109
+ // SQLc still uses sql.NullBool rather than the generic type. So converting from
110
+ // the generic type is required.
111
+ func (p * QueryParamParser )NullableBoolean (vals url.Values ,def sql.NullBool ,queryParam string ) sql.NullBool {
112
+ v ,err := parseNullableQueryParam [bool ](p ,vals ,strconv .ParseBool , sql.Null [bool ]{
113
+ V :def .Bool ,
114
+ Valid :def .Valid ,
115
+ },queryParam )
116
+ if err != nil {
117
+ p .Errors = append (p .Errors , codersdk.ValidationError {
118
+ Field :queryParam ,
119
+ Detail :fmt .Sprintf ("Query param %q must be a valid boolean: %s" ,queryParam ,err .Error ()),
120
+ })
121
+ }
122
+
123
+ return sql.NullBool {
124
+ Bool :v .V ,
125
+ Valid :v .Valid ,
126
+ }
127
+ }
128
+
107
129
func (p * QueryParamParser )Boolean (vals url.Values ,def bool ,queryParam string )bool {
108
130
v ,err := parseQueryParam (p ,vals ,strconv .ParseBool ,def ,queryParam )
109
131
if err != nil {
@@ -294,9 +316,34 @@ func ParseCustomList[T any](parser *QueryParamParser, vals url.Values, def []T,
294
316
return v
295
317
}
296
318
319
+ func parseNullableQueryParam [T any ](parser * QueryParamParser ,vals url.Values ,parse func (v string ) (T ,error ),def sql.Null [T ],queryParam string ) (sql.Null [T ],error ) {
320
+ setParse := parseSingle (parser ,parse ,def .V ,queryParam )
321
+ return parseQueryParamSet [sql.Null [T ]](parser ,vals ,func (set []string ) (sql.Null [T ],error ) {
322
+ if len (set )== 0 {
323
+ return sql.Null [T ]{
324
+ Valid :false ,
325
+ },nil
326
+ }
327
+
328
+ value ,err := setParse (set )
329
+ if err != nil {
330
+ return sql.Null [T ]{},err
331
+ }
332
+ return sql.Null [T ]{
333
+ V :value ,
334
+ Valid :true ,
335
+ },nil
336
+ },def ,queryParam )
337
+ }
338
+
297
339
// parseQueryParam expects just 1 value set for the given query param.
298
340
func parseQueryParam [T any ](parser * QueryParamParser ,vals url.Values ,parse func (v string ) (T ,error ),def T ,queryParam string ) (T ,error ) {
299
- setParse := func (set []string ) (T ,error ) {
341
+ setParse := parseSingle (parser ,parse ,def ,queryParam )
342
+ return parseQueryParamSet (parser ,vals ,setParse ,def ,queryParam )
343
+ }
344
+
345
+ func parseSingle [T any ](parser * QueryParamParser ,parse func (v string ) (T ,error ),def T ,queryParam string )func (set []string ) (T ,error ) {
346
+ return func (set []string ) (T ,error ) {
300
347
if len (set )> 1 {
301
348
// Set as a parser.Error rather than return an error.
302
349
// Returned errors are errors from the passed in `parse` function, and
@@ -311,7 +358,6 @@ func parseQueryParam[T any](parser *QueryParamParser, vals url.Values, parse fun
311
358
}
312
359
return parse (set [0 ])
313
360
}
314
- return parseQueryParamSet (parser ,vals ,setParse ,def ,queryParam )
315
361
}
316
362
317
363
func parseQueryParamSet [T any ](parser * QueryParamParser ,vals url.Values ,parse func (set []string ) (T ,error ),def T ,queryParam string ) (T ,error ) {