6 Commits

Author SHA1 Message Date
ad1faf2056 join with conditions 2025-08-10 20:26:09 +05:30
525c64e678 removed toLower 2025-08-10 12:54:29 +05:30
5f0fdadb8b undo, strings.ToLower 2025-08-10 12:24:26 +05:30
68263895f7 EqFold to do value lower case 2025-08-10 11:59:01 +05:30
ee6cb445ab remove unwanted method args 2025-08-03 22:21:24 +05:30
d07c25fe01 COALESCE related methods 2025-08-03 22:17:58 +05:30
5 changed files with 83 additions and 18 deletions

View File

@@ -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

19
pgm.go
View File

@@ -44,6 +44,21 @@ func (f Field) Count() Field {
return Field("COUNT(" + f.String() + ")") return Field("COUNT(" + f.String() + ")")
} }
// StringEscape will return a empty string for null value
func (f Field) StringEscape() Field {
return Field("COALESCE(" + f.String() + ", '')")
}
// NumberEscape will return a zero string for null value
func (f Field) NumberEscape() Field {
return Field("COALESCE(" + f.String() + ", 0)")
}
// BooleanEscape will return a false for null value
func (f Field) BooleanEscape() Field {
return Field("COALESCE(" + f.String() + ", FALSE)")
}
// Avg fn wrapping of field // Avg fn wrapping of field
func (f Field) Avg() Field { func (f Field) Avg() Field {
return Field("AVG(" + f.String() + ")") return Field("AVG(" + f.String() + ")")
@@ -89,8 +104,8 @@ func (f Field) Eq(val any) Conditioner {
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 // EqualFold will use LOWER(column_name) = LOWER(val) for comparision
func (f Field) EqFold(val any) Conditioner { func (f Field) EqFold(val string) Conditioner {
col := f.String() col := f.String()
return &Cond{Field: "LOWER(" + col + ")", Val: val, op: " = LOWER($", action: CondActionNeedToClose, len: len(col) + 5} return &Cond{Field: "LOWER(" + col + ")", Val: val, op: " = LOWER($", action: CondActionNeedToClose, len: len(col) + 5}
} }

View File

@@ -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() {

8
qry.go
View File

@@ -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

View File

@@ -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
} }