Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.

Commit

Permalink
Merge pull request #74 from dadleyy/GH-73/inclusive
Browse files Browse the repository at this point in the history
adding "inclusive" field to blueprints for "OR" clauses
  • Loading branch information
dadleyy authored Nov 24, 2017
2 parents 3c207c6 + 0daa175 commit 45af02c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 29 deletions.
17 changes: 13 additions & 4 deletions examples/library/models/author_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func Test_Author(t *testing.T) {
IDRange: []int{1, 2},
})

g.Assert(r).Equal("WHERE authors.system_id > ? AND authors.system_id < ?")
g.Assert(r).Equal("WHERE (authors.system_id > ? AND authors.system_id < ?)")
})

g.It("supports in on uint column querying", func() {
Expand All @@ -88,12 +88,12 @@ func Test_Author(t *testing.T) {

g.It("supports range on uint column querying", func() {
r := fmt.Sprintf("%s", &AuthorBlueprint{AuthorFlagsRange: []uint8{1, 2}})
g.Assert(r).Equal("WHERE authors.flags > ? AND authors.flags < ?")
g.Assert(r).Equal("WHERE (authors.flags > ? AND authors.flags < ?)")
})

g.It("supports range on float64 column querying", func() {
r := fmt.Sprintf("%s", &AuthorBlueprint{ReaderRatingRange: []float64{1, 2}})
g.Assert(r).Equal("WHERE authors.rating > ? AND authors.rating < ?")
g.Assert(r).Equal("WHERE (authors.rating > ? AND authors.rating < ?)")
})

g.It("supports 'IN' on float64 column querying", func() {
Expand All @@ -112,9 +112,18 @@ func Test_Author(t *testing.T) {
IDRange: []int{1, 4},
})

g.Assert(r).Equal("WHERE authors.system_id IN (?,?,?) AND authors.system_id > ? AND authors.system_id < ?")
g.Assert(r).Equal("WHERE authors.system_id IN (?,?,?) AND (authors.system_id > ? AND authors.system_id < ?)")
})

g.It("supports making a blueprint inclusive", func() {
r := fmt.Sprintf("%s", &AuthorBlueprint{
NameLike: []string{"%rodger%"},
IDRange: []int{1, 4},
Inclusive: true,
})

g.Assert(r).Equal("WHERE (authors.system_id > ? AND authors.system_id < ?) OR authors.name LIKE ?")
})
})

g.Describe("Author model & generated store test suite", func() {
Expand Down
10 changes: 10 additions & 0 deletions examples/library/models/book_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ func Test_Book(t *testing.T) {
str := fmt.Sprintf("%s", &BookBlueprint{TitleLike: []string{"b"}})
g.Assert(str).Equal("WHERE books.title LIKE ?")
})

g.It("allows inclusive (OR) blueprints", func() {
str := fmt.Sprintf("%s", &BookBlueprint{
TitleLike: []string{"b", "c"},
IDRange: []int{1, 2},
Inclusive: true,
})
expected := "WHERE (books.system_id > ? AND books.system_id < ?) OR books.title LIKE ? OR books.title LIKE ?"
g.Assert(str).Equal(expected)
})
})

g.Describe("Book model & generated store", func() {
Expand Down
57 changes: 39 additions & 18 deletions examples/library/models/genre_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,31 @@ func Test_Genre(t *testing.T) {
store = NewGenreStore(db)
})

g.It("uses the postgres dialect for blueprint string in params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{Name: []string{"horror", "comedy"}})
g.Assert(s).Equal("WHERE genres.name IN ($1,$2)")
})
g.Describe("genre blueprint test suite", func() {
g.It("supports ors between string like clauses when inclusive", func() {
a := fmt.Sprintf("%s", &GenreBlueprint{NameLike: []string{"hi", "bye"}, Inclusive: true})
g.Assert(a).Equal("WHERE genres.name LIKE $1 OR genres.name LIKE $2")
})

g.It("uses the postgres dialect for blueprint int in params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{ID: []uint{0, 10}})
g.Assert(s).Equal("WHERE genres.id IN ($1,$2)")
})
g.It("uses the postgres dialect for blueprint string in params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{Name: []string{"horror", "comedy"}})
g.Assert(s).Equal("WHERE genres.name IN ($1,$2)")
})

g.It("uses the postgres dialect for blueprint int range params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{IDRange: []uint{0, 10}})
g.Assert(s).Equal("WHERE genres.id > $1 AND genres.id < $2")
})
g.It("uses the postgres dialect for blueprint int in params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{ID: []uint{0, 10}})
g.Assert(s).Equal("WHERE genres.id IN ($1,$2)")
})

g.It("uses the postgres dialect for blueprint int range params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{IDRange: []uint{0, 10}})
g.Assert(s).Equal("WHERE (genres.id > $1 AND genres.id < $2)")
})

g.It("uses the postgres dialect for blueprint string like params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{NameLike: []string{"danny"}})
g.Assert(s).Equal("WHERE genres.name LIKE $1")
g.It("uses the postgres dialect for blueprint string like params", func() {
s := fmt.Sprintf("%s", &GenreBlueprint{NameLike: []string{"danny"}})
g.Assert(s).Equal("WHERE genres.name LIKE $1")
})
})

g.It("allows user to create genres", func() {
Expand Down Expand Up @@ -87,10 +94,24 @@ func Test_Genre(t *testing.T) {
{Name: "Comedy"},
{Name: "Literature"},
{Name: "Science Fiction", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
{Name: "History", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
{Name: "Western European History", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
{Name: "Eastern European History", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
{Name: "South American History", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
{Name: "North American History", ParentID: sql.NullInt64{Valid: true, Int64: 10}},
}...)
g.Assert(e).Equal(nil)
})

g.It("supports or-ing clauses when blueprint set to be inclusive", func() {
genres, e := store.FindGenres(&GenreBlueprint{
NameLike: []string{"%European%", "%American%"},
Inclusive: true,
})
g.Assert(e).Equal(nil)
g.Assert(len(genres)).Equal(4)
})

g.It("supports selecting parent ids", func() {
parents, e := store.SelectParentIDs(&GenreBlueprint{
ID: []uint{uint(lastID)},
Expand All @@ -106,7 +127,7 @@ func Test_Genre(t *testing.T) {
ParentID: []sql.NullInt64{},
})
g.Assert(e).Equal(nil)
g.Assert(c).Equal(1)
g.Assert(c).Equal(6)
})

g.It("allows counting w/ valid NullInt64 blueprint", func() {
Expand All @@ -116,7 +137,7 @@ func Test_Genre(t *testing.T) {
ParentID: []sql.NullInt64{p},
})
g.Assert(e).Equal(nil)
g.Assert(children).Equal(1)
g.Assert(children).Equal(6)
})

g.It("allows counting w/ nil NullInt64 blueprint", func() {
Expand Down Expand Up @@ -153,7 +174,7 @@ func Test_Genre(t *testing.T) {
IDRange: []uint{0, 10},
})
g.Assert(e).Equal(nil)
g.Assert(len(genres)).Equal(4)
g.Assert(len(genres)).Equal(9)
})

g.It("allows updating the genre name", func() {
Expand Down
30 changes: 23 additions & 7 deletions marlow/blueprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func writeBlueprint(destination io.Writer, record marlowRecord) error {
out.Println("%s []%s", name, fieldType)
}

out.Println("Inclusive bool")
out.Println("Limit int")
out.Println("Offset int")
out.Println("OrderBy string")
Expand Down Expand Up @@ -81,7 +82,8 @@ func writeBlueprint(destination io.Writer, record marlowRecord) error {
wg.Done()
}()

for name, config := range record.fields {
for _, f := range record.fieldList() {
name, config := f.name, record.fields[f.name]
fieldGenerators := fieldMethods(record, name, config, methodReceiver)

if len(fieldGenerators) == 0 {
Expand All @@ -99,11 +101,12 @@ func writeBlueprint(destination io.Writer, record marlowRecord) error {
wg.Wait()

symbols := struct {
clauseMap string
clauseSlice string
clauseItem string
valueCount string
values string
}{"_clauses", "_item", "_count", "_values"}
}{"_map", "_clauses", "_item", "_count", "_values"}

// With all of our fields having generated non-exported clause generation methods on our struct, we can create the
// final 'String' method which iterates over all of these, calling them and adding the non-empty string clauses to
Expand All @@ -124,7 +127,13 @@ func writeBlueprint(destination io.Writer, record marlowRecord) error {
return out.Returns(writing.EmptyString)
}, symbols.clauseSlice)

return out.Returns(fmt.Sprintf("\"WHERE \" + strings.Join(%s, \" AND \")", symbols.clauseSlice))
out.Println("%s := \" AND \"", symbols.clauseMap)

out.WithIf("%s.Inclusive == true", func(url.Values) error {
return out.Println("%s = \" OR \"", symbols.clauseMap)
}, scope.Get("receiver"))

return out.Returns(fmt.Sprintf("\"WHERE \" + strings.Join(%s, %s)", symbols.clauseSlice, symbols.clauseMap))
})

if e != nil {
Expand Down Expand Up @@ -348,13 +357,14 @@ func stringMethods(record marlowRecord, fieldName string, fieldConfig url.Values
columnReference := fmt.Sprintf("%s.%s", record.table(), columnName)

symbols := struct {
conjunction string
placeholders string
item string
values string
statement string
count string
index string
}{"_placeholders", "_value", "_values", "_like", "_count", "_i"}
}{"_conjunc", "_placeholders", "_value", "_values", "_like", "_count", "_i"}

if record.dialect() != "postgres" {
symbols.index = "_"
Expand Down Expand Up @@ -394,7 +404,13 @@ func stringMethods(record marlowRecord, fieldName string, fieldConfig url.Values
return writer.Println("%s = append(%s, %s)", symbols.values, symbols.values, symbols.item)
}, symbols.index, symbols.item, likeSlice)

clauseString := fmt.Sprintf("strings.Join(%s, \" AND \")", symbols.placeholders)
writer.Println("%s := \" AND \"", symbols.conjunction)

writer.WithIf("%s.Inclusive == true", func(url.Values) error {
return writer.Println("%s = \" OR \"", symbols.conjunction)
}, scope.Get("receiver"))

clauseString := fmt.Sprintf("strings.Join(%s, %s)", symbols.placeholders, symbols.conjunction)
return writer.Returns(clauseString, symbols.values)
})

Expand Down Expand Up @@ -448,7 +464,7 @@ func numericalMethods(record marlowRecord, fieldName string, fieldConfig url.Val

if record.dialect() == "postgres" {
rangeString := fmt.Sprintf(
"fmt.Sprintf(\"%s > $%%d AND %s < $%%d\", %s, %s+1)",
"fmt.Sprintf(\"(%s > $%%d AND %s < $%%d)\", %s, %s+1)",
columnReference,
columnReference,
symbols.count,
Expand All @@ -458,7 +474,7 @@ func numericalMethods(record marlowRecord, fieldName string, fieldConfig url.Val
return writer.Returns(rangeString, symbols.values)
}

return writer.Returns(fmt.Sprintf("\"%s > ? AND %s < ?\"", columnReference, columnReference), symbols.values)
return writer.Returns(fmt.Sprintf("\"(%s > ? AND %s < ?)\"", columnReference, columnReference), symbols.values)
})

if e == nil {
Expand Down

0 comments on commit 45af02c

Please sign in to comment.