@@ -7,17 +7,30 @@ import (
7
7
)
8
8
9
9
type IndexesInfo struct {
10
- Comment string
11
- Field string
12
- Label string
13
- SearchItem string // TODO `前方一致` や `部分一致` など (5/7 unused)
10
+ Comment string
11
+ ConstName string
12
+ Label string
13
+ Method string
14
+ }
15
+
16
+ type FieldInfo struct {
17
+ Field string
18
+ FieldType string
19
+ Indexes []* IndexesInfo
20
+ }
21
+
22
+ type ImportInfo struct {
23
+ Name string
14
24
}
15
25
16
26
type generator struct {
17
27
PackageName string
28
+ ImportName string
29
+ ImportList []ImportInfo
18
30
GeneratedFileName string
19
31
FileName string
20
32
StructName string
33
+ LowerStructName string
21
34
22
35
GoGenerate string
23
36
RepositoryStructName string
@@ -28,10 +41,14 @@ type generator struct {
28
41
29
42
KeyValueName string // lower camel case
30
43
31
- ConstMapForIndexes []IndexesInfo
44
+ FieldInfos []* FieldInfo
45
+
46
+ EnableIndexes bool
47
+ BoolCriteriaCnt int
32
48
}
33
49
34
50
func (g * generator ) setting () {
51
+ g .ImportName = ImportName
35
52
g .GoGenerate = "go:generate"
36
53
g .RepositoryInterfaceName = g .StructName + "Repository"
37
54
g .setRepositoryStructName ()
@@ -81,9 +98,18 @@ func (g *generator) generate(writer io.Writer) {
81
98
}
82
99
}
83
100
101
+ func (g * generator ) generateLabel (writer io.Writer ) {
102
+ t := template .Must (template .New ("tmplLabel" ).Parse (tmplLabel ))
103
+
104
+ err := t .Execute (writer , g )
105
+
106
+ if err != nil {
107
+ log .Printf ("failed to execute template: %+v" , err )
108
+ }
109
+ }
110
+
84
111
func (g * generator ) generateConstant (writer io.Writer ) {
85
- g .setting ()
86
- t := template .Must (template .New ("tmpl" ).Parse (tmplConst ))
112
+ t := template .Must (template .New ("tmplConst" ).Parse (tmplConst ))
87
113
88
114
err := t .Execute (writer , g )
89
115
@@ -92,13 +118,55 @@ func (g *generator) generateConstant(writer io.Writer) {
92
118
}
93
119
}
94
120
95
- const tmplConst = `// THIS FILE IS A GENERATED CODE. EDIT OK
121
+ const tmplConst = `// THIS FILE IS A GENERATED CODE. DO NOT EDIT
96
122
package configs
97
123
124
+ import "strconv"
125
+
126
+ type BoolCriteria string
127
+
98
128
const (
99
- {{- range .ConstMapForIndexes }}
100
- // {{ .Comment }}検索用ラベル
101
- {{ .Field }} = "{{ .Label }}"
129
+ BoolCriteriaEmpty BoolCriteria = ""
130
+ BoolCriteriaTrue BoolCriteria = "true"
131
+ BoolCriteriaFalse BoolCriteria = "false"
132
+ )
133
+
134
+ func (src BoolCriteria) Bool() bool {
135
+ return src == BoolCriteriaTrue
136
+ }
137
+
138
+ type IntegerCriteria string
139
+
140
+ const (
141
+ IntegerCriteriaEmpty IntegerCriteria = ""
142
+ )
143
+
144
+ func (str IntegerCriteria) Int() int {
145
+ i32, err := strconv.Atoi(string(str))
146
+ if err != nil {
147
+ return -1
148
+ }
149
+ return i32
150
+ }
151
+
152
+ func (str IntegerCriteria) Int64() int64 {
153
+ i64, err := strconv.ParseInt(string(str), 10, 64)
154
+ if err != nil {
155
+ return -1
156
+ }
157
+ return i64
158
+ }
159
+ `
160
+
161
+ const tmplLabel = `// THIS FILE IS A GENERATED CODE. EDIT OK
162
+ package configs
163
+
164
+ const (
165
+ {{- range $fi := .FieldInfos }}
166
+ {{- range $idx := $fi.Indexes }}
167
+ // {{ $idx.Comment }}検索用ラベル
168
+ {{ $idx.ConstName }} = "{{ $idx.Label }}"
169
+ {{- end }}
102
170
{{- end }}
103
171
)
104
172
`
@@ -114,6 +182,7 @@ import (
114
182
{{- end }}
115
183
116
184
"cloud.google.com/go/datastore"
185
+ "{{ .ImportName }}/configs"
117
186
"golang.org/x/xerrors"
118
187
)
119
188
@@ -127,11 +196,15 @@ type {{ .RepositoryInterfaceName }} interface {
127
196
Delete(ctx context.Context, subject *{{ .StructName }}) error
128
197
DeleteBy{{ .KeyFieldName }}(ctx context.Context, {{ .KeyValueName }} {{ .KeyFieldType }}) error
129
198
// Multiple
130
- GetMulti(ctx context.Context, {{.KeyValueName}}s []{{.KeyFieldType}}) ([]*{{.StructName}}, error)
131
- InsertMulti(ctx context.Context, subjects []*{{.StructName}}) ([]{{.KeyFieldType}}, error)
132
- UpdateMulti(ctx context.Context, subjects []*{{.StructName}}) error
133
- DeleteMulti(ctx context.Context, subjects []*{{.StructName}}) error
134
- DeleteMultiBy{{.KeyFieldName}}s(ctx context.Context, {{.KeyValueName}}s []{{.KeyFieldType}}) error
199
+ GetMulti(ctx context.Context, {{ .KeyValueName }}s []{{ .KeyFieldType }}) ([]*{{ .StructName }}, error)
200
+ InsertMulti(ctx context.Context, subjects []*{{ .StructName }}) ([]{{ .KeyFieldType }}, error)
201
+ UpdateMulti(ctx context.Context, subjects []*{{ .StructName }}) error
202
+ DeleteMulti(ctx context.Context, subjects []*{{ .StructName }}) error
203
+ DeleteMultiBy{{ .KeyFieldName }}s(ctx context.Context, {{ .KeyValueName }}s []{{ .KeyFieldType }}) error
204
+ // List
205
+ List(ctx context.Context, req *{{ .StructName }}ListReq, q *datastore.Query) ([]*{{ .StructName }}, error)
206
+ // misc
207
+ GetKindName() string
135
208
}
136
209
137
210
type {{ .RepositoryStructName }} struct {
@@ -146,7 +219,12 @@ func New{{ .RepositoryInterfaceName }}(datastoreClient *datastore.Client) {{ .Re
146
219
}
147
220
}
148
221
149
- func (repo *{{.RepositoryStructName}}) getKeys(subjects ...*{{.StructName}}) ([]*datastore.Key, error) {
222
+ func (repo *{{ .RepositoryStructName }}) GetKindName() string {
223
+ return repo.kind
224
+ }
225
+
226
+ // getKeys Entityからkeyを取得する
227
+ func (repo *{{ .RepositoryStructName }}) getKeys(subjects ...*{{ .StructName }}) ([]*datastore.Key, error) {
150
228
keys := make([]*datastore.Key, 0, len(subjects))
151
229
for _, subject := range subjects {
152
230
key := subject.{{ .KeyFieldName }}
@@ -170,6 +248,137 @@ func (repo *{{.RepositoryStructName}}) getKeys(subjects ...*{{.StructName}}) ([]
170
248
171
249
return keys, nil
172
250
}
251
+ {{ if eq .EnableIndexes true }}
252
+ // saveIndexes 拡張フィルタを保存する
253
+ func (repo *{{ .RepositoryStructName }}) saveIndexes(subjects ...*{{ .StructName }}) error {
254
+ for _, subject := range subjects {
255
+ idx := xian.NewIndexes({{ .LowerStructName }}IndexesConfig)
256
+ {{- range $fi := .FieldInfos }}
257
+ {{- range $idx := $fi.Indexes }}
258
+ {{- if eq $fi.FieldType "bool" }}
259
+ idx.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, subject.{{ $fi.Field }})
260
+ {{- else if eq $fi.FieldType "string" }}
261
+ {{- if eq $idx.Method "AddPrefix" }}
262
+ idx.{{ $idx.Method }}es(configs.{{ $idx.ConstName }}, subject.{{ $fi.Field }})
263
+ {{- else }}
264
+ idx.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, subject.{{ $fi.Field }})
265
+ {{- end }}
266
+ {{- else if eq $fi.FieldType "int" }}
267
+ idx.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, subject.{{ $fi.Field }})
268
+ {{- else if eq $fi.FieldType "time.Time" }}
269
+ idx.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, subject.{{ $fi.Field }}.Unix())
270
+ {{- end }}
271
+ {{- end }}
272
+ {{- end }}
273
+ built, err := idx.Build()
274
+ if err != nil {
275
+ return err
276
+ }
277
+ subject.Indexes = built
278
+ }
279
+
280
+ return nil
281
+ }
282
+
283
+ var {{ .LowerStructName }}IndexesConfig = &xian.Config{
284
+ IgnoreCase: true, // Case insensitive
285
+ SaveNoFiltersIndex: true, // https://qiita.com/hogedigo/items/02dcce80f6197faae1fb#savenofiltersindex
286
+ }
287
+ {{- end }}
288
+
289
+ // {{ .StructName }}ListReq List取得時に渡すリクエスト
290
+ // └─ bool/int(64) は stringで渡す(configs.BoolCriteria | configs.IntegerCriteria)
291
+ type {{ .StructName }}ListReq struct {
292
+ {{- range .FieldInfos }}
293
+ {{- if eq .FieldType "bool" }}
294
+ {{ .Field }} configs.BoolCriteria
295
+ {{- else if or (eq .FieldType "int") (eq .FieldType "int64") }}
296
+ {{ .Field }} configs.IntegerCriteria
297
+ {{- else }}
298
+ {{ .Field }} {{ .FieldType }}
299
+ {{- end }}
300
+ {{- end }}
301
+ }
302
+
303
+ // List datastore.Queryを使用し条件抽出をする
304
+ // └─ 第3引数はNOT/OR/IN/RANGEなど、より複雑な条件を適用したいときにつける
305
+ // └─ 基本的にnilを渡せば良い
306
+ // BUG(54mch4n) 潜在的なバグがあるかもしれない
307
+ func (repo *{{ .RepositoryStructName }}) List(ctx context.Context, req *{{ .StructName }}ListReq, q *datastore.Query) ([]*{{ .StructName }}, error) {
308
+ if q == nil {
309
+ q = datastore.NewQuery(repo.kind)
310
+ }
311
+ {{ $Enable := .EnableIndexes }}
312
+ {{- if eq $Enable true }}
313
+ filters := xian.NewFilters({{ .LowerStructName }}IndexesConfig)
314
+ {{- end }}
315
+ {{- range $fi := .FieldInfos }}
316
+ {{- if eq $fi.FieldType "bool" }}
317
+ if req.{{ $fi.Field }} != "" {
318
+ {{- if eq $Enable true }}
319
+ {{- range $idx := $fi.Indexes }}
320
+ filters.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, req.{{ $fi.Field }})
321
+ {{- end }}
322
+ {{- else }}
323
+ q = q.Filter("{{ $fi.Field }}", req.{{ $fi.Field }}.Bool())
324
+ {{- end }}
325
+ }
326
+ {{- else if eq $fi.FieldType "string" }}
327
+ if req.{{ $fi.Field }} != "" {
328
+ {{- if eq $Enable true }}
329
+ {{- range $idx := $fi.Indexes }}
330
+ filters.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, req.{{ $fi.Field }})
331
+ {{- end }}
332
+ {{- else }}
333
+ q = q.Filter("{{ $fi.Field }}", req.{{ $fi.Field }})
334
+ {{- end }}
335
+ }
336
+ {{- else if or (eq $fi.FieldType "int") (eq $fi.FieldType "int64") }}
337
+ if req.{{ $fi.Field }} != configs.IntegerCriteriaEmpty {
338
+ {{- if eq $Enable true }}
339
+ {{- range $idx := $fi.Indexes }}
340
+ filters.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, req.{{ Parse $fi.Field $fi.FieldType }})
341
+ {{- end }}
342
+ {{- else }}
343
+ q = q.Filter("{{ $fi.Field }}", req.{{ Parse $fi.Field $fi.FieldType }})
344
+ {{- end }}
345
+ }
346
+ {{- else if eq $fi.FieldType "time.Time" }}
347
+ if !req.{{ $fi.Field }}.IsZero() {
348
+ {{- if eq $Enable true }}
349
+ {{- range $idx := $fi.Indexes }}
350
+ filters.{{ $idx.Method }}(configs.{{ $idx.ConstName }}, req.{{ $fi.Field }}.Unix())
351
+ {{- end }}
352
+ {{- else }}
353
+ q = q.Filter("{{ $fi.Field }}", req.{{ $fi.Field }})
354
+ {{- end }}
355
+ }
356
+ {{- end }}
357
+ {{- end }}
358
+ {{ if eq $Enable true }}
359
+ built, err := filters.Build()
360
+ if err != nil {
361
+ return nil, err
362
+ }
363
+
364
+ for _, f := range built {
365
+ q = q.Filter("Indexes =", f)
366
+ }
367
+ {{- end }}
368
+ subjects := make([]*{{ .StructName }}, 0)
369
+ keys, err := repo.datastoreClient.GetAll(ctx, q, &subjects)
370
+ if err != nil {
371
+ return nil, err
372
+ }
373
+
374
+ for i, k := range keys {
375
+ if k != nil {
376
+ subjects[i].ID = k.ID
377
+ }
378
+ }
379
+
380
+ return subjects, nil
381
+ }
173
382
174
383
func (repo *{{ .RepositoryStructName }}) Get(ctx context.Context, {{ .KeyValueName }} {{ .KeyFieldType }}) (*{{ .StructName }}, error) {
175
384
{{- if eq .KeyFieldType "int64" }}
@@ -206,7 +415,11 @@ func (repo *{{ .RepositoryStructName }}) Insert(ctx context.Context, subject *{{
206
415
if err != nil {
207
416
return zero, xerrors.Errorf("error in getKeys method: %w", err)
208
417
}
209
-
418
+ {{ if eq .EnableIndexes true }}
419
+ if err := repo.saveIndexes(subject); err != nil {
420
+ return zero, xerrors.Errorf("error in saveIndexes method: %w", err)
421
+ }
422
+ {{ end }}
210
423
key, err := repo.datastoreClient.Put(ctx, keys[0], subject)
211
424
if err != nil {
212
425
return zero, err
@@ -229,7 +442,11 @@ func (repo *{{ .RepositoryStructName }}) Update(ctx context.Context, subject *{{
229
442
if err != nil {
230
443
return xerrors.Errorf("error in getKeys method: %w", err)
231
444
}
232
-
445
+ {{ if eq .EnableIndexes true }}
446
+ if err := repo.saveIndexes(subject); err != nil {
447
+ return xerrors.Errorf("error in saveIndexes method: %w", err)
448
+ }
449
+ {{ end }}
233
450
if _, err := repo.datastoreClient.Put(ctx, keys[0], subject); err != nil {
234
451
return err
235
452
}
@@ -311,7 +528,11 @@ func (repo *{{ .RepositoryStructName }}) InsertMulti(ctx context.Context, subjec
311
528
if len(subjects) != cnt {
312
529
return nil, xerrors.Errorf("already exist. (%d)", len(subjects)-cnt)
313
530
}
314
-
531
+ {{ if eq .EnableIndexes true }}
532
+ if err := repo.saveIndexes(subjects...); err != nil {
533
+ return nil, xerrors.Errorf("error in saveIndexes method: %w", err)
534
+ }
535
+ {{ end }}
315
536
resKeys, err := repo.datastoreClient.PutMulti(ctx, keys, subjects)
316
537
if err != nil {
317
538
return nil, err
@@ -344,7 +565,11 @@ func (repo *{{ .RepositoryStructName }}) UpdateMulti(ctx context.Context, subjec
344
565
return err
345
566
}
346
567
}
347
-
568
+ {{ if eq .EnableIndexes true }}
569
+ if err := repo.saveIndexes(subjects...); err != nil {
570
+ return xerrors.Errorf("error in saveIndexes method: %w", err)
571
+ }
572
+ {{ end }}
348
573
_, err = repo.datastoreClient.PutMulti(ctx, keys, subjects)
349
574
if err != nil {
350
575
return err
0 commit comments