diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 0f96bb2a..85a6252f 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -4,10 +4,10 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: "1.20" - name: Test run: | go test $(go list ./... | grep -Ev "generator|internal") -race -coverprofile=coverage.txt -covermode=atomic diff --git a/.github/workflows/migrate.yml b/.github/workflows/migrate.yml index 47106d65..23dd114a 100644 --- a/.github/workflows/migrate.yml +++ b/.github/workflows/migrate.yml @@ -4,10 +4,10 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: "1.20" - name: Build run: go build -o /usr/local/bin/queryx cmd/queryx/main.go - uses: actions/upload-artifact@v3 @@ -18,10 +18,10 @@ jobs: needs: [build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: "1.20" - uses: actions/download-artifact@v3 with: name: bin @@ -59,10 +59,10 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: "1.20" - uses: actions/download-artifact@v3 with: name: bin @@ -99,10 +99,10 @@ jobs: --health-timeout 5s --health-retries 10 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: "1.20" - uses: actions/download-artifact@v3 with: name: bin diff --git a/generator/client/golang/templates/queryx.gotmpl b/generator/client/golang/templates/queryx.gotmpl index 0becc474..8b6bc83b 100644 --- a/generator/client/golang/templates/queryx.gotmpl +++ b/generator/client/golang/templates/queryx.gotmpl @@ -77,8 +77,8 @@ func (c *QXClient) Query{{ $m.Name }}() *{{ $m.Name }}Query { } {{- end }} -func (c *QXClient) Raw(fragment string, args ...interface{}) *queryx.Clause { - return queryx.NewClause(fragment , args) +func (c *QXClient) Raw(fragment string, args ...interface{}) *queryx.Clause { + return queryx.NewClause(fragment, args) } type Tx struct { diff --git a/generator/client/golang/templates/queryx/clause.go b/generator/client/golang/templates/queryx/clause.go index 1a21a11c..a5b03575 100644 --- a/generator/client/golang/templates/queryx/clause.go +++ b/generator/client/golang/templates/queryx/clause.go @@ -25,6 +25,10 @@ func (c *Clause) Err() error { } func (c *Clause) And(clauses ...*Clause) *Clause { + if len(clauses) == 0 { + return c + } + var fragments []string var args []interface{} clauses = append([]*Clause{c}, clauses...) @@ -33,13 +37,14 @@ func (c *Clause) And(clauses ...*Clause) *Clause { args = append(args, clause.args...) } - return &Clause{ - fragment: strings.Join(fragments, " AND "), - args: args, - } + return NewClause(strings.Join(fragments, " AND "), args) } func (c *Clause) Or(clauses ...*Clause) *Clause { + if len(clauses) == 0 { + return c + } + var fragments []string var args []interface{} clauses = append([]*Clause{c}, clauses...) @@ -48,8 +53,5 @@ func (c *Clause) Or(clauses ...*Clause) *Clause { args = append(args, clause.args...) } - return &Clause{ - fragment: strings.Join(fragments, " OR "), - args: args, - } + return NewClause(strings.Join(fragments, " OR "), args) } diff --git a/generator/client/golang/templates/queryx/select.go b/generator/client/golang/templates/queryx/select.go index 7b24aae8..fec8eeb8 100644 --- a/generator/client/golang/templates/queryx/select.go +++ b/generator/client/golang/templates/queryx/select.go @@ -34,21 +34,17 @@ func (s *SelectStatement) From(from string) *SelectStatement { return s } -func (s *SelectStatement) Where(expr ...*Clause) *SelectStatement { - var fragments []string - var args []interface{} - if s.where != nil { - fragments = append(fragments, fmt.Sprintf("(%s)", s.where.fragment)) - args = append(args, s.where.args...) - } - for _, clause := range expr { - fragments = append(fragments, fmt.Sprintf("(%s)", clause.fragment)) - args = append(args, clause.args...) +func (s *SelectStatement) Where(clauses ...*Clause) *SelectStatement { + if len(clauses) == 0 { + return s } - s.where = &Clause{ - fragment: strings.Join(fragments, " AND "), - args: args, + + if s.where == nil { + s.where = clauses[0].And(clauses[1:]...) + } else { + s.where = s.where.And(clauses...) } + return s } diff --git a/generator/client/golang/templates/queryx/select_test.go b/generator/client/golang/templates/queryx/select_test.go index 07e43c5e..5c4b8977 100644 --- a/generator/client/golang/templates/queryx/select_test.go +++ b/generator/client/golang/templates/queryx/select_test.go @@ -21,3 +21,15 @@ func TestSelect(t *testing.T) { require.Equal(t, `SELECT users.* FROM users LIMIT ?`, sql) require.Equal(t, []interface{}{1}, args) } + +func TestSelectWhere(t *testing.T) { + s1 := NewSelect().Select("users.*").From("users").Where(NewClause("id = ?", []interface{}{1})) + sql, args := s1.ToSQL() + require.Equal(t, `SELECT users.* FROM users WHERE id = ?`, sql) + require.Equal(t, []interface{}{1}, args) + + s1.Where(NewClause("name = ?", []interface{}{"test"})) + sql, args = s1.ToSQL() + require.Equal(t, `SELECT users.* FROM users WHERE (id = ?) AND (name = ?)`, sql) + require.Equal(t, []interface{}{1, "test"}, args) +} diff --git a/generator/client/typescript/templates/[model]/[model]_query.tstmpl b/generator/client/typescript/templates/[model]/[model]_query.tstmpl index acdaab89..c1ff697b 100644 --- a/generator/client/typescript/templates/[model]/[model]_query.tstmpl +++ b/generator/client/typescript/templates/[model]/[model]_query.tstmpl @@ -143,8 +143,8 @@ export class {{ $.model.Name }}Query { } where(...clauses: Clause[]) { - this.selectStatement.where(...clauses); - return this; + this.selectStatement.where(...clauses); + return this; } select(...selection: string[]) { diff --git a/generator/client/typescript/templates/queryx/clause.ts b/generator/client/typescript/templates/queryx/clause.ts index bdbff757..c4446288 100644 --- a/generator/client/typescript/templates/queryx/clause.ts +++ b/generator/client/typescript/templates/queryx/clause.ts @@ -10,6 +10,10 @@ export class Clause { } and(...clauses: Clause[]) { + if (clauses.length === 0) { + return this; + } + let fragment = this.fragment; let args = this.args; @@ -21,6 +25,10 @@ export class Clause { } or(...clauses: Clause[]) { + if (clauses.length === 0) { + return this; + } + let fragment = this.fragment; let args = this.args; diff --git a/generator/client/typescript/templates/queryx/client.tstmpl b/generator/client/typescript/templates/queryx/client.tstmpl index 01fc6aba..e3217524 100644 --- a/generator/client/typescript/templates/queryx/client.tstmpl +++ b/generator/client/typescript/templates/queryx/client.tstmpl @@ -48,7 +48,7 @@ export class QXClient { } {{- end }} - raw(fragment : string, ...args: any[]) { + raw(fragment: string, ...args: any[]) { return new Clause(fragment, args) } diff --git a/generator/client/typescript/templates/queryx/select.test.ts b/generator/client/typescript/templates/queryx/select.test.ts index 1ce63e72..fcb88afd 100644 --- a/generator/client/typescript/templates/queryx/select.test.ts +++ b/generator/client/typescript/templates/queryx/select.test.ts @@ -1,7 +1,22 @@ import { test, expect } from "vitest"; import { newSelect } from "./select"; +import { Clause } from "./clause"; test("select", () => { let s = newSelect().select("users.*").from("users"); expect(s.toSQL()).toEqual(["SELECT users.* FROM users", []]); }); + +test("select where", () => { + let s1 = newSelect() + .select("users.*") + .from("users") + .where(new Clause("id = ?", [1])); + expect(s1.toSQL()).toEqual(["SELECT users.* FROM users WHERE id = ?", [1]]); + + s1.where(new Clause("name = ?", ["test"])); + expect(s1.toSQL()).toEqual([ + "SELECT users.* FROM users WHERE (id = ?) AND (name = ?)", + [1, "test"], + ]); +}); diff --git a/generator/client/typescript/templates/queryx/select.ts b/generator/client/typescript/templates/queryx/select.ts index cdc7d3ac..fee184eb 100644 --- a/generator/client/typescript/templates/queryx/select.ts +++ b/generator/client/typescript/templates/queryx/select.ts @@ -31,18 +31,17 @@ export class SelectStatement { return this; } - where(...expr: Clause[]) { - let fragments:string[]=[]; - let args=[]; - if (this._where !== undefined) { - fragments.push(`(${this._where.fragment})`); - args.push(...this._where.args); + where(...clauses: Clause[]) { + if (clauses.length === 0) { + return this; } - for (let i = 0; i < expr.length; i++) { - fragments.push(`(${expr[i].fragment})`); - args.push(...expr[i].args); + + if (this._where === undefined) { + this._where = clauses[0].and(...clauses.slice(1)); + } else { + this._where = this._where.and(...clauses); } - this._where=new Clause(fragments.join(" AND "),args) + return this; } diff --git a/internal/integration/client.test.ts b/internal/integration/client.test.ts index 27c2f3c6..c97a1ec9 100644 --- a/internal/integration/client.test.ts +++ b/internal/integration/client.test.ts @@ -251,13 +251,19 @@ test("inEmpty", async () => { }); test("where", async () => { - let user = await c.queryUser().create({ weight:"98.0",name: "name" ,type:"type"}); - let users = await c.queryUser().where(c.userID.eq(user.id)).where(c.userName.eq("name"),c.userType.eq("type")).all() - expect(users.length).toEqual(1); + let user = await c.queryUser().create({ name: "name", type: "type" }); + let users = await c + .queryUser() + .where(c.userID.eq(user.id)) + .where(c.userName.eq("name"), c.userType.eq("type")) + .all(); + expect(users).toEqual([user]); - let u = await c.queryUser().where(c.raw("name = ? and type = ?", "name","type")).all(); - expect(u[0].name).toEqual("name"); - expect(u[0].type).toEqual("type"); + users = await c + .queryUser() + .where(c.raw("name = ? and type = ?", "name", "type")) + .all(); + expect(users).toEqual([user]); }); test("hasManyEmpty", async () => { diff --git a/internal/integration/client_test.go b/internal/integration/client_test.go index cf26aff1..7c74b515 100644 --- a/internal/integration/client_test.go +++ b/internal/integration/client_test.go @@ -326,17 +326,17 @@ func TestInEmpty(t *testing.T) { } func TestWhere(t *testing.T) { - user, err := c.QueryUser().Create(c.ChangeUser().SetWeight(98.0).SetName("name").SetType("type")) + user, err := c.QueryUser().Create(c.ChangeUser().SetName("name").SetType("type")) require.NoError(t, err) users, err := c.QueryUser().Where(c.UserID.EQ(user.ID)).Where(c.UserName.EQ("name"), c.UserType.EQ("type")).All() require.NoError(t, err) - require.NotNil(t, users) require.Equal(t, 1, len(users)) + require.Equal(t, user, users[0]) - user, err = c.QueryUser().Where(c.Raw("name = ? and type = ?", "name", "type")).First() + users, err = c.QueryUser().Where(c.Raw("name = ? and type = ?", "name", "type")).All() require.NoError(t, err) - require.Equal(t, "name", user.Name.Val) - require.Equal(t, "type", user.Type.Val) + require.Equal(t, 1, len(users)) + require.Equal(t, user, users[0]) } func TestHasManyEmpty(t *testing.T) {