Skip to content

Commit 6d21e2b

Browse files
committed
Generate schema consts and scan func
1 parent 0f4096a commit 6d21e2b

File tree

4 files changed

+89
-20
lines changed

4 files changed

+89
-20
lines changed

README.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ go generate ./repository
4141

4242
**Roll your own persistence code for full control and low abstraction**
4343

44+
Structure your persistence code as it fits the project. A very simple and working approach is to have a bunch of
45+
functions that operator on the target type for finding, inserting, updating and deleting. Add more complex queries
46+
as you like in the same way.
47+
48+
There's no need to use Squirrel, but it helps to build correct SQL queries instead of relying on string manipulation
49+
and manually handling placeholders and arguments.
50+
4451
*repository/customer_repository.go*
4552
```go
4653
package repository
@@ -50,10 +57,12 @@ func FindCustomerByID(ctx context.Context, runner squirrel.BaseRunner, id uuid.U
5057
Select(buildCustomerJson()).
5158
From("customers").
5259
LeftJoin("domains ON (domains.customer_id = customers.customer_id)").
53-
Where(squirrel.Eq{"customers.customer_id": id}).
54-
GroupBy("customers.customer_id").
60+
// constants for read columns are generated by construct to prevent typos
61+
Where(squirrel.Eq{customer_id: id}).
62+
GroupBy(customer_id).
5563
QueryRowContext(ctx)
56-
return scanCustomerResult(row)
64+
// customerScanJsonRow is generated by construct and will scan a JSON row result into the target type
65+
return customerScanJsonRow(row)
5766
}
5867

5968
// CustomerChangeSet is generated by construct for handling partially filled models
@@ -69,7 +78,7 @@ func InsertCustomer(ctx context.Context, runner squirrel.BaseRunner, changeSet C
6978
func UpdateCustomer(ctx context.Context, runner squirrel.BaseRunner, id uuid.UUID, changeSet CustomerChangeSet) error {
7079
res, err := queryBuilder(runner).
7180
Update("customers").
72-
Where(squirrel.Eq{"customer_id": id}).
81+
Where(squirrel.Eq{customer_id: id}).
7382
SetMap(changeSet.toMap()).
7483
ExecContext(ctx)
7584
if err != nil {
@@ -86,20 +95,13 @@ func buildCustomerJson() string {
8695
Set("DomainCount", cjson.Exp("COUNT(domains.domain_id)")).
8796
ToSql()
8897
}
98+
```
8999

90-
func scanCustomerResult(row squirrel.RowScanner) (result domain.Customer, err error) {
91-
var data []byte
92-
if err := row.Scan(&data); err != nil {
93-
if err == sql.ErrNoRows {
94-
return result, ErrNotFound
95-
}
96-
return result, err
97-
}
98-
99-
return result, json.Unmarshal(data, &result)
100-
}
100+
These are common functions that can be shared by all repository implementations:
101101

102-
// These are common functions that can be shared by all repository implementations
102+
*repository/commong.go*
103+
```go
104+
package repository
103105

104106
func queryBuilder(runner squirrel.BaseRunner) squirrel.StatementBuilderType {
105107
return squirrel.StatementBuilder.

internal/fixtures/repository/mappings_mytype_gen.go

Lines changed: 23 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/generate.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func Generate(m *StructMapping, goPackage string, goFile string, w io.Writer) (o
1616

1717
f.PackageComment("Code generated by construct, DO NOT EDIT.")
1818

19+
generateConstSchema(f, m)
20+
1921
generateSortFields(f, m)
2022

2123
// ChangeSet struct
@@ -99,7 +101,7 @@ func Generate(m *StructMapping, goPackage string, goFile string, w io.Writer) (o
99101

100102
generateDefaultSelectJsonObject(f, m)
101103

102-
// TODO Generate Schema for refactoring friendly access to fields
104+
generateScanJsonRow(f, m)
103105

104106
ext := filepath.Ext(goFile)
105107
baseFilename := goFile[0 : len(goFile)-len(ext)]
@@ -108,6 +110,20 @@ func Generate(m *StructMapping, goPackage string, goFile string, w io.Writer) (o
108110
return outputFilename, f.Render(w)
109111
}
110112

113+
func generateConstSchema(f *File, m *StructMapping) {
114+
f.Const().DefsFunc(func(g *Group) {
115+
for _, fm := range m.FieldMappings {
116+
if fm.ReadColDef != nil {
117+
g.Id(readColConstId(m, fm)).Op("=").Lit(fm.ReadColDef.Col)
118+
}
119+
}
120+
})
121+
}
122+
123+
func readColConstId(m *StructMapping, fm FieldMapping) string {
124+
return firstToLower(m.MappingTypeName) + "_" + firstToLower(fm.Name)
125+
}
126+
111127
func generateDefaultSelectJsonObject(f *File, m *StructMapping) {
112128
varName := firstToLower(m.TargetName + "DefaultSelectJson")
113129

@@ -126,6 +142,27 @@ func generateDefaultSelectJsonObject(f *File, m *StructMapping) {
126142
}
127143
}
128144

145+
func generateScanJsonRow(f *File, m *StructMapping) {
146+
f.Func().Id(firstToLower(m.TargetName)+"ScanJsonRow").Params(
147+
Id("row").Qual("github.com/networkteam/construct", "RowScanner"),
148+
).Params(
149+
Id("result").Qual(m.MappingTypePackage, m.MappingTypeName),
150+
Id("err").Error(),
151+
).Block(
152+
Var().Id("data").Op("[]").Byte(),
153+
If(
154+
Id("err").Op(":=").Id("row").Dot("Scan").Call(Op("&").Id("data")),
155+
Id("err").Op("!=").Nil(),
156+
).Block(
157+
If(Id("err").Op("==").Qual("database/sql", "ErrNoRows")).Block(
158+
Return(Id("result"), Qual("github.com/networkteam/construct", "ErrNotFound")),
159+
),
160+
Return(Id("result"), Id("err")),
161+
),
162+
Return(Id("result"), Qual("encoding/json", "Unmarshal").Call(Id("data"), Op("&").Id("result"))),
163+
)
164+
}
165+
129166
func generateChangeSetStruct(f *File, m *StructMapping) (changeSetName string, err error) {
130167
var structFields []Code
131168

@@ -190,7 +227,7 @@ func generateSortFields(f *File, m *StructMapping) {
190227
sortFieldDict := make(Dict)
191228
for _, fm := range m.FieldMappings {
192229
if fm.ReadColDef != nil && fm.ReadColDef.Sortable {
193-
sortFieldDict[Lit(strings.ToLower(fm.Name))] = Lit(fm.ReadColDef.Col)
230+
sortFieldDict[Lit(strings.ToLower(fm.Name))] = Id(readColConstId(m, fm))
194231
}
195232
}
196233
f.Var().Id(firstToLower(m.TargetName + "SortFields")).Op("=").Map(String()).String().

sql.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package construct
2+
3+
import "errors"
4+
5+
var ErrNotFound = errors.New("record not found")
6+
7+
type RowScanner interface {
8+
Scan(...interface{}) error
9+
}

0 commit comments

Comments
 (0)