Skip to content

Commit 5fd41b4

Browse files
committed
add sample to show how to build JOIN with Struct
1 parent c6a9ca2 commit 5fd41b4

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fmt.Println(sql)
5252
// SELECT id, name FROM demo.user WHERE status = 1 LIMIT 10
5353
```
5454

55-
In the most cases, we need to escape all input from user. In this case, create a builder before starting.
55+
In the most common cases, we need to escape all input from user. In this case, create a builder before starting.
5656

5757
```go
5858
sb := sqlbuilder.NewSelectBuilder()
@@ -222,7 +222,7 @@ type ATable struct {
222222
Field1 string // If a field doesn't has a tag, use "Field1" as column name in SQL.
223223
Field2 int `db:"field2"` // Use "db" in field tag to set column name used in SQL.
224224
Field3 int64 `db:"field3" fieldtag:"foo,bar"` // Set fieldtag to a field. We can call `WithTag` to include fields with tag or `WithoutTag` to exclude fields with tag.
225-
Field4 int64 `db:"field4" fieldtag:"foo"` // If we use `s.WithTag("foo").Select(table)`, columnes of SELECT are field3 and field4.
225+
Field4 int64 `db:"field4" fieldtag:"foo"` // If we use `s.WithTag("foo").Select("t")`, columnes of SELECT are "t.field3" and "t.field4".
226226
Field5 string `db:"field5" fieldas:"f5_alias"` // Use "fieldas" in field tag to set a column alias (AS) used in SELECT.
227227
Ignored int32 `db:"-"` // If we set field name as "-", Struct will ignore it.
228228
unexported int // Unexported field is not visible to Struct.
@@ -232,6 +232,10 @@ type ATable struct {
232232
// The `omitempty` can be written as a function.
233233
// In this case, omit empty field `Tagged` when UPDATE for tag `tag1` and `tag3` but not `tag2`.
234234
Tagged string `db:"tagged" fieldopt:"omitempty(tag1,tag3)" fieldtag:"tag1,tag2,tag3"`
235+
236+
// By default, the `SelectFrom("t")` will add the "t." to all names of fields matched tag.
237+
// We can add dot to field name to disable this behavior.
238+
FieldWithTableAlias string `db:"m.field"`
235239
}
236240
```
237241

@@ -254,7 +258,7 @@ var userStruct = NewStruct(new(User))
254258

255259
func ExampleStruct() {
256260
// Prepare SELECT query.
257-
// SELECT id, name, status FROM user WHERE id = 1234
261+
// SELECT user.id, user.name, user.status FROM user WHERE id = 1234
258262
sb := userStruct.SelectFrom("user")
259263
sb.Where(sb.Equal("id", 1234))
260264

struct.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,11 @@ func (s *Struct) selectFromWithTags(table string, with, without []string) (sb *S
307307

308308
buf := newStringBuilder()
309309
cols := make([]string, 0, len(tagged.ForRead))
310+
tableAlias := parseTableAlias(table)
310311

311312
for _, sf := range tagged.ForRead {
312313
if s.Flavor != CQL && !strings.ContainsRune(sf.Alias, '.') {
313-
buf.WriteString(table)
314+
buf.WriteString(tableAlias)
314315
buf.WriteRune('.')
315316
}
316317
buf.WriteString(sf.NameForSelect(s.Flavor))
@@ -323,6 +324,16 @@ func (s *Struct) selectFromWithTags(table string, with, without []string) (sb *S
323324
return sb
324325
}
325326

327+
func parseTableAlias(table string) string {
328+
idx := strings.LastIndex(table, " ")
329+
330+
if idx == -1 {
331+
return table
332+
}
333+
334+
return table[idx+1:]
335+
}
336+
326337
// Update creates a new `UpdateBuilder` with table name.
327338
// By default, all exported fields of the s is assigned in UPDATE with the field values from value.
328339
// If value's type is not the same as that of s, Update returns a dummy `UpdateBuilder` with table name.

struct_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,37 @@ func ExampleStruct_useStructAsORM() {
386386
// sqlbuilder.User{ID:1234, Name:"huandu", Status:1}
387387
}
388388

389+
func ExampleStruct_buildJOIN() {
390+
// Suppose we're going to query a "member" table joined with "user" table.
391+
type Member struct {
392+
ID string `db:"id"`
393+
UserID string `db:"user_id"`
394+
MemberName int `db:"name"`
395+
CreatedAt time.Time `db:"created_at"`
396+
397+
// Add "u." prefix to the field name to specify the field in "user" table.
398+
Name string `db:"u.name"`
399+
Email string `db:"u.email"`
400+
}
401+
402+
// Parse member struct. The memberStruct can be a global variable.
403+
// It's guraanteed to be thread-safe.
404+
var memberStruct = NewStruct(new(Member))
405+
406+
// Prepare JOIN query.
407+
sb := memberStruct.SelectFrom("member m").Join("user u", "m.user_id = u.user_id")
408+
sb.Where(sb.Like("m.name", "Huan%"))
409+
410+
sql, args := sb.Build()
411+
412+
fmt.Println(sql)
413+
fmt.Println(args)
414+
415+
// Output:
416+
// SELECT m.id, m.user_id, m.name, m.created_at, u.name, u.email FROM member m JOIN user u ON m.user_id = u.user_id WHERE m.name LIKE ?
417+
// [Huan%]
418+
}
419+
389420
var orderDB testDB = 1
390421

391422
func ExampleStruct_WithTag() {

0 commit comments

Comments
 (0)