Skip to content

Commit 23c7d04

Browse files
committed
feat js data api
1 parent 01a0864 commit 23c7d04

File tree

7 files changed

+172
-90
lines changed

7 files changed

+172
-90
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ require (
2020
google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247 // indirect
2121
google.golang.org/grpc v1.42.0 // indirect
2222
gopkg.in/yaml.v2 v2.4.0 // indirect
23+
rogchap.com/v8go v0.6.0 // indirect
2324
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
746746
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
747747
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
748748
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
749+
rogchap.com/v8go v0.6.0 h1:wNn5Iu06+ke7HM511zXTVBBpRNYaauyZoPMTrLsGurU=
750+
rogchap.com/v8go v0.6.0/go.mod h1:IitZnaOtWSJadY/7qinKHIEHpxsilMWyLQ+Efdo4n4I=
749751
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
750752
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
751753
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

pkg/inserter/common_inserter.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package inserter
2+
3+
import (
4+
"context"
5+
"log"
6+
"strings"
7+
"time"
8+
9+
"cloud.google.com/go/firestore"
10+
"golang.org/x/xerrors"
11+
)
12+
13+
type CommonInserter struct {
14+
client *firestore.Client
15+
refIDs map[string]string
16+
}
17+
18+
func NewCommonInserter(client *firestore.Client) *CommonInserter {
19+
return &CommonInserter{
20+
client: client,
21+
refIDs: map[string]string{},
22+
}
23+
}
24+
25+
func (c *CommonInserter) CreateItem(ctx context.Context, cn, refID string, item map[string]interface{}) error {
26+
item = c.tryParseDate(item)
27+
item = c.setRefs(item)
28+
29+
d := c.client.Collection(cn).NewDoc()
30+
_, err := d.Create(ctx, item)
31+
if err != nil {
32+
return xerrors.Errorf("failed to create item: %w", err)
33+
}
34+
35+
if refID != "" {
36+
if _, ok := c.refIDs[refID]; ok {
37+
return xerrors.Errorf("already ref id: %s", refID)
38+
}
39+
c.refIDs[refID] = d.ID
40+
}
41+
42+
return nil
43+
}
44+
45+
func (ci *CommonInserter) tryParseDate(item map[string]interface{}) map[string]interface{} {
46+
for k, v := range item {
47+
switch vt := v.(type) {
48+
case string:
49+
pt, err := time.Parse(time.RFC3339, vt)
50+
if err != nil {
51+
// print log?
52+
continue
53+
}
54+
item[k] = pt
55+
56+
case map[string]interface{}:
57+
item[k] = ci.tryParseDate(vt)
58+
}
59+
}
60+
61+
return item
62+
}
63+
64+
func (ci *CommonInserter) setRefs(item map[string]interface{}) map[string]interface{} {
65+
for k, v := range item {
66+
switch vt := v.(type) {
67+
case string:
68+
if strings.HasPrefix(vt, "$") {
69+
refID := strings.TrimPrefix(vt, "$")
70+
rv, ok := ci.refIDs[refID]
71+
if !ok {
72+
log.Printf("%s was not found", refID)
73+
continue
74+
}
75+
item[k] = rv
76+
}
77+
}
78+
}
79+
80+
return item
81+
}

pkg/inserter/inserter.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ import (
1515

1616
type Inserter struct {
1717
jsonInserter *JSONInserter
18+
jsInserter *JSInserter
1819
}
1920

2021
func NewInserter(client *firestore.Client) *Inserter {
22+
ci := NewCommonInserter(client)
2123
return &Inserter{
22-
jsonInserter: NewJSONInserter(client),
24+
jsonInserter: NewJSONInserter(ci),
25+
jsInserter: NewJSInserter(ci),
2326
}
2427
}
2528

@@ -50,12 +53,15 @@ func (i *Inserter) executeFile(ctx context.Context) func(path string, info os.Fi
5053
var err error
5154
switch {
5255
case strings.HasSuffix(path, ".json"):
53-
err = i.jsonInserter.executeJSON(ctx, cn, path)
56+
err = i.jsonInserter.Execute(ctx, cn, path)
5457
if err != nil {
5558
log.Printf("failed to insert json file: %s\n%+v", path, err)
5659
}
5760
case strings.HasSuffix(path, ".js"):
58-
// TODO: implements here for js api
61+
err = i.jsInserter.Execute(ctx, cn, path)
62+
if err != nil {
63+
log.Printf("failed to insert js file: %s\n%+v", path, err)
64+
}
5965
}
6066

6167
return nil

pkg/inserter/js_inserter.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package inserter
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"os"
7+
8+
"golang.org/x/xerrors"
9+
v8 "rogchap.com/v8go"
10+
)
11+
12+
type JSInserter struct {
13+
ci *CommonInserter
14+
}
15+
16+
func NewJSInserter(ci *CommonInserter) *JSInserter {
17+
return &JSInserter{
18+
ci: ci,
19+
}
20+
}
21+
22+
func (j *JSInserter) Execute(ctx context.Context, cn, path string) error {
23+
b, err := os.ReadFile(path)
24+
if err != nil {
25+
return xerrors.Errorf("failed to js read from file: %w", err)
26+
}
27+
28+
v8ctx, err := v8.NewContext()
29+
if err != nil {
30+
return xerrors.Errorf("failed to create v8 context: %w", err)
31+
}
32+
33+
val, err := v8ctx.RunScript(string(b), path)
34+
if err != nil {
35+
return xerrors.Errorf("failed to run script: %s\n%w", path, err)
36+
}
37+
38+
if !val.IsArray() {
39+
return xerrors.Errorf("js returned data must be array")
40+
}
41+
obj, err := val.AsObject()
42+
if err != nil {
43+
return xerrors.Errorf("failed to convert object by returned value: %w", err)
44+
}
45+
46+
jb, err := obj.MarshalJSON()
47+
if err != nil {
48+
return xerrors.Errorf("failed to marshal json of returned value: %w", err)
49+
}
50+
51+
jms := make([]JsonModelItem, 0)
52+
err = json.Unmarshal(jb, &jms)
53+
if err != nil {
54+
return xerrors.Errorf("failed to unmarshal json: %w", err)
55+
}
56+
57+
for idx, item := range jms {
58+
err = j.ci.CreateItem(ctx, cn, item.Ref, item.Payload)
59+
if err != nil {
60+
return xerrors.Errorf("failed to create item (index: %d): %w", idx, err)
61+
}
62+
}
63+
64+
return nil
65+
}

pkg/inserter/json_inserter.go

Lines changed: 7 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,22 @@ package inserter
33
import (
44
"context"
55
"encoding/json"
6-
"log"
76
"os"
8-
"strings"
9-
"time"
107

11-
"cloud.google.com/go/firestore"
128
"golang.org/x/xerrors"
139
)
1410

1511
type JSONInserter struct {
16-
client *firestore.Client
17-
refIDs map[string]string
12+
ci *CommonInserter
1813
}
1914

20-
func NewJSONInserter(client *firestore.Client) *JSONInserter {
15+
func NewJSONInserter(ci *CommonInserter) *JSONInserter {
2116
return &JSONInserter{
22-
client: client,
23-
refIDs: map[string]string{},
17+
ci: ci,
2418
}
2519
}
2620

27-
func (j *JSONInserter) executeJSON(ctx context.Context, cn, path string) error {
21+
func (j *JSONInserter) Execute(ctx context.Context, cn, path string) error {
2822
jb, err := os.ReadFile(path)
2923
if err != nil {
3024
return xerrors.Errorf("failed to read json file: %+v", err)
@@ -36,83 +30,12 @@ func (j *JSONInserter) executeJSON(ctx context.Context, cn, path string) error {
3630
return xerrors.Errorf("failed to unmarshal json: %w", err)
3731
}
3832

39-
if payload, ok := jm.Payload.([]interface{}); ok {
40-
for idx, p := range payload {
41-
mp, ok := p.(map[string]interface{})
42-
if !ok {
43-
continue
44-
}
45-
err := j.createItem(ctx, cn, jm.Ref, mp)
46-
if err != nil {
47-
return xerrors.Errorf("failed to create item in array (index=%d): %w", idx, err)
48-
}
49-
}
50-
} else if payload, ok := jm.Payload.(map[string]interface{}); ok {
51-
err := j.createItem(ctx, cn, jm.Ref, payload)
33+
for idx, item := range jm.Items {
34+
err := j.ci.CreateItem(ctx, cn, item.Ref, item.Payload)
5235
if err != nil {
53-
return xerrors.Errorf("failed to create item: %w", err)
54-
}
55-
} else {
56-
// print log or error?
57-
}
58-
59-
return nil
60-
}
61-
62-
func (j *JSONInserter) createItem(ctx context.Context, cn, refID string, item map[string]interface{}) error {
63-
item = j.tryParseDate(item)
64-
item = j.setRefs(item)
65-
66-
d := j.client.Collection(cn).NewDoc()
67-
_, err := d.Create(ctx, item)
68-
if err != nil {
69-
return xerrors.Errorf("failed to create item: %w", err)
70-
}
71-
72-
if refID != "" {
73-
if _, ok := j.refIDs[refID]; ok {
74-
return xerrors.Errorf("already ref id: %s", refID)
36+
return xerrors.Errorf("failed to create item in array (index=%d): %w", idx, err)
7537
}
76-
j.refIDs[refID] = d.ID
7738
}
7839

7940
return nil
8041
}
81-
82-
func (j *JSONInserter) tryParseDate(item map[string]interface{}) map[string]interface{} {
83-
for k, v := range item {
84-
switch vt := v.(type) {
85-
case string:
86-
pt, err := time.Parse(time.RFC3339, vt)
87-
if err != nil {
88-
// print log?
89-
continue
90-
}
91-
item[k] = pt
92-
93-
case map[string]interface{}:
94-
item[k] = j.tryParseDate(vt)
95-
}
96-
}
97-
98-
return item
99-
}
100-
101-
func (j *JSONInserter) setRefs(item map[string]interface{}) map[string]interface{} {
102-
for k, v := range item {
103-
switch vt := v.(type) {
104-
case string:
105-
if strings.HasPrefix(vt, "$") {
106-
refID := strings.TrimPrefix(vt, "$")
107-
rv, ok := j.refIDs[refID]
108-
if !ok {
109-
log.Printf("%s was not found", refID)
110-
continue
111-
}
112-
item[k] = rv
113-
}
114-
}
115-
}
116-
117-
return item
118-
}

pkg/inserter/json_model.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package inserter
22

33
type JsonModel struct {
4-
Version string `json:"version"`
5-
Ref string `json:"ref"`
6-
Payload interface{} `json:"payload"`
4+
Version string `json:"version"`
5+
Items []JsonModelItem `json:"items"`
6+
}
7+
8+
type JsonModelItem struct {
9+
Ref string `json:"ref"`
10+
Payload map[string]interface{} `json:"payload"`
711
}

0 commit comments

Comments
 (0)