Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
8750f3ad95 | |||
ad1faf2056 | |||
525c64e678 | |||
5f0fdadb8b | |||
68263895f7 | |||
ee6cb445ab |
3
Makefile
3
Makefile
@@ -2,3 +2,6 @@ run:
|
|||||||
go run ./cmd -o ./example/db ./example/schema.sql
|
go run ./cmd -o ./example/db ./example/schema.sql
|
||||||
bench-select:
|
bench-select:
|
||||||
go test ./example -bench BenchmarkSelect -memprofile memprofile.out -cpuprofile profile.out
|
go test ./example -bench BenchmarkSelect -memprofile memprofile.out -cpuprofile profile.out
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test ./playground
|
||||||
|
25
pgm.go
25
pgm.go
@@ -45,17 +45,17 @@ func (f Field) Count() Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StringEscape will return a empty string for null value
|
// StringEscape will return a empty string for null value
|
||||||
func (f Field) StringEscape(arg ...any) Field {
|
func (f Field) StringEscape() Field {
|
||||||
return Field("COALESCE(" + f.String() + ", '')")
|
return Field("COALESCE(" + f.String() + ", '')")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumberEscape will return a zero string for null value
|
// NumberEscape will return a zero string for null value
|
||||||
func (f Field) NumberEscape(arg ...any) Field {
|
func (f Field) NumberEscape() Field {
|
||||||
return Field("COALESCE(" + f.String() + ", 0)")
|
return Field("COALESCE(" + f.String() + ", 0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// BooleanEscape will return a false for null value
|
// BooleanEscape will return a false for null value
|
||||||
func (f Field) BooleanEscape(arg ...any) Field {
|
func (f Field) BooleanEscape() Field {
|
||||||
return Field("COALESCE(" + f.String() + ", FALSE)")
|
return Field("COALESCE(" + f.String() + ", FALSE)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,19 +98,19 @@ func (f Field) IsNotNull() Conditioner {
|
|||||||
return &Cond{Field: col, op: " IS NOT NULL", len: len(col) + 12}
|
return &Cond{Field: col, op: " IS NOT NULL", len: len(col) + 12}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EqualFold will use LOWER(column_name) = LOWER(val) for comparision
|
||||||
|
func (f Field) EqFold(val string) Conditioner {
|
||||||
|
col := f.String()
|
||||||
|
return &Cond{Field: "LOWER(" + col + ")", Val: val, op: " = LOWER($", action: CondActionNeedToClose, len: len(col) + 5}
|
||||||
|
}
|
||||||
|
|
||||||
// Eq is equal
|
// Eq is equal
|
||||||
func (f Field) Eq(val any) Conditioner {
|
func (f Field) Eq(val any) Conditioner {
|
||||||
col := f.String()
|
col := f.String()
|
||||||
return &Cond{Field: col, Val: val, op: " = $", len: len(col) + 5}
|
return &Cond{Field: col, Val: val, op: " = $", len: len(col) + 5}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualFold will user LOWER() for comparision
|
func (f Field) NotEq(val any) Conditioner {
|
||||||
func (f Field) EqFold(val any) Conditioner {
|
|
||||||
col := f.String()
|
|
||||||
return &Cond{Field: "LOWER(" + col + ")", Val: val, op: " = LOWER($", action: CondActionNeedToClose, len: len(col) + 5}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Field) NEq(val any) Conditioner {
|
|
||||||
col := f.String()
|
col := f.String()
|
||||||
return &Cond{Field: col, Val: val, op: " != $", len: len(col) + 5}
|
return &Cond{Field: col, Val: val, op: " != $", len: len(col) + 5}
|
||||||
}
|
}
|
||||||
@@ -151,6 +151,11 @@ func (f Field) ILike(val string) Conditioner {
|
|||||||
return &Cond{Field: col, Val: val, op: " ILIKE $", len: len(col) + 5}
|
return &Cond{Field: col, Val: val, op: " ILIKE $", len: len(col) + 5}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f Field) In(val ...any) Conditioner {
|
||||||
|
col := f.String()
|
||||||
|
return &Cond{Field: col, Val: val, op: " IN($", action: CondActionNeedToClose, len: len(col) + 5}
|
||||||
|
}
|
||||||
|
|
||||||
func (f Field) NotIn(val ...any) Conditioner {
|
func (f Field) NotIn(val ...any) Conditioner {
|
||||||
col := f.String()
|
col := f.String()
|
||||||
return &Cond{Field: col, Val: val, op: " NOT IN($", action: CondActionNeedToClose, len: len(col) + 5}
|
return &Cond{Field: col, Val: val, op: " NOT IN($", action: CondActionNeedToClose, len: len(col) + 5}
|
||||||
|
@@ -28,7 +28,7 @@ func TestQryBuilder2(t *testing.T) {
|
|||||||
),
|
),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
user.LastName.NEq(7),
|
user.LastName.NotEq(7),
|
||||||
user.Phone.Like("%123%"),
|
user.Phone.Like("%123%"),
|
||||||
user.UpdatedAt.IsNotNull(),
|
user.UpdatedAt.IsNotNull(),
|
||||||
user.Email.NotInSubQuery(db.User.Select(user.ID).Where(user.ID.Eq(123))),
|
user.Email.NotInSubQuery(db.User.Select(user.ID).Where(user.ID.Eq(123))),
|
||||||
@@ -60,7 +60,31 @@ func TestSelectWithHaving(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkSelect-12 668817 1753 ns/op 4442 B/op 59 allocs/op
|
func TestSelectWithJoin(t *testing.T) {
|
||||||
|
got := db.User.Select(user.Email, user.FirstName).
|
||||||
|
Join(db.UserSession, user.ID, usersession.UserID).
|
||||||
|
LeftJoin(db.BranchUser, user.ID, branchuser.UserID, pgm.Or(branchuser.RoleID.Eq("1"), branchuser.RoleID.Eq("2"))).
|
||||||
|
Where(
|
||||||
|
user.ID.Eq(3),
|
||||||
|
pgm.Or(
|
||||||
|
user.StatusID.Eq(4),
|
||||||
|
user.UpdatedAt.Eq(5),
|
||||||
|
),
|
||||||
|
).
|
||||||
|
Limit(10).
|
||||||
|
Offset(100).
|
||||||
|
String()
|
||||||
|
|
||||||
|
expected := "SELECT users.email, users.first_name " +
|
||||||
|
"FROM users JOIN user_sessions ON users.id = user_sessions.user_id " +
|
||||||
|
"LEFT JOIN branch_users ON users.id = branch_users.user_id AND (branch_users.role_id = $1 OR branch_users.role_id = $2) " +
|
||||||
|
"WHERE users.id = $3 AND (users.status_id = $4 OR users.updated_at = $5) " +
|
||||||
|
"LIMIT 10 OFFSET 100"
|
||||||
|
if expected != got {
|
||||||
|
t.Errorf("\nexpected: %q\ngot: %q", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BenchmarkSelect-12 638901 1860 ns/op 4266 B/op 61 allocs/op
|
// BenchmarkSelect-12 638901 1860 ns/op 4266 B/op 61 allocs/op
|
||||||
func BenchmarkSelect(b *testing.B) {
|
func BenchmarkSelect(b *testing.B) {
|
||||||
for b.Loop() {
|
for b.Loop() {
|
||||||
@@ -80,7 +104,7 @@ func BenchmarkSelect(b *testing.B) {
|
|||||||
),
|
),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
user.LastName.NEq(7),
|
user.LastName.NotEq(7),
|
||||||
user.Phone.Like("%123%"),
|
user.Phone.Like("%123%"),
|
||||||
user.Email.NotInSubQuery(db.User.Select(user.ID).Where(user.ID.Eq(123))),
|
user.Email.NotInSubQuery(db.User.Select(user.ID).Where(user.ID.Eq(123))),
|
||||||
).
|
).
|
||||||
|
@@ -17,7 +17,7 @@ func TestUpdateQuery(t *testing.T) {
|
|||||||
user.Email.Eq("aa@aa.com"),
|
user.Email.Eq("aa@aa.com"),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
user.StatusID.NEq(1),
|
user.StatusID.NotEq(1),
|
||||||
).
|
).
|
||||||
String()
|
String()
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func TestUpdateSetMap(t *testing.T) {
|
|||||||
user.Email.Eq("aa@aa.com"),
|
user.Email.Eq("aa@aa.com"),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
user.StatusID.NEq(1),
|
user.StatusID.NotEq(1),
|
||||||
).
|
).
|
||||||
String()
|
String()
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func BenchmarkUpdateQuery(b *testing.B) {
|
|||||||
user.Email.Eq("aa@aa.com"),
|
user.Email.Eq("aa@aa.com"),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
user.StatusID.NEq(1),
|
user.StatusID.NotEq(1),
|
||||||
).
|
).
|
||||||
String()
|
String()
|
||||||
}
|
}
|
||||||
|
8
qry.go
8
qry.go
@@ -21,10 +21,10 @@ type (
|
|||||||
|
|
||||||
SelectClause interface {
|
SelectClause interface {
|
||||||
// Join and Inner Join are same
|
// Join and Inner Join are same
|
||||||
Join(m Table, t1Field, t2Field Field) SelectClause
|
Join(m Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause
|
||||||
LeftJoin(m Table, t1Field, t2Field Field) SelectClause
|
LeftJoin(m Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause
|
||||||
RightJoin(m Table, t1Field, t2Field Field) SelectClause
|
RightJoin(m Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause
|
||||||
FullJoin(m Table, t1Field, t2Field Field) SelectClause
|
FullJoin(m Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause
|
||||||
CrossJoin(m Table) SelectClause
|
CrossJoin(m Table) SelectClause
|
||||||
WhereClause
|
WhereClause
|
||||||
OrderByClause
|
OrderByClause
|
||||||
|
@@ -62,23 +62,46 @@ func (t Table) Select(field ...Field) SelectClause {
|
|||||||
return qb
|
return qb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *selectQry) Join(t Table, t1Field, t2Field Field) SelectClause {
|
func (q *selectQry) Join(t Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause {
|
||||||
q.join = append(q.join, "JOIN "+t.Name+" ON "+t1Field.String()+" = "+t2Field.String())
|
return q.buildJoin(t, "JOIN", t1Field, t2Field, cond...)
|
||||||
return q
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *selectQry) LeftJoin(t Table, t1Field, t2Field Field) SelectClause {
|
func (q *selectQry) LeftJoin(t Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause {
|
||||||
q.join = append(q.join, "LEFT JOIN "+t.Name+" ON "+t1Field.String()+" = "+t2Field.String())
|
return q.buildJoin(t, "LEFT JOIN", t1Field, t2Field, cond...)
|
||||||
return q
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *selectQry) RightJoin(t Table, t1Field, t2Field Field) SelectClause {
|
func (q *selectQry) RightJoin(t Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause {
|
||||||
q.join = append(q.join, "RIGHT JOIN "+t.Name+" ON "+t1Field.String()+" = "+t2Field.String())
|
return q.buildJoin(t, "RIGHT JOIN", t1Field, t2Field, cond...)
|
||||||
return q
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *selectQry) FullJoin(t Table, t1Field, t2Field Field) SelectClause {
|
func (q *selectQry) FullJoin(t Table, t1Field, t2Field Field, cond ...Conditioner) SelectClause {
|
||||||
q.join = append(q.join, "FULL JOIN "+t.Name+" ON "+t1Field.String()+" = "+t2Field.String())
|
return q.buildJoin(t, "FULL JOIN", t1Field, t2Field, cond...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *selectQry) buildJoin(t Table, joinKW string, t1Field, t2Field Field, cond ...Conditioner) SelectClause {
|
||||||
|
str := joinKW + " " + t.Name + " ON " + t1Field.String() + " = " + t2Field.String()
|
||||||
|
if len(cond) == 0 { // Join with no condition
|
||||||
|
q.join = append(q.join, str)
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join has condition(s)
|
||||||
|
sb := getSB()
|
||||||
|
defer putSB(sb)
|
||||||
|
sb.Grow(len(str) * 2)
|
||||||
|
|
||||||
|
sb.WriteString(str + " AND ")
|
||||||
|
|
||||||
|
var argIdx int
|
||||||
|
for i, c := range cond {
|
||||||
|
argIdx = len(q.args)
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteString(" AND ")
|
||||||
|
}
|
||||||
|
sb.WriteString(c.Condition(&q.args, argIdx))
|
||||||
|
}
|
||||||
|
|
||||||
|
q.join = append(q.join, sb.String())
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user