Skip to content

Commit 420a698

Browse files
feat: adds the ability to control SelectBuilder
1 parent f382a96 commit 420a698

File tree

5 files changed

+115
-12
lines changed

5 files changed

+115
-12
lines changed

builder.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
type Builder interface {
1111
// Build builds sql query
12-
Build(ctx context.Context, query *qparser.Query) (Sqlizer, error)
12+
Build(ctx context.Context, query *qparser.Query, sb ...*SelectBuilder) (*SelectBuilder, error)
1313
}
1414

1515
// Extension is used in order to extend a builder
@@ -54,9 +54,20 @@ func NewResourceSelectBuilder(
5454
}
5555

5656
// Build builds sql query which depends on the applied options
57-
func (s *ResourceSelectBuilder) Build(ctx context.Context, query *qparser.Query) (Sqlizer, error) {
58-
var selectFields []string
59-
sb := new(SelectBuilder)
57+
func (s *ResourceSelectBuilder) Build(
58+
ctx context.Context,
59+
query *qparser.Query,
60+
sb ...*SelectBuilder,
61+
) (*SelectBuilder, error) {
62+
var (
63+
selectFields []string
64+
b *SelectBuilder
65+
)
66+
if len(sb) > 0 {
67+
b = sb[0]
68+
} else {
69+
b = new(SelectBuilder)
70+
}
6071
if fields, ok := query.Fields.FieldsByResource(s.resourceName); ok {
6172
fields, err := s.translator(fields)
6273
if err != nil {
@@ -71,15 +82,15 @@ func (s *ResourceSelectBuilder) Build(ctx context.Context, query *qparser.Query)
7182
return nil, fmt.Errorf("field %q not allowed for selection criteria", field)
7283
}
7384
}
74-
sb.Select(selectFields).From(s.resourceName)
85+
b.Select(selectFields).From(s.resourceName)
7586
conditions, err := s.retrieveFilterConditions(query)
7687
if err != nil {
7788
return nil, err
7889
}
79-
if len(conditions) == 0 {
80-
sb.Where(alwaysTrue)
90+
if len(conditions) == 0 && len(b.WhereParts) == 0 {
91+
b.Where(alwaysTrue)
8192
} else {
82-
sb.Where(conditions...)
93+
b.Where(conditions...)
8394
}
8495
sortList := make([]qparser.Sort, len(query.Sort))
8596
sortFields := make([]string, len(query.Sort))
@@ -105,14 +116,14 @@ func (s *ResourceSelectBuilder) Build(ctx context.Context, query *qparser.Query)
105116
sortList[i].FieldName = sortFields[i]
106117
}
107118
if len(sortList) > 0 {
108-
sb.OrderBy(OrderBy(sortList))
119+
b.OrderBy(OrderBy(sortList))
109120
}
110121
for _, extension := range s.extensions {
111-
if err = extension(ctx, query, sb); err != nil {
122+
if err = extension(ctx, query, b); err != nil {
112123
return nil, err
113124
}
114125
}
115-
return sb, nil
126+
return b, nil
116127
}
117128

118129
func (s *ResourceSelectBuilder) retrieveFilterConditions(query *qparser.Query) ([]Sqlizer, error) {

builder_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type resourceBuilderTest struct {
1515
sql string
1616
args []interface{}
1717
expectedErr bool
18+
sb func() *SelectBuilder
1819
}
1920

2021
const (
@@ -85,6 +86,16 @@ var resourceBuilderTests = []resourceBuilderTest{
8586
query: fmt.Sprintf("fields[%s]=updatedAt", resourceName),
8687
expectedErr: true,
8788
},
89+
{
90+
title: "With extra params",
91+
query: fmt.Sprintf("fields[%s]=%s,%s", resourceName, resourceFieldID, resourceFieldTitle),
92+
sql: fmt.Sprintf("SELECT %s, %s FROM %s WHERE id = ?", resourceFieldID, resourceFieldTitle, resourceName),
93+
args: []interface{}{"1"},
94+
sb: func() *SelectBuilder {
95+
sb := new(SelectBuilder)
96+
return sb.Where(&RawSqlWithArgs{"id = ?", []interface{}{"1"}})
97+
},
98+
},
8899
}
89100

90101
func TestNewResourceSelectBuilder(t *testing.T) {
@@ -149,7 +160,11 @@ func TestNewResourceSelectBuilder(t *testing.T) {
149160
if err != nil {
150161
t.Fatalf("%sqparser.ParseQuery(%q) returned unexpected error: %s", meta, tt.query, err)
151162
}
152-
sqlizer, err := builder.Build(ctx, query)
163+
var sb []*SelectBuilder
164+
if tt.sb != nil {
165+
sb = []*SelectBuilder{tt.sb()}
166+
}
167+
sqlizer, err := builder.Build(ctx, query, sb...)
153168
if !tt.expectedErr && err != nil {
154169
t.Errorf("%sunexpected error %s", meta, err)
155170
continue
File renamed without changes.

examples/custom_params/main.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/velmie/qparser"
7+
"log"
8+
9+
"github.com/velmie/q2sql"
10+
"github.com/velmie/q2sql/condition"
11+
"github.com/velmie/q2sql/extension"
12+
)
13+
14+
func main() {
15+
translator := q2sql.MapTranslator(map[string]string{
16+
"id": "id",
17+
"title": "title",
18+
"body": "body",
19+
"author": "author",
20+
"createdAt": "created_at",
21+
})
22+
23+
allowedConditionsByField := q2sql.AllowedConditions{
24+
"id": []string{condition.NameIn},
25+
}
26+
builder := q2sql.NewResourceSelectBuilder(
27+
"articles",
28+
translator,
29+
q2sql.AllowSelectFields([]string{"id", "title", "author"}),
30+
q2sql.AllowFiltering(
31+
allowedConditionsByField,
32+
condition.DefaultConditionMap,
33+
q2sql.DefaultFilterExpressionParser,
34+
),
35+
q2sql.AllowSortingByFields([]string{"created_at", "title"}),
36+
q2sql.Extend(extension.LimitOffsetPagination(extension.Unlimited, extension.Unlimited)),
37+
)
38+
39+
qstr := "?fields[articles]=id,title,author&filter[id]=in:1,2,3,4,5&sort=-createdAt,title&page[limit]=100"
40+
query, _ := qparser.ParseQuery(qstr)
41+
42+
// It's possible to pass select builder
43+
sb := new(q2sql.SelectBuilder)
44+
// and define custom conditions
45+
sb.Where(&q2sql.Eq{"author", "Alan Turing"})
46+
47+
// not necessary to declare new variable since the "sb" already points to the select builder
48+
_, err := builder.Build(context.Background(), query, sb)
49+
if err != nil {
50+
log.Fatal("failed to build query", err)
51+
}
52+
// or rewrite some parts, for example the line below clears sorting
53+
sb.OrderByParts = nil
54+
55+
sqlStr, args, err := sb.ToSql()
56+
if err != nil {
57+
log.Fatal("failed to build SQL query", err)
58+
}
59+
fmt.Println(sqlStr)
60+
fmt.Println(args)
61+
// prints
62+
/*
63+
SELECT id, title, author FROM articles WHERE author = ? AND id IN (?,?,?,?,?) LIMIT 100
64+
[Alan Turing 1 2 3 4 5]
65+
*/
66+
}

readme.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,14 @@ The Extension accesses * q2sql.SelectBuilder and can use it to modify the result
208208
[1 2 3 4 5]
209209
*/
210210
```
211+
212+
In order to apply custom conditions you may pass select builder to the resource select builder.
213+
214+
```go
215+
sb := new(q2sql.SelectBuilder)
216+
sb.Where(&q2sql.Eq{"author", "Alan Turing"})
217+
218+
_, err := builder.Build(context.Background(), query, sb)
219+
...
220+
221+
```

0 commit comments

Comments
 (0)