From f8a3bafa263b570a73ce1132aab3704a9e81408e Mon Sep 17 00:00:00 2001 From: Masahiro Sano Date: Mon, 8 Jun 2020 12:49:59 +0900 Subject: [PATCH] update memefish to support foreign key (#42) --- go.mod | 6 +- go.sum | 13 +- test/testdata/schema.sql | 12 + test/testmodels/customtypes/fereignitem.yo.go | 176 ++++++++++ test/testmodels/customtypes/item.yo.go | 170 +++++++++ test/testmodels/default/fereignitem.yo.go | 176 ++++++++++ test/testmodels/default/item.yo.go | 170 +++++++++ test/testmodels/single/single_file.go | 324 ++++++++++++++++++ 8 files changed, 1038 insertions(+), 9 deletions(-) create mode 100644 test/testmodels/customtypes/fereignitem.yo.go create mode 100644 test/testmodels/customtypes/item.yo.go create mode 100644 test/testmodels/default/fereignitem.yo.go create mode 100644 test/testmodels/default/item.yo.go diff --git a/go.mod b/go.mod index d5b985f..068ca00 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( cloud.google.com/go v0.56.0 cloud.google.com/go/spanner v1.5.1 - github.com/MakeNowJust/memefish v0.0.0-20190917025248-4520997b3960 + github.com/MakeNowJust/memefish v0.0.0-20200430105843-c8e9c6d29dd6 github.com/gcpug/handy-spanner v0.6.2 github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 github.com/golang/protobuf v1.4.0 @@ -13,13 +13,11 @@ require ( github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 github.com/jinzhu/inflection v1.0.0 github.com/knq/snaker v0.0.0-20181215144011-2bc8a4db4687 - github.com/mattn/go-isatty v0.0.11 // indirect github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 // indirect google.golang.org/api v0.21.0 google.golang.org/genproto v0.0.0-20200416231807-8751e049a2a0 google.golang.org/grpc v1.28.1 - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/yaml.v2 v2.2.7 + gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index aff4ac5..93131aa 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZ github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM= github.com/MakeNowJust/memefish v0.0.0-20190917025248-4520997b3960 h1:SO/okB0gB+nJ3xvvVn/VDUWTIsnVQGnxC1rv/P2NEHI= github.com/MakeNowJust/memefish v0.0.0-20190917025248-4520997b3960/go.mod h1:kW35XLkNaGGQ8A126qYYha2RCWZMIkkR4zSfHrHdLOI= +github.com/MakeNowJust/memefish v0.0.0-20200430105843-c8e9c6d29dd6 h1:Dml87l7vEqgp5AEvyU9jA26eaA8LZ8tdHOXkBX1YsYQ= +github.com/MakeNowJust/memefish v0.0.0-20200430105843-c8e9c6d29dd6/go.mod h1:1ft7DGastdJzagZDRTdbkXNqh48UTbjEOHofr2pUz90= github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -177,6 +179,7 @@ github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfE github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/k0kubun/pp v1.3.1-0.20200204103551-99835366d1cc/go.mod h1:qK2ivXw91omfE1uXcpR5kWbAMZRdDOnGbqWlZ7reRFk= github.com/k0kubun/pp v3.0.2-0.20190719145753-b20d3da80efa+incompatible h1:46zqq9SllBiviBmvTmkM73qrMs0S9dEzJAr1XFnSid4= github.com/k0kubun/pp v3.0.2-0.20190719145753-b20d3da80efa+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= @@ -209,8 +212,8 @@ github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -387,10 +390,10 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -536,8 +539,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/test/testdata/schema.sql b/test/testdata/schema.sql index 9ec8fa0..b82a401 100644 --- a/test/testdata/schema.sql +++ b/test/testdata/schema.sql @@ -86,3 +86,15 @@ CREATE TABLE snake_cases ( ) PRIMARY KEY(id); CREATE INDEX snake_cases_by_string_id ON snake_cases(string_id, foo_bar_baz); + +CREATE TABLE Items ( + ID INT64 NOT NULL, + Price INT64 NOT NULL, +) PRIMARY KEY (ID); + +CREATE TABLE FereignItems ( + ID INT64 NOT NULL, + ItemID INT64 NOT NULL, + Category INT64 NOT NULL, + CONSTRAINT FK_ItemID_ForeignItems FOREIGN KEY (ItemID) REFERENCES Items (ID) +) PRIMARY KEY (ID); diff --git a/test/testmodels/customtypes/fereignitem.yo.go b/test/testmodels/customtypes/fereignitem.yo.go new file mode 100644 index 0000000..4d6906f --- /dev/null +++ b/test/testmodels/customtypes/fereignitem.yo.go @@ -0,0 +1,176 @@ +// Code generated by yo. DO NOT EDIT. +// Package customtypes contains the types. +package customtypes + +import ( + "context" + "fmt" + + "cloud.google.com/go/spanner" + "google.golang.org/grpc/codes" +) + +// FereignItem represents a row from 'FereignItems'. +type FereignItem struct { + ID int64 `spanner:"ID" json:"ID"` // ID + ItemID int64 `spanner:"ItemID" json:"ItemID"` // ItemID + Category int64 `spanner:"Category" json:"Category"` // Category +} + +func FereignItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func FereignItemColumns() []string { + return []string{ + "ID", + "ItemID", + "Category", + } +} + +func (fi *FereignItem) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &fi.ID) + case "ItemID": + ret = append(ret, &fi.ItemID) + case "Category": + ret = append(ret, &fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (fi *FereignItem) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, fi.ID) + case "ItemID": + ret = append(ret, fi.ItemID) + case "Category": + ret = append(ret, fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newFereignItem_Decoder returns a decoder which reads a row from *spanner.Row +// into FereignItem. The decoder is not goroutine-safe. Don't use it concurrently. +func newFereignItem_Decoder(cols []string) func(*spanner.Row) (*FereignItem, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*FereignItem, error) { + var fi FereignItem + ptrs, err := fi.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &fi, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (fi *FereignItem) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (fi *FereignItem) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (fi *FereignItem) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (fi *FereignItem) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, FereignItemPrimaryKeys()...) + + values, err := fi.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "FereignItem.UpdateColumns", "FereignItems", err) + } + + return spanner.Update("FereignItems", colsWithPKeys, values), nil +} + +// FindFereignItem gets a FereignItem by primary key +func FindFereignItem(ctx context.Context, db YORODB, id int64) (*FereignItem, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "FereignItems", key, FereignItemColumns()) + if err != nil { + return nil, newError("FindFereignItem", "FereignItems", err) + } + + decoder := newFereignItem_Decoder(FereignItemColumns()) + fi, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindFereignItem", "FereignItems", err) + } + + return fi, nil +} + +// ReadFereignItem retrieves multiples rows from FereignItem by KeySet as a slice. +func ReadFereignItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*FereignItem, error) { + var res []*FereignItem + + decoder := newFereignItem_Decoder(FereignItemColumns()) + + rows := db.Read(ctx, "FereignItems", keys, FereignItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + fi, err := decoder(row) + if err != nil { + return err + } + res = append(res, fi) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadFereignItem", "FereignItems", err) + } + + return res, nil +} + +// Delete deletes the FereignItem from the database. +func (fi *FereignItem) Delete(ctx context.Context) *spanner.Mutation { + values, _ := fi.columnsToValues(FereignItemPrimaryKeys()) + return spanner.Delete("FereignItems", spanner.Key(values)) +} diff --git a/test/testmodels/customtypes/item.yo.go b/test/testmodels/customtypes/item.yo.go new file mode 100644 index 0000000..ff463c5 --- /dev/null +++ b/test/testmodels/customtypes/item.yo.go @@ -0,0 +1,170 @@ +// Code generated by yo. DO NOT EDIT. +// Package customtypes contains the types. +package customtypes + +import ( + "context" + "fmt" + + "cloud.google.com/go/spanner" + "google.golang.org/grpc/codes" +) + +// Item represents a row from 'Items'. +type Item struct { + ID int64 `spanner:"ID" json:"ID"` // ID + Price int64 `spanner:"Price" json:"Price"` // Price +} + +func ItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func ItemColumns() []string { + return []string{ + "ID", + "Price", + } +} + +func (i *Item) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &i.ID) + case "Price": + ret = append(ret, &i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (i *Item) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, i.ID) + case "Price": + ret = append(ret, i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newItem_Decoder returns a decoder which reads a row from *spanner.Row +// into Item. The decoder is not goroutine-safe. Don't use it concurrently. +func newItem_Decoder(cols []string) func(*spanner.Row) (*Item, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*Item, error) { + var i Item + ptrs, err := i.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &i, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (i *Item) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (i *Item) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (i *Item) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (i *Item) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, ItemPrimaryKeys()...) + + values, err := i.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "Item.UpdateColumns", "Items", err) + } + + return spanner.Update("Items", colsWithPKeys, values), nil +} + +// FindItem gets a Item by primary key +func FindItem(ctx context.Context, db YORODB, id int64) (*Item, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "Items", key, ItemColumns()) + if err != nil { + return nil, newError("FindItem", "Items", err) + } + + decoder := newItem_Decoder(ItemColumns()) + i, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindItem", "Items", err) + } + + return i, nil +} + +// ReadItem retrieves multiples rows from Item by KeySet as a slice. +func ReadItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*Item, error) { + var res []*Item + + decoder := newItem_Decoder(ItemColumns()) + + rows := db.Read(ctx, "Items", keys, ItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + i, err := decoder(row) + if err != nil { + return err + } + res = append(res, i) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadItem", "Items", err) + } + + return res, nil +} + +// Delete deletes the Item from the database. +func (i *Item) Delete(ctx context.Context) *spanner.Mutation { + values, _ := i.columnsToValues(ItemPrimaryKeys()) + return spanner.Delete("Items", spanner.Key(values)) +} diff --git a/test/testmodels/default/fereignitem.yo.go b/test/testmodels/default/fereignitem.yo.go new file mode 100644 index 0000000..f98c91a --- /dev/null +++ b/test/testmodels/default/fereignitem.yo.go @@ -0,0 +1,176 @@ +// Code generated by yo. DO NOT EDIT. +// Package models contains the types. +package models + +import ( + "context" + "fmt" + + "cloud.google.com/go/spanner" + "google.golang.org/grpc/codes" +) + +// FereignItem represents a row from 'FereignItems'. +type FereignItem struct { + ID int64 `spanner:"ID" json:"ID"` // ID + ItemID int64 `spanner:"ItemID" json:"ItemID"` // ItemID + Category int64 `spanner:"Category" json:"Category"` // Category +} + +func FereignItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func FereignItemColumns() []string { + return []string{ + "ID", + "ItemID", + "Category", + } +} + +func (fi *FereignItem) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &fi.ID) + case "ItemID": + ret = append(ret, &fi.ItemID) + case "Category": + ret = append(ret, &fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (fi *FereignItem) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, fi.ID) + case "ItemID": + ret = append(ret, fi.ItemID) + case "Category": + ret = append(ret, fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newFereignItem_Decoder returns a decoder which reads a row from *spanner.Row +// into FereignItem. The decoder is not goroutine-safe. Don't use it concurrently. +func newFereignItem_Decoder(cols []string) func(*spanner.Row) (*FereignItem, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*FereignItem, error) { + var fi FereignItem + ptrs, err := fi.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &fi, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (fi *FereignItem) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (fi *FereignItem) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (fi *FereignItem) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (fi *FereignItem) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, FereignItemPrimaryKeys()...) + + values, err := fi.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "FereignItem.UpdateColumns", "FereignItems", err) + } + + return spanner.Update("FereignItems", colsWithPKeys, values), nil +} + +// FindFereignItem gets a FereignItem by primary key +func FindFereignItem(ctx context.Context, db YORODB, id int64) (*FereignItem, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "FereignItems", key, FereignItemColumns()) + if err != nil { + return nil, newError("FindFereignItem", "FereignItems", err) + } + + decoder := newFereignItem_Decoder(FereignItemColumns()) + fi, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindFereignItem", "FereignItems", err) + } + + return fi, nil +} + +// ReadFereignItem retrieves multiples rows from FereignItem by KeySet as a slice. +func ReadFereignItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*FereignItem, error) { + var res []*FereignItem + + decoder := newFereignItem_Decoder(FereignItemColumns()) + + rows := db.Read(ctx, "FereignItems", keys, FereignItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + fi, err := decoder(row) + if err != nil { + return err + } + res = append(res, fi) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadFereignItem", "FereignItems", err) + } + + return res, nil +} + +// Delete deletes the FereignItem from the database. +func (fi *FereignItem) Delete(ctx context.Context) *spanner.Mutation { + values, _ := fi.columnsToValues(FereignItemPrimaryKeys()) + return spanner.Delete("FereignItems", spanner.Key(values)) +} diff --git a/test/testmodels/default/item.yo.go b/test/testmodels/default/item.yo.go new file mode 100644 index 0000000..dd1b9ac --- /dev/null +++ b/test/testmodels/default/item.yo.go @@ -0,0 +1,170 @@ +// Code generated by yo. DO NOT EDIT. +// Package models contains the types. +package models + +import ( + "context" + "fmt" + + "cloud.google.com/go/spanner" + "google.golang.org/grpc/codes" +) + +// Item represents a row from 'Items'. +type Item struct { + ID int64 `spanner:"ID" json:"ID"` // ID + Price int64 `spanner:"Price" json:"Price"` // Price +} + +func ItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func ItemColumns() []string { + return []string{ + "ID", + "Price", + } +} + +func (i *Item) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &i.ID) + case "Price": + ret = append(ret, &i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (i *Item) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, i.ID) + case "Price": + ret = append(ret, i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newItem_Decoder returns a decoder which reads a row from *spanner.Row +// into Item. The decoder is not goroutine-safe. Don't use it concurrently. +func newItem_Decoder(cols []string) func(*spanner.Row) (*Item, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*Item, error) { + var i Item + ptrs, err := i.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &i, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (i *Item) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (i *Item) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (i *Item) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (i *Item) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, ItemPrimaryKeys()...) + + values, err := i.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "Item.UpdateColumns", "Items", err) + } + + return spanner.Update("Items", colsWithPKeys, values), nil +} + +// FindItem gets a Item by primary key +func FindItem(ctx context.Context, db YORODB, id int64) (*Item, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "Items", key, ItemColumns()) + if err != nil { + return nil, newError("FindItem", "Items", err) + } + + decoder := newItem_Decoder(ItemColumns()) + i, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindItem", "Items", err) + } + + return i, nil +} + +// ReadItem retrieves multiples rows from Item by KeySet as a slice. +func ReadItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*Item, error) { + var res []*Item + + decoder := newItem_Decoder(ItemColumns()) + + rows := db.Read(ctx, "Items", keys, ItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + i, err := decoder(row) + if err != nil { + return err + } + res = append(res, i) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadItem", "Items", err) + } + + return res, nil +} + +// Delete deletes the Item from the database. +func (i *Item) Delete(ctx context.Context) *spanner.Mutation { + values, _ := i.columnsToValues(ItemPrimaryKeys()) + return spanner.Delete("Items", spanner.Key(values)) +} diff --git a/test/testmodels/single/single_file.go b/test/testmodels/single/single_file.go index fd13776..6861852 100644 --- a/test/testmodels/single/single_file.go +++ b/test/testmodels/single/single_file.go @@ -206,6 +206,171 @@ func (cpk *CompositePrimaryKey) Delete(ctx context.Context) *spanner.Mutation { return spanner.Delete("CompositePrimaryKeys", spanner.Key(values)) } +// FereignItem represents a row from 'FereignItems'. +type FereignItem struct { + ID int64 `spanner:"ID" json:"ID"` // ID + ItemID int64 `spanner:"ItemID" json:"ItemID"` // ItemID + Category int64 `spanner:"Category" json:"Category"` // Category +} + +func FereignItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func FereignItemColumns() []string { + return []string{ + "ID", + "ItemID", + "Category", + } +} + +func (fi *FereignItem) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &fi.ID) + case "ItemID": + ret = append(ret, &fi.ItemID) + case "Category": + ret = append(ret, &fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (fi *FereignItem) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, fi.ID) + case "ItemID": + ret = append(ret, fi.ItemID) + case "Category": + ret = append(ret, fi.Category) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newFereignItem_Decoder returns a decoder which reads a row from *spanner.Row +// into FereignItem. The decoder is not goroutine-safe. Don't use it concurrently. +func newFereignItem_Decoder(cols []string) func(*spanner.Row) (*FereignItem, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*FereignItem, error) { + var fi FereignItem + ptrs, err := fi.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &fi, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (fi *FereignItem) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (fi *FereignItem) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (fi *FereignItem) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("FereignItems", FereignItemColumns(), []interface{}{ + fi.ID, fi.ItemID, fi.Category, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (fi *FereignItem) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, FereignItemPrimaryKeys()...) + + values, err := fi.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "FereignItem.UpdateColumns", "FereignItems", err) + } + + return spanner.Update("FereignItems", colsWithPKeys, values), nil +} + +// FindFereignItem gets a FereignItem by primary key +func FindFereignItem(ctx context.Context, db YORODB, id int64) (*FereignItem, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "FereignItems", key, FereignItemColumns()) + if err != nil { + return nil, newError("FindFereignItem", "FereignItems", err) + } + + decoder := newFereignItem_Decoder(FereignItemColumns()) + fi, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindFereignItem", "FereignItems", err) + } + + return fi, nil +} + +// ReadFereignItem retrieves multiples rows from FereignItem by KeySet as a slice. +func ReadFereignItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*FereignItem, error) { + var res []*FereignItem + + decoder := newFereignItem_Decoder(FereignItemColumns()) + + rows := db.Read(ctx, "FereignItems", keys, FereignItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + fi, err := decoder(row) + if err != nil { + return err + } + res = append(res, fi) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadFereignItem", "FereignItems", err) + } + + return res, nil +} + +// Delete deletes the FereignItem from the database. +func (fi *FereignItem) Delete(ctx context.Context) *spanner.Mutation { + values, _ := fi.columnsToValues(FereignItemPrimaryKeys()) + return spanner.Delete("FereignItems", spanner.Key(values)) +} + // FullType represents a row from 'FullTypes'. type FullType struct { PKey string `spanner:"PKey" json:"PKey"` // PKey @@ -527,6 +692,165 @@ func (ft *FullType) Delete(ctx context.Context) *spanner.Mutation { return spanner.Delete("FullTypes", spanner.Key(values)) } +// Item represents a row from 'Items'. +type Item struct { + ID int64 `spanner:"ID" json:"ID"` // ID + Price int64 `spanner:"Price" json:"Price"` // Price +} + +func ItemPrimaryKeys() []string { + return []string{ + "ID", + } +} + +func ItemColumns() []string { + return []string{ + "ID", + "Price", + } +} + +func (i *Item) columnsToPtrs(cols []string, customPtrs map[string]interface{}) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + if val, ok := customPtrs[col]; ok { + ret = append(ret, val) + continue + } + + switch col { + case "ID": + ret = append(ret, &i.ID) + case "Price": + ret = append(ret, &i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + return ret, nil +} + +func (i *Item) columnsToValues(cols []string) ([]interface{}, error) { + ret := make([]interface{}, 0, len(cols)) + for _, col := range cols { + switch col { + case "ID": + ret = append(ret, i.ID) + case "Price": + ret = append(ret, i.Price) + default: + return nil, fmt.Errorf("unknown column: %s", col) + } + } + + return ret, nil +} + +// newItem_Decoder returns a decoder which reads a row from *spanner.Row +// into Item. The decoder is not goroutine-safe. Don't use it concurrently. +func newItem_Decoder(cols []string) func(*spanner.Row) (*Item, error) { + customPtrs := map[string]interface{}{} + + return func(row *spanner.Row) (*Item, error) { + var i Item + ptrs, err := i.columnsToPtrs(cols, customPtrs) + if err != nil { + return nil, err + } + + if err := row.Columns(ptrs...); err != nil { + return nil, err + } + + return &i, nil + } +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func (i *Item) Insert(ctx context.Context) *spanner.Mutation { + return spanner.Insert("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func (i *Item) Update(ctx context.Context) *spanner.Mutation { + return spanner.Update("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +func (i *Item) InsertOrUpdate(ctx context.Context) *spanner.Mutation { + return spanner.InsertOrUpdate("Items", ItemColumns(), []interface{}{ + i.ID, i.Price, + }) +} + +// UpdateColumns returns a Mutation to update specified columns of a row in a table. +func (i *Item) UpdateColumns(ctx context.Context, cols ...string) (*spanner.Mutation, error) { + // add primary keys to columns to update by primary keys + colsWithPKeys := append(cols, ItemPrimaryKeys()...) + + values, err := i.columnsToValues(colsWithPKeys) + if err != nil { + return nil, newErrorWithCode(codes.InvalidArgument, "Item.UpdateColumns", "Items", err) + } + + return spanner.Update("Items", colsWithPKeys, values), nil +} + +// FindItem gets a Item by primary key +func FindItem(ctx context.Context, db YORODB, id int64) (*Item, error) { + key := spanner.Key{id} + row, err := db.ReadRow(ctx, "Items", key, ItemColumns()) + if err != nil { + return nil, newError("FindItem", "Items", err) + } + + decoder := newItem_Decoder(ItemColumns()) + i, err := decoder(row) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "FindItem", "Items", err) + } + + return i, nil +} + +// ReadItem retrieves multiples rows from Item by KeySet as a slice. +func ReadItem(ctx context.Context, db YORODB, keys spanner.KeySet) ([]*Item, error) { + var res []*Item + + decoder := newItem_Decoder(ItemColumns()) + + rows := db.Read(ctx, "Items", keys, ItemColumns()) + err := rows.Do(func(row *spanner.Row) error { + i, err := decoder(row) + if err != nil { + return err + } + res = append(res, i) + + return nil + }) + if err != nil { + return nil, newErrorWithCode(codes.Internal, "ReadItem", "Items", err) + } + + return res, nil +} + +// Delete deletes the Item from the database. +func (i *Item) Delete(ctx context.Context) *spanner.Mutation { + values, _ := i.columnsToValues(ItemPrimaryKeys()) + return spanner.Delete("Items", spanner.Key(values)) +} + // MaxLength represents a row from 'MaxLengths'. type MaxLength struct { MaxString string `spanner:"MaxString" json:"MaxString"` // MaxString