Pārlūkot izejas kodu

添加组装sql语句的接口

yjp 1 gadu atpakaļ
vecāks
revīzija
6720b3a8f6

+ 6 - 0
framework/core/infrastructure/database/clause/clause.go

@@ -0,0 +1,6 @@
+package clause
+
+type Clause interface {
+	Clause() (string, error)
+	Args() []any
+}

+ 178 - 0
framework/core/infrastructure/database/clause/condition.go

@@ -0,0 +1,178 @@
+package clause
+
+import "strings"
+
+type Conditions struct {
+	queries []string
+	args    [][]any
+	err     error
+}
+
+func NewConditions() *Conditions {
+	return &Conditions{
+		queries: make([]string, 0),
+		args:    make([][]any, 0),
+	}
+}
+
+func (conditions *Conditions) AddCondition(query string, args ...any) *Conditions {
+	conditions.queries = append(conditions.queries, query)
+	conditions.args = append(conditions.args, args)
+	return conditions
+}
+
+func (conditions *Conditions) Equal(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" = ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) Like(columnName string, arg string) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" LIKE ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) In(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" IN ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) NotIn(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" NOT IN ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) Not(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" != ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) LessThan(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" < ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) LessThanAndEqual(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" <= ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) GreaterThan(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" > ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) GreaterThanAndEqual(columnName string, arg any) *Conditions {
+	if conditions.err != nil {
+		return conditions
+	}
+
+	conditions.queries = append(conditions.queries, "\""+columnName+"\" >= ?")
+	conditions.args = append(conditions.args, []any{arg})
+	return conditions
+}
+
+func (conditions *Conditions) And() *And {
+	return &And{conditions: conditions}
+}
+
+func (conditions *Conditions) Or() *Or {
+	return &Or{conditions: conditions}
+}
+
+func (conditions *Conditions) formClause(conditionOperator string) (string, error) {
+	if conditions.queries == nil || len(conditions.queries) == 0 {
+		return "", nil
+	}
+
+	stringBuilder := strings.Builder{}
+	for i, query := range conditions.queries {
+		stringBuilder.WriteString(query)
+
+		if i != len(conditions.queries)-1 {
+			stringBuilder.WriteString(" " + conditionOperator + " ")
+		}
+	}
+
+	return stringBuilder.String(), nil
+}
+
+func (conditions *Conditions) formArgs() []any {
+	args := make([]any, 0)
+	for _, conditionArgs := range conditions.args {
+		if conditionArgs == nil {
+			continue
+		}
+
+		if len(conditionArgs) == 1 {
+			args = append(args, conditionArgs[0])
+		} else {
+			args = append(args, conditionArgs)
+		}
+	}
+
+	return args
+}
+
+type And struct {
+	conditions *Conditions
+}
+
+func (and *And) Clause() (string, error) {
+	return and.conditions.formClause("AND")
+}
+
+func (and *And) Args() []any {
+	return and.conditions.formArgs()
+}
+
+type Or struct {
+	conditions *Conditions
+}
+
+func (or *Or) Clause() (string, error) {
+	return or.conditions.formClause("OR")
+}
+
+func (or *Or) Args() []any {
+	return or.conditions.formArgs()
+}

+ 41 - 0
framework/core/infrastructure/database/clause/from.go

@@ -0,0 +1,41 @@
+package clause
+
+import "strings"
+
+type From struct {
+	otherClauses []Clause
+}
+
+func NewFrom(otherClauses []Clause) *From {
+	return &From{
+		otherClauses: otherClauses,
+	}
+}
+
+func (clause *From) Clause() (string, error) {
+	otherClauseBuilder := strings.Builder{}
+	for _, otherClause := range clause.otherClauses {
+		otherClauseStr, err := otherClause.Clause()
+		if err != nil {
+			return "", err
+		}
+
+		otherClauseBuilder.WriteString("  " + otherClauseStr)
+	}
+
+	clauseBuilder := strings.Builder{}
+	clauseBuilder.WriteString("FROM\n")
+	clauseBuilder.WriteString(otherClauseBuilder.String())
+
+	return clauseBuilder.String(), nil
+}
+
+func (clause *From) Args() []any {
+	args := make([]any, 0)
+
+	for _, otherClause := range clause.otherClauses {
+		args = append(args, otherClause.Args()...)
+	}
+
+	return args
+}

+ 45 - 0
framework/core/infrastructure/database/clause/join.go

@@ -0,0 +1,45 @@
+package clause
+
+import "strings"
+
+type Join struct {
+	joinType  string
+	tableName string
+	on        string
+}
+
+func NewJoin(tableName string, on string) *Join {
+	return &Join{
+		joinType:  "JOIN",
+		tableName: tableName,
+		on:        on,
+	}
+}
+
+func (clause *Join) Left() *Join {
+	clause.joinType = "LEFT JOIN"
+	return clause
+}
+
+func (clause *Join) Right() *Join {
+	clause.joinType = "RIGHT JOIN"
+	return clause
+}
+
+func (clause *Join) Inner() *Join {
+	clause.joinType = "INNER JOIN"
+	return clause
+}
+
+func (clause *Join) Clause() (string, error) {
+	clauseBuilder := strings.Builder{}
+	clauseBuilder.WriteString(clause.joinType)
+	clauseBuilder.WriteString(" " + clause.tableName)
+	clauseBuilder.WriteString(" ON ")
+	clauseBuilder.WriteString(clause.on + "\n")
+	return clauseBuilder.String(), nil
+}
+
+func (clause *Join) Args() []any {
+	return make([]any, 0)
+}

+ 37 - 0
framework/core/infrastructure/database/clause/limit.go

@@ -0,0 +1,37 @@
+package clause
+
+type Limit struct {
+	limit  int
+	offset int
+}
+
+func NewLimit(pageNo int, pageSize int) *Limit {
+	limit := -1
+	offset := -1
+
+	if pageNo != 0 && pageSize != 0 {
+		limit = pageSize
+		offset = (pageNo - 1) * pageSize
+	}
+
+	return &Limit{
+		limit:  limit,
+		offset: offset,
+	}
+}
+
+func (limit *Limit) Clause() (string, error) {
+	if limit.limit == -1 || limit.offset == -1 {
+		return "", nil
+	}
+
+	return `LIMIT ? OFFSET ?`, nil
+}
+
+func (limit *Limit) Args() []any {
+	if limit.limit == -1 || limit.offset == -1 {
+		return make([]any, 0)
+	}
+
+	return []any{limit.limit, limit.offset}
+}

+ 69 - 0
framework/core/infrastructure/database/clause/select.go

@@ -0,0 +1,69 @@
+package clause
+
+import "strings"
+
+type Select struct {
+	selectClauses []string
+	fromClause    *From
+	otherClauses  []Clause
+}
+
+func NewSelect(selectClauses []string, fromClause *From, otherClauses ...Clause) *Select {
+	return &Select{
+		selectClauses: selectClauses,
+		fromClause:    fromClause,
+		otherClauses:  otherClauses,
+	}
+}
+
+func (clause *Select) Clause() (string, error) {
+	selectClauseBuilder := strings.Builder{}
+	if clause.selectClauses == nil || len(clause.selectClauses) == 0 {
+		selectClauseBuilder.WriteString("*\n")
+	} else {
+		for i, selectClause := range clause.selectClauses {
+			selectClauseBuilder.WriteString("  " + selectClause)
+
+			if i < len(clause.selectClauses)-1 {
+				selectClauseBuilder.WriteString(",\n")
+			} else {
+				selectClauseBuilder.WriteString("\n")
+			}
+		}
+	}
+
+	fromClause, err := clause.fromClause.Clause()
+	if err != nil {
+		return "", err
+	}
+
+	otherClauseBuilder := strings.Builder{}
+	for _, otherClause := range clause.otherClauses {
+		otherClauseStr, err := otherClause.Clause()
+		if err != nil {
+			return "", err
+		}
+
+		otherClauseBuilder.WriteString(otherClauseStr)
+	}
+
+	clauseBuilder := strings.Builder{}
+	clauseBuilder.WriteString("SELECT\n")
+	clauseBuilder.WriteString(selectClauseBuilder.String())
+	clauseBuilder.WriteString(fromClause)
+	clauseBuilder.WriteString(otherClauseBuilder.String())
+
+	return clauseBuilder.String(), nil
+}
+
+func (clause *Select) Args() []any {
+	args := make([]any, 0)
+
+	args = append(args, clause.fromClause.Args()...)
+
+	for _, otherClause := range clause.otherClauses {
+		args = append(args, otherClause.Args()...)
+	}
+
+	return args
+}

+ 11 - 0
framework/core/infrastructure/database/clause/table_name.go

@@ -0,0 +1,11 @@
+package clause
+
+type TableName string
+
+func (s TableName) Clause() (string, error) {
+	return string(s + "\n"), nil
+}
+
+func (s TableName) Args() []any {
+	return make([]any, 0)
+}

+ 55 - 0
framework/core/infrastructure/database/clause/where.go

@@ -0,0 +1,55 @@
+package clause
+
+import "strings"
+
+type Where struct {
+	conditions []Clause
+}
+
+func NewWhere(conditions []Clause) *Where {
+	return &Where{
+		conditions: conditions,
+	}
+}
+
+func (clause *Where) Clause() (string, error) {
+	conditionClauseBuilder := strings.Builder{}
+	conditionClauseBuilder.WriteString("  ")
+	for i, condition := range clause.conditions {
+		if len(clause.conditions) > 1 {
+			conditionClauseBuilder.WriteString("(")
+		}
+
+		conditionClauseStr, err := condition.Clause()
+		if err != nil {
+			return "", err
+		}
+
+		conditionClauseBuilder.WriteString(conditionClauseStr)
+
+		if len(clause.conditions) > 1 {
+			conditionClauseBuilder.WriteString(")")
+		}
+
+		if i != len(clause.conditions)-1 && len(clause.conditions) > 1 {
+			conditionClauseBuilder.WriteString(" AND ")
+		}
+	}
+
+	clauseBuilder := strings.Builder{}
+	clauseBuilder.WriteString("WHERE\n")
+	clauseBuilder.WriteString(conditionClauseBuilder.String())
+	clauseBuilder.WriteString("\n")
+
+	return clauseBuilder.String(), nil
+}
+
+func (clause *Where) Args() []any {
+	args := make([]any, 0)
+
+	for _, condition := range clause.conditions {
+		args = append(args, condition.Args()...)
+	}
+
+	return args
+}

+ 4 - 5
framework/core/infrastructure/database/sql/conditions.go

@@ -214,13 +214,12 @@ func (conditions *Conditions) And() string {
 	stringBuilder := strings.Builder{}
 	stringBuilder.WriteString("WHERE ")
 
-	for i, query := range conditions.queries {
+	for _, query := range conditions.queries {
 		stringBuilder.WriteString(query)
-
-		if i != len(conditions.queries)-1 {
-			stringBuilder.WriteString(" AND ")
-		}
+		stringBuilder.WriteString(" AND ")
 	}
 
+	stringBuilder.WriteString("1 = 1")
+
 	return stringBuilder.String()
 }

+ 83 - 0
test/database_clause_test.go

@@ -0,0 +1,83 @@
+package test
+
+import (
+	"git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/clause"
+	"github.com/pkg/errors"
+	"testing"
+)
+
+func TestDatabaseClause(t *testing.T) {
+	exceptSql := `SELECT
+  name,
+  age,
+  gender,
+  hobby
+FROM
+  test.students
+  JOIN test.classes ON classes.id = test.students.class_id
+WHERE
+  ("name" = ? AND "hobby" IN ?) AND ("age" = ? OR "gender" = ?)
+LIMIT ? OFFSET ?`
+
+	selectClause := clause.NewSelect(
+		[]string{"name", "age", "gender", "hobby"},
+		clause.NewFrom([]clause.Clause{
+			clause.TableName("test.students"),
+			clause.NewJoin("test.classes", "classes.id = test.students.class_id"),
+		}),
+		[]clause.Clause{
+			clause.NewWhere([]clause.Clause{
+				clause.NewConditions().
+					Equal("name", "test").
+					In("hobby", []string{"football", "basketball"}).
+					And(),
+				clause.NewConditions().
+					Equal("age", 18).
+					Equal("gender", "male").
+					Or(),
+			}),
+			clause.NewLimit(1, 10),
+		}...)
+
+	selectClauseStr, err := selectClause.Clause()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if exceptSql != selectClauseStr {
+		t.Errorf("%+v\n", errors.Errorf("except: %s\nactual: %s", exceptSql, selectClauseStr))
+	}
+
+	args := selectClause.Args()
+	if len(args) != 6 {
+		t.Errorf("%+v\n", errors.Errorf("args len: %d", len(args)))
+	}
+
+	if args[0] != "test" {
+		t.Errorf("%+v\n", errors.Errorf("args[0]: %s", args[0]))
+	}
+
+	if args[1].([]string)[0] != "football" {
+		t.Errorf("%+v\n", errors.Errorf("args[1]: %s", args[1]))
+	}
+
+	if args[1].([]string)[1] != "basketball" {
+		t.Errorf("%+v\n", errors.Errorf("args[1]: %s", args[1]))
+	}
+
+	if args[2] != 18 {
+		t.Errorf("%+v\n", errors.Errorf("args[2]: %s", args[2]))
+	}
+
+	if args[3] != "male" {
+		t.Errorf("%+v\n", errors.Errorf("args[3]: %s", args[3]))
+	}
+
+	if args[4] != 10 {
+		t.Errorf("%+v\n", errors.Errorf("args[4]: %s", args[4]))
+	}
+
+	if args[5] != 0 {
+		t.Errorf("%+v\n", errors.Errorf("args[5]: %s", args[5]))
+	}
+}