From d0cb404675aba768f0e47b10db63f4df6b7e7dc5 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Sun, 18 Feb 2024 07:59:18 +0300 Subject: [PATCH 01/18] support connection of go-tarantool --- go.mod | 1 + go.sum | 15 +++++ pkg/activerecord/hash.go | 49 ++++++++++++++++ pkg/octopus/options.go | 41 +++---------- pkg/tarantool/box.go | 112 ++++++++++++++++++++++++++++++++++++ pkg/tarantool/connection.go | 37 ++++++++++++ pkg/tarantool/options.go | 85 +++++++++++++++++++++++++++ 7 files changed, 308 insertions(+), 32 deletions(-) create mode 100644 pkg/activerecord/hash.go create mode 100644 pkg/tarantool/box.go create mode 100644 pkg/tarantool/connection.go create mode 100644 pkg/tarantool/options.go diff --git a/go.mod b/go.mod index d0db24b..1e76d6a 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 + github.com/tarantool/go-tarantool v1.6.0 golang.org/x/mod v0.7.0 golang.org/x/net v0.7.0 golang.org/x/sync v0.1.0 diff --git a/go.sum b/go.sum index 4d072af..5e318f3 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,15 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 h1:x3Zw96Gt6HbEPUWsTbQYj/nfaNv5lWHy6CeEkl8gwqw= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45/go.mod h1:guLmlFj8yjd0hoz+QWxRU4Gn+VOb2nOQZ4EqRmMHarw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -19,22 +24,32 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tarantool/go-tarantool v1.6.0/go.mod h1:SFamRDArn3Be+qwzMzdzQqGz9/D9mgSb3xCpKxbqMjQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/activerecord/hash.go b/pkg/activerecord/hash.go new file mode 100644 index 0000000..578368b --- /dev/null +++ b/pkg/activerecord/hash.go @@ -0,0 +1,49 @@ +package activerecord + +import ( + "encoding/binary" + "encoding/hex" + "fmt" + "hash" +) + +type GroupHash struct { + hash hash.Hash32 + calculated bool +} + +func NewGroupHash(hash hash.Hash32) *GroupHash { + return &GroupHash{hash: hash} +} + +func (o *GroupHash) UpdateHash(data ...interface{}) error { + if o.calculated { + return fmt.Errorf("can't update hash after calculate") + } + + for _, data := range data { + var err error + + switch v := data.(type) { + case string: + err = binary.Write(o.hash, binary.LittleEndian, []byte(v)) + case int: + err = binary.Write(o.hash, binary.LittleEndian, int64(v)) + default: + err = binary.Write(o.hash, binary.LittleEndian, v) + } + + if err != nil { + return fmt.Errorf("can't calculate connectionID: %w", err) + } + } + + return nil +} + +func (o *GroupHash) GetHash() string { + o.calculated = true + hashInBytes := o.hash.Sum(nil)[:] + + return hex.EncodeToString(hashInBytes) +} diff --git a/pkg/octopus/options.go b/pkg/octopus/options.go index 8580795..fcd7ff1 100644 --- a/pkg/octopus/options.go +++ b/pkg/octopus/options.go @@ -1,10 +1,7 @@ package octopus import ( - "encoding/binary" - "encoding/hex" "fmt" - "hash" "hash/crc32" "time" @@ -36,11 +33,10 @@ const ( // ConnectionOptions - опции используемые для подключения type ConnectionOptions struct { - server string - Mode ServerModeType - poolCfg *iproto.PoolConfig - connectionHash hash.Hash32 - calculated bool + *activerecord.GroupHash + server string + Mode ServerModeType + poolCfg *iproto.PoolConfig } // NewOptions - cоздание структуры с опциями и дефолтными значениями. Для мидификации значений по умолчанию, @@ -65,9 +61,10 @@ func NewOptions(server string, mode ServerModeType, opts ...ConnectionOption) (* PingInterval: DefaultPingInterval, }, }, - connectionHash: crc32.New(crc32table), } + octopusOpts.GroupHash = activerecord.NewGroupHash(crc32.New(crc32table)) + for _, opt := range opts { if err := opt.apply(octopusOpts); err != nil { return nil, fmt.Errorf("error apply options: %w", err) @@ -84,25 +81,8 @@ func NewOptions(server string, mode ServerModeType, opts ...ConnectionOption) (* // UpdateHash - функция расчета ConnectionID, необходима для шаринга конектов между моделями. func (o *ConnectionOptions) UpdateHash(data ...interface{}) error { - if o.calculated { - return fmt.Errorf("can't update hash after calculate") - } - - for _, data := range data { - var err error - - switch v := data.(type) { - case string: - err = binary.Write(o.connectionHash, binary.LittleEndian, []byte(v)) - case int: - err = binary.Write(o.connectionHash, binary.LittleEndian, int64(v)) - default: - err = binary.Write(o.connectionHash, binary.LittleEndian, v) - } - - if err != nil { - return fmt.Errorf("can't calculate connectionID: %w", err) - } + if err := o.GroupHash.UpdateHash(data); err != nil { + return fmt.Errorf("can't calculate group hash: %w", err) } return nil @@ -110,10 +90,7 @@ func (o *ConnectionOptions) UpdateHash(data ...interface{}) error { // GetConnectionID - получение ConnecitionID. После первого получения, больше нельзя его модифицировать. Можно только новый Options создать func (o *ConnectionOptions) GetConnectionID() string { - o.calculated = true - hashInBytes := o.connectionHash.Sum(nil)[:] - - return hex.EncodeToString(hashInBytes) + return o.GroupHash.GetHash() } // InstanceMode - метод для получения режима аботы инстанса RO или RW diff --git a/pkg/tarantool/box.go b/pkg/tarantool/box.go new file mode 100644 index 0000000..6f025ef --- /dev/null +++ b/pkg/tarantool/box.go @@ -0,0 +1,112 @@ +package tarantool + +import ( + "context" + "fmt" + + "github.com/mailru/activerecord/pkg/activerecord" +) + +var DefaultOptionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) { + return NewOptions(sic.Addr, sic.Mode, WithTimeout(sic.Timeout)) +} + +func Box(ctx context.Context, shard int, instType activerecord.ShardInstanceType, configPath string, optionCreator func(activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error)) (*Connection, error) { + if optionCreator == nil { + optionCreator = DefaultOptionCreator + } + + clusterInfo, err := activerecord.ConfigCacher().Get( + ctx, + configPath, + DefaultConnectionParams, + optionCreator, + ) + if err != nil { + return nil, fmt.Errorf("can't get cluster %s info: %w", configPath, err) + } + + if clusterInfo.Shards() < shard { + return nil, fmt.Errorf("invalid shard num %d, max = %d", shard, clusterInfo.Shards()) + } + + var ( + configBox activerecord.ShardInstance + ok bool + ) + + switch instType { + case activerecord.ReplicaInstanceType: + configBox, ok = clusterInfo.NextReplica(shard) + if !ok { + return nil, fmt.Errorf("replicas not set") + } + case activerecord.ReplicaOrMasterInstanceType: + configBox, ok = clusterInfo.NextReplica(shard) + if ok { + break + } + + fallthrough + case activerecord.MasterInstanceType: + configBox = clusterInfo.NextMaster(shard) + } + + conn, err := activerecord.ConnectionCacher().GetOrAdd(configBox, func(options interface{}) (activerecord.ConnectionInterface, error) { + octopusOpt, ok := options.(*ConnectionOptions) + if !ok { + return nil, fmt.Errorf("invalit type of options %T, want Options", options) + } + + return GetConnection(ctx, octopusOpt) + }) + if err != nil { + return nil, fmt.Errorf("error from connectionCacher: %w", err) + } + + box, ex := conn.(*Connection) + if !ex { + return nil, fmt.Errorf("invalid connection type %T, want *tarantool.Connection", conn) + } + + return box, nil +} + +func CheckShardInstance(ctx context.Context, instance activerecord.ShardInstance) (activerecord.OptionInterface, error) { + opts, ok := instance.Options.(*ConnectionOptions) + if !ok { + return nil, fmt.Errorf("invalit type of options %T, want Options", instance.Options) + } + + var err error + c := activerecord.ConnectionCacher().Get(instance) + if c == nil { + c, err = GetConnection(ctx, opts) + if err != nil { + return nil, fmt.Errorf("error from connectionCacher: %w", err) + } + } + + conn, ok := c.(*Connection) + if !ok { + return nil, fmt.Errorf("invalid connection type %T, want *tarantool.Connection", conn) + } + + var res []bool + + if err = conn.Call17Typed("dostring", []interface{}{"return box.info.ro"}, &res); err != nil { + return nil, fmt.Errorf("can't get instance status: %w", err) + } + + if len(res) == 1 { + ret := res[0] + switch ret { + case false: + return NewOptions(opts.server, activerecord.ModeMaster) + default: + return NewOptions(opts.server, activerecord.ModeReplica) + } + } + + return nil, fmt.Errorf("can't parse instance status: %w", err) +} diff --git a/pkg/tarantool/connection.go b/pkg/tarantool/connection.go new file mode 100644 index 0000000..3c17477 --- /dev/null +++ b/pkg/tarantool/connection.go @@ -0,0 +1,37 @@ +package tarantool + +import ( + "context" + "fmt" + + "github.com/mailru/activerecord/pkg/activerecord" + "github.com/tarantool/go-tarantool" +) + +var DefaultConnectionParams = activerecord.MapGlobParam{ + Timeout: DefaultConnectionTimeout, +} + +type Connection struct { + *tarantool.Connection +} + +func GetConnection(_ context.Context, opts *ConnectionOptions) (*Connection, error) { + conn, err := tarantool.Connect(opts.server, opts.cfg) + if err != nil { + return nil, fmt.Errorf("error connect to tarantool %s with connect timeout '%d': %s", opts.server, opts.cfg.Timeout, err) + } + + return &Connection{conn}, nil +} + +func (c *Connection) Close() { + if err := c.Connection.Close(); err != nil { + panic(err) + } + +} + +func (c *Connection) Done() <-chan struct{} { + return nil +} diff --git a/pkg/tarantool/options.go b/pkg/tarantool/options.go new file mode 100644 index 0000000..f8eefef --- /dev/null +++ b/pkg/tarantool/options.go @@ -0,0 +1,85 @@ +package tarantool + +import ( + "fmt" + "hash/crc32" + "time" + + "github.com/mailru/activerecord/pkg/activerecord" + "github.com/tarantool/go-tarantool" +) + +const DefaultConnectionTimeout = 20 * time.Millisecond + +type ConnectionOptions struct { + *activerecord.GroupHash + cfg tarantool.Opts + server string + Mode activerecord.ServerModeType +} + +type ConnectionOption interface { + apply(*ConnectionOptions) error +} + +type optionConnectionFunc func(*ConnectionOptions) error + +func (o optionConnectionFunc) apply(c *ConnectionOptions) error { + return o(c) +} + +// WithTimeout - опция для изменений таймаутов +func WithTimeout(request time.Duration) ConnectionOption { + return optionConnectionFunc(func(opts *ConnectionOptions) error { + opts.cfg.Timeout = request + + return opts.UpdateHash("T", request) + }) +} + +// WithCredential - опция авторизации +func WithCredential(user, pass string) ConnectionOption { + return optionConnectionFunc(func(opts *ConnectionOptions) error { + opts.cfg.User = user + opts.cfg.Pass = pass + + return opts.UpdateHash("L", user, pass) + }) +} + +func NewOptions(server string, mode activerecord.ServerModeType, opts ...ConnectionOption) (*ConnectionOptions, error) { + if server == "" { + return nil, fmt.Errorf("invalid param: server is empty") + } + + connectionOpts := &ConnectionOptions{ + cfg: tarantool.Opts{ + Timeout: DefaultConnectionTimeout, + }, + server: server, + Mode: mode, + } + + connectionOpts.GroupHash = activerecord.NewGroupHash(crc32.NewIEEE()) + + for _, opt := range opts { + if err := opt.apply(connectionOpts); err != nil { + return nil, fmt.Errorf("error apply options: %w", err) + } + } + + err := connectionOpts.UpdateHash("S", server) + if err != nil { + return nil, fmt.Errorf("can't get pool: %w", err) + } + + return connectionOpts, nil +} + +func (c *ConnectionOptions) GetConnectionID() string { + return c.GetHash() +} + +func (c *ConnectionOptions) InstanceMode() activerecord.ServerModeType { + return c.Mode +} From c3cb7002054f4a57a27fcac22a8e3386a16858ef Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:04:56 +0300 Subject: [PATCH 02/18] add connection options --- pkg/activerecord/hash.go | 4 ++-- pkg/octopus/options.go | 2 +- pkg/tarantool/connection.go | 14 +++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/activerecord/hash.go b/pkg/activerecord/hash.go index 578368b..649119e 100644 --- a/pkg/activerecord/hash.go +++ b/pkg/activerecord/hash.go @@ -21,10 +21,10 @@ func (o *GroupHash) UpdateHash(data ...interface{}) error { return fmt.Errorf("can't update hash after calculate") } - for _, data := range data { + for _, v := range data { var err error - switch v := data.(type) { + switch v := v.(type) { case string: err = binary.Write(o.hash, binary.LittleEndian, []byte(v)) case int: diff --git a/pkg/octopus/options.go b/pkg/octopus/options.go index fcd7ff1..5e75c1c 100644 --- a/pkg/octopus/options.go +++ b/pkg/octopus/options.go @@ -81,7 +81,7 @@ func NewOptions(server string, mode ServerModeType, opts ...ConnectionOption) (* // UpdateHash - функция расчета ConnectionID, необходима для шаринга конектов между моделями. func (o *ConnectionOptions) UpdateHash(data ...interface{}) error { - if err := o.GroupHash.UpdateHash(data); err != nil { + if err := o.GroupHash.UpdateHash(data...); err != nil { return fmt.Errorf("can't calculate group hash: %w", err) } diff --git a/pkg/tarantool/connection.go b/pkg/tarantool/connection.go index 3c17477..0956164 100644 --- a/pkg/tarantool/connection.go +++ b/pkg/tarantool/connection.go @@ -14,6 +14,7 @@ var DefaultConnectionParams = activerecord.MapGlobParam{ type Connection struct { *tarantool.Connection + opts *ConnectionOptions } func GetConnection(_ context.Context, opts *ConnectionOptions) (*Connection, error) { @@ -22,7 +23,14 @@ func GetConnection(_ context.Context, opts *ConnectionOptions) (*Connection, err return nil, fmt.Errorf("error connect to tarantool %s with connect timeout '%d': %s", opts.server, opts.cfg.Timeout, err) } - return &Connection{conn}, nil + return &Connection{ + Connection: conn, + opts: opts, + }, nil +} + +func (c *Connection) InstanceMode() any { + return c.opts.InstanceMode() } func (c *Connection) Close() { @@ -35,3 +43,7 @@ func (c *Connection) Close() { func (c *Connection) Done() <-chan struct{} { return nil } + +func (c *Connection) Info() string { + return fmt.Sprintf("Server: %s, timeout; %d, user: %s", c.opts.server, c.opts.cfg.Timeout, c.opts.cfg.User) +} From f6936f606c68a584d972e5813cb2f9fd8463c093 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:29:26 +0300 Subject: [PATCH 03/18] update go.mod --- go.mod | 6 ++++-- go.sum | 10 +++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 1e76d6a..465df18 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,19 @@ require ( github.com/tarantool/go-tarantool v1.6.0 golang.org/x/mod v0.7.0 golang.org/x/net v0.7.0 - golang.org/x/sync v0.1.0 golang.org/x/sys v0.5.0 golang.org/x/text v0.7.0 golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 golang.org/x/tools v0.5.0 - gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + gopkg.in/vmihailenco/msgpack.v2 v2.9.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 5e318f3..8eb6c71 100644 --- a/go.sum +++ b/go.sum @@ -3,14 +3,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 h1:x3Zw96Gt6HbEPUWsTbQYj/nfaNv5lWHy6CeEkl8gwqw= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45/go.mod h1:guLmlFj8yjd0hoz+QWxRU4Gn+VOb2nOQZ4EqRmMHarw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -24,6 +27,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tarantool/go-tarantool v1.6.0 h1:D/GW7hw9r8MbvSfcHqr6tT7brO7nqwhtWKJMj6OtArw= github.com/tarantool/go-tarantool v1.6.0/go.mod h1:SFamRDArn3Be+qwzMzdzQqGz9/D9mgSb3xCpKxbqMjQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= @@ -31,8 +35,6 @@ golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -45,10 +47,12 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2 h1:gjPqo9orRVlSAH/065qw3MsFCDpH7fa1KpiizXyllY4= gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From a9652e71ded443e08c9ae10e4608c90dbb8b8015 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:36:06 +0300 Subject: [PATCH 04/18] implement tarantool2 backend generator --- go.mod | 7 +- go.sum | 25 ++- internal/pkg/checker/checker.go | 6 + internal/pkg/generator/fixture.go | 55 ----- internal/pkg/generator/fixture_test.go | 2 +- internal/pkg/generator/generator.go | 140 ++++++++---- internal/pkg/generator/octopus.go | 46 +++- internal/pkg/generator/tarantool.go | 105 +++++++++ .../pkg/generator/tmpl/tarantool/fixture.tmpl | 67 ++++++ .../tmpl/tarantool/fixturestore.tmpl | 72 ++++++ .../pkg/generator/tmpl/tarantool/main.tmpl | 210 ++++++++++++++++++ pkg/octopus/types.go | 12 +- pkg/tarantool/types.go | 24 ++ 13 files changed, 659 insertions(+), 112 deletions(-) create mode 100644 internal/pkg/generator/tarantool.go create mode 100644 internal/pkg/generator/tmpl/tarantool/fixture.tmpl create mode 100644 internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl create mode 100644 internal/pkg/generator/tmpl/tarantool/main.tmpl create mode 100644 pkg/tarantool/types.go diff --git a/go.mod b/go.mod index d0db24b..465df18 100644 --- a/go.mod +++ b/go.mod @@ -8,19 +8,22 @@ require ( github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 + github.com/tarantool/go-tarantool v1.6.0 golang.org/x/mod v0.7.0 golang.org/x/net v0.7.0 - golang.org/x/sync v0.1.0 golang.org/x/sys v0.5.0 golang.org/x/text v0.7.0 golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 golang.org/x/tools v0.5.0 - gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + gopkg.in/vmihailenco/msgpack.v2 v2.9.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4d072af..8eb6c71 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 h1:x3Zw96Gt6HbEPUWsTbQYj/nfaNv5lWHy6CeEkl8gwqw= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45/go.mod h1:guLmlFj8yjd0hoz+QWxRU4Gn+VOb2nOQZ4EqRmMHarw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -19,22 +27,33 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tarantool/go-tarantool v1.6.0 h1:D/GW7hw9r8MbvSfcHqr6tT7brO7nqwhtWKJMj6OtArw= +github.com/tarantool/go-tarantool v1.6.0/go.mod h1:SFamRDArn3Be+qwzMzdzQqGz9/D9mgSb3xCpKxbqMjQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2 h1:gjPqo9orRVlSAH/065qw3MsFCDpH7fa1KpiizXyllY4= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/pkg/checker/checker.go b/internal/pkg/checker/checker.go index 16ea6b0..807744a 100644 --- a/internal/pkg/checker/checker.go +++ b/internal/pkg/checker/checker.go @@ -213,6 +213,12 @@ func Check(files map[string]*ds.RecordPackage, linkedObjects map[string]string) // Бекендозависимые проверки for _, backend := range cl.Backends { switch backend { + case "tarantool16": + fallthrough + case "tarantool2": + fallthrough + case "tarantool15": + fallthrough case "octopus": if err := checkOctopus(cl); err != nil { return err diff --git a/internal/pkg/generator/fixture.go b/internal/pkg/generator/fixture.go index 5b3a2c3..03eaf5e 100644 --- a/internal/pkg/generator/fixture.go +++ b/internal/pkg/generator/fixture.go @@ -1,16 +1,9 @@ package generator import ( - "bufio" - "bytes" _ "embed" - "io" - "strings" - "text/template" - "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" - "github.com/mailru/activerecord/pkg/iproto/util/text" ) type FixturePkgData struct { @@ -29,51 +22,3 @@ type FixturePkgData struct { Imports []ds.ImportDeclaration AppInfo string } - -func generateFixture(params FixturePkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { - fixtureWriter := bytes.Buffer{} - - fixtureFile := bufio.NewWriter(&fixtureWriter) - - err := GenerateFixtureTmpl(fixtureFile, params) - if err != nil { - return nil, err - } - - fixtureFile.Flush() - - ret := map[string]bytes.Buffer{ - "fixture": fixtureWriter, - } - - return ret, nil -} - -//go:embed tmpl/octopus/fixturestore.tmpl -var tmpl string - -func GenerateFixtureTmpl(dstFile io.Writer, params FixturePkgData) *arerror.ErrGeneratorPhases { - templatePackage, err := template.New(TemplateName).Funcs(templateFuncs).Funcs(OctopusTemplateFuncs).Parse(disclaimer + tmpl) - if err != nil { - tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+tmpl, "\n"), err.Error()) - if errgetline != nil { - tmplLines = errgetline.Error() - } - - return &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "parse", TmplLines: tmplLines, Err: err} - } - - err = templatePackage.Execute(dstFile, params) - if err != nil { - tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+tmpl, "\n"), err.Error()) - if errgetline != nil { - tmplLines = errgetline.Error() - } - - return &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "execute", TmplLines: tmplLines, Err: err} - } - - return nil -} - -var templateFuncs = template.FuncMap{"snakeCase": text.ToSnakeCase, "split": strings.Split} diff --git a/internal/pkg/generator/fixture_test.go b/internal/pkg/generator/fixture_test.go index 75b5590..3ff9c61 100644 --- a/internal/pkg/generator/fixture_test.go +++ b/internal/pkg/generator/fixture_test.go @@ -222,7 +222,7 @@ func TestGenerateFixture(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ret, got := generateFixture(tt.args.params) + ret, got := GenerateOctopusFixtureStore(tt.args.params) if got != tt.want { t.Errorf("GenerateFixture() = %v, want %v", got, tt.want) } diff --git a/internal/pkg/generator/generator.go b/internal/pkg/generator/generator.go index 37ce6a9..a21b6b9 100644 --- a/internal/pkg/generator/generator.go +++ b/internal/pkg/generator/generator.go @@ -12,6 +12,7 @@ import ( "strings" "text/template" + "github.com/mailru/activerecord/pkg/iproto/util/text" "github.com/pkg/errors" "golang.org/x/tools/imports" @@ -115,8 +116,13 @@ func GenerateMeta(params MetaData) ([]GenerateFile, *arerror.ErrGeneratorFile) { return []GenerateFile{genRes}, nil } -func GenerateByTmpl(dstFile io.Writer, params any, name, tmpl string) *arerror.ErrGeneratorPhases { - templatePackage, err := template.New(TemplateName).Funcs(funcs).Funcs(OctopusTemplateFuncs).Parse(disclaimer + tmpl) +func GenerateByTmpl(dstFile io.Writer, params any, name, tmpl string, tmplFuncs ...template.FuncMap) *arerror.ErrGeneratorPhases { + template := template.New(TemplateName).Funcs(funcs) + for _, f := range tmplFuncs { + template = template.Funcs(f) + } + + templatePackage, err := template.Parse(disclaimer + tmpl) if err != nil { tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+tmpl, "\n"), err.Error()) if errgetline != nil { @@ -162,7 +168,18 @@ func Generate(appInfo string, cl ds.RecordPackage, linkObject map[string]ds.Reco case "tarantool16": fallthrough case "tarantool2": - return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: backend, Err: arerror.ErrGeneratorBackendNotImplemented} + params := NewPkgData(appInfo, cl) + params.LinkedObject = linkObject + + log.Printf("Generate tarantool package (%v)", cl) + + var err *arerror.ErrGeneratorPhases + + generated, err = GenerateTarantool(params) + if err != nil { + err.Name = cl.Namespace.PublicName + return nil, err + } case "postgres": return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: backend, Err: arerror.ErrGeneratorBackendNotImplemented} default: @@ -224,53 +241,98 @@ func ErrorLine(errIn error, genData string) error { } func GenerateFixture(appInfo string, cl ds.RecordPackage, pkg string, pkgFixture string) ([]GenerateFile, error) { - var generated map[string]bytes.Buffer + var ret []GenerateFile - ret := make([]GenerateFile, 0, 1) + for _, backend := range cl.Backends { + var generated map[string]bytes.Buffer - params := FixturePkgData{ - FixturePkg: pkgFixture, - ARPkg: pkg, - ARPkgTitle: cl.Namespace.PublicName, - FieldList: cl.Fields, - FieldMap: cl.FieldsMap, - FieldObject: cl.FieldsObjectMap, - ProcInFieldList: cl.ProcInFields, - ProcOutFieldList: cl.ProcOutFields.List(), - Container: cl.Namespace, - Indexes: cl.Indexes, - Serializers: cl.SerializerMap, - Mutators: cl.MutatorMap, - Imports: cl.Imports, - AppInfo: appInfo, - } + switch backend { + case "tarantool15": + fallthrough + case "octopus": + params := FixturePkgData{ + FixturePkg: pkgFixture, + ARPkg: pkg, + ARPkgTitle: cl.Namespace.PublicName, + FieldList: cl.Fields, + FieldMap: cl.FieldsMap, + FieldObject: cl.FieldsObjectMap, + ProcInFieldList: cl.ProcInFields, + ProcOutFieldList: cl.ProcOutFields.List(), + Container: cl.Namespace, + Indexes: cl.Indexes, + Serializers: cl.SerializerMap, + Mutators: cl.MutatorMap, + Imports: cl.Imports, + AppInfo: appInfo, + } - log.Printf("Generate package (%v)", cl) + log.Printf("Generate package (%v)", cl) - var err *arerror.ErrGeneratorPhases + var err *arerror.ErrGeneratorPhases - generated, err = generateFixture(params) - if err != nil { - err.Name = cl.Namespace.PublicName - return nil, err - } + generated, err = GenerateOctopusFixtureStore(params) + if err != nil { + err.Name = cl.Namespace.PublicName + return nil, err + } + case "tarantool16": + fallthrough + case "tarantool2": + params := FixturePkgData{ + FixturePkg: pkgFixture, + ARPkg: pkg, + ARPkgTitle: cl.Namespace.PublicName, + FieldList: cl.Fields, + FieldMap: cl.FieldsMap, + FieldObject: cl.FieldsObjectMap, + ProcInFieldList: cl.ProcInFields, + ProcOutFieldList: cl.ProcOutFields.List(), + Container: cl.Namespace, + Indexes: cl.Indexes, + Serializers: cl.SerializerMap, + Mutators: cl.MutatorMap, + Imports: cl.Imports, + AppInfo: appInfo, + } - for _, data := range generated { - genRes := GenerateFile{ - Dir: pkgFixture, - Name: cl.Namespace.PackageName + "_gen.go", - } + log.Printf("Generate package (%v)", cl) - genData := data.Bytes() + var err *arerror.ErrGeneratorPhases - dataImp, err := imports.Process("", genData, nil) - if err != nil { - return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: "fixture", Filename: genRes.Name, Err: ErrorLine(err, string(genData))} + generated, err = GenerateTarantoolFixtureStore(params) + if err != nil { + err.Name = cl.Namespace.PublicName + return nil, err + } + case "postgres": + return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: backend, Err: arerror.ErrGeneratorBackendNotImplemented} + default: + return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: backend, Err: arerror.ErrGeneratorBackendUnknown} } - genRes.Data = dataImp - ret = append(ret, genRes) + for _, data := range generated { + genRes := GenerateFile{ + Dir: pkgFixture, + Name: cl.Namespace.PackageName + "_gen.go", + } + + genData := data.Bytes() + + dataImp, err := imports.Process("", genData, nil) + if err != nil { + return nil, &arerror.ErrGeneratorFile{Name: cl.Namespace.PublicName, Backend: "fixture", Filename: genRes.Name, Err: ErrorLine(err, string(genData))} + } + + genRes.Data = dataImp + ret = append(ret, genRes) + } } return ret, nil } + +var funcs = template.FuncMap{ + "snakeCase": text.ToSnakeCase, + "split": strings.Split, +} diff --git a/internal/pkg/generator/octopus.go b/internal/pkg/generator/octopus.go index ef30e34..f427bd7 100644 --- a/internal/pkg/generator/octopus.go +++ b/internal/pkg/generator/octopus.go @@ -10,7 +10,6 @@ import ( "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" - "github.com/mailru/activerecord/pkg/iproto/util/text" "github.com/mailru/activerecord/pkg/octopus" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -28,8 +27,6 @@ var OctopusRootRepositoryTmpl string //go:embed tmpl/octopus/fixture.tmpl var OctopusFixtureRepositoryTmpl string -var funcs = template.FuncMap{"snakeCase": text.ToSnakeCase} - func GenerateOctopus(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { octopusWriter := bytes.Buffer{} mockWriter := bytes.Buffer{} @@ -38,7 +35,7 @@ func GenerateOctopus(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGener octopusFile := bufio.NewWriter(&octopusWriter) //TODO возможно имеет смысл разделить большой шаблон OctopusRootRepositoryTmpl для удобства поддержки - err := GenerateByTmpl(octopusFile, params, "octopus", OctopusRootRepositoryTmpl) + err := GenerateByTmpl(octopusFile, params, "octopus", OctopusRootRepositoryTmpl, OctopusTemplateFuncs) if err != nil { return nil, err } @@ -47,7 +44,7 @@ func GenerateOctopus(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGener mockFile := bufio.NewWriter(&mockWriter) - err = GenerateByTmpl(mockFile, params, "octopus", OctopusMockRepositoryTmpl) + err = GenerateByTmpl(mockFile, params, "octopus", OctopusMockRepositoryTmpl, OctopusTemplateFuncs) if err != nil { return nil, err } @@ -56,7 +53,7 @@ func GenerateOctopus(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGener fixtureFile := bufio.NewWriter(&fixtureWriter) - err = GenerateByTmpl(fixtureFile, params, "octopus", OctopusFixtureRepositoryTmpl) + err = GenerateByTmpl(fixtureFile, params, "octopus", OctopusFixtureRepositoryTmpl, OctopusTemplateFuncs) if err != nil { return nil, err } @@ -72,6 +69,43 @@ func GenerateOctopus(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGener return ret, nil } +//go:embed tmpl/octopus/fixturestore.tmpl +var fixtureStoreTmpl string + +func GenerateOctopusFixtureStore(params FixturePkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { + fixtureWriter := bytes.Buffer{} + + file := bufio.NewWriter(&fixtureWriter) + + templatePackage, err := template.New(TemplateName).Funcs(funcs).Funcs(OctopusTemplateFuncs).Parse(disclaimer + fixtureStoreTmpl) + if err != nil { + tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+fixtureStoreTmpl, "\n"), err.Error()) + if errgetline != nil { + tmplLines = errgetline.Error() + } + + return nil, &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "parse", TmplLines: tmplLines, Err: err} + } + + err = templatePackage.Execute(file, params) + if err != nil { + tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+fixtureStoreTmpl, "\n"), err.Error()) + if errgetline != nil { + tmplLines = errgetline.Error() + } + + return nil, &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "execute", TmplLines: tmplLines, Err: err} + } + + file.Flush() + + ret := map[string]bytes.Buffer{ + "fixture": fixtureWriter, + } + + return ret, nil +} + var OctopusTemplateFuncs = template.FuncMap{ "packerParam": func(format octopus.Format) OctopusFormatParam { ret, ex := OctopusFormatMapper[format] diff --git a/internal/pkg/generator/tarantool.go b/internal/pkg/generator/tarantool.go new file mode 100644 index 0000000..25bc39e --- /dev/null +++ b/internal/pkg/generator/tarantool.go @@ -0,0 +1,105 @@ +package generator + +import ( + "bufio" + "bytes" + _ "embed" + "strings" + "text/template" + + "github.com/mailru/activerecord/internal/pkg/arerror" + "github.com/mailru/activerecord/internal/pkg/ds" +) + +//nolint:revive +//go:embed tmpl/tarantool/main.tmpl +var tarantoolRootRepositoryTmpl string + +//nolint:revive +//go:embed tmpl/tarantool/fixture.tmpl +var tarantoolFixtureRepositoryTmpl string + +func GenerateTarantool(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { + mainWriter := bytes.Buffer{} + fixtureWriter := bytes.Buffer{} + + octopusFile := bufio.NewWriter(&mainWriter) + + err := GenerateByTmpl(octopusFile, params, "tarantool", tarantoolRootRepositoryTmpl, Tarantool2TmplFunc) + if err != nil { + return nil, err + } + + octopusFile.Flush() + + fixtureFile := bufio.NewWriter(&fixtureWriter) + + err = GenerateByTmpl(fixtureFile, params, "tarantool", tarantoolFixtureRepositoryTmpl, Tarantool2TmplFunc) + if err != nil { + return nil, err + } + + fixtureFile.Flush() + + ret := map[string]bytes.Buffer{ + "tarantool": mainWriter, + "fixture": fixtureWriter, + } + + return ret, nil +} + +//go:embed tmpl/tarantool/fixturestore.tmpl +var tarantoolFixtureStoreTmpl string + +func GenerateTarantoolFixtureStore(params FixturePkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { + fixtureWriter := bytes.Buffer{} + + file := bufio.NewWriter(&fixtureWriter) + + templatePackage, err := template.New(TemplateName).Funcs(funcs).Parse(disclaimer + tarantoolFixtureStoreTmpl) + if err != nil { + tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+tarantoolFixtureStoreTmpl, "\n"), err.Error()) + if errgetline != nil { + tmplLines = errgetline.Error() + } + + return nil, &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "parse", TmplLines: tmplLines, Err: err} + } + + err = templatePackage.Execute(file, params) + if err != nil { + tmplLines, errgetline := getTmplErrorLine(strings.SplitAfter(disclaimer+tarantoolFixtureStoreTmpl, "\n"), err.Error()) + if errgetline != nil { + tmplLines = errgetline.Error() + } + + return nil, &arerror.ErrGeneratorPhases{Backend: "fixture", Phase: "execute", TmplLines: tmplLines, Err: err} + } + + file.Flush() + + ret := map[string]bytes.Buffer{ + "fixture": fixtureWriter, + } + + return ret, nil +} + +var Tarantool2TmplFunc = template.FuncMap{ + "addImport": func(flds []ds.FieldDeclaration) (imports []string) { + var needStrconv bool + + for _, fld := range flds { + if fld.PrimaryKey && fld.Format != "string" { + needStrconv = true + } + } + + if needStrconv { + imports = append(imports, "strconv") + } + + return + }, +} diff --git a/internal/pkg/generator/tmpl/tarantool/fixture.tmpl b/internal/pkg/generator/tmpl/tarantool/fixture.tmpl new file mode 100644 index 0000000..11f6cc6 --- /dev/null +++ b/internal/pkg/generator/tmpl/tarantool/fixture.tmpl @@ -0,0 +1,67 @@ +package {{ .ARPkg }} + +import ( + "context" + "log" + + "gopkg.in/vmihailenco/msgpack.v2" + "gopkg.in/yaml.v3" +{{- range $ind, $imp := .Imports }} +{{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}" +{{- end }} +{{- range $i, $imp := addImport .FieldList }} + "{{ $imp }}" +{{- end }} +) + +{{ $PublicStructName := .ARPkgTitle -}} +{{ $serializers := .Serializers -}} +{{ $fields := .FieldList }} +{{ $procfields := .ProcOutFieldList }} + + +type {{ $PublicStructName }}FT struct { + {{- range $ind, $fstruct := .FieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $serlen := len $fstruct.Serializer -}} + {{ if ne $serlen 0 -}} + {{ $sname := index $fstruct.Serializer 0 -}} + {{ $serializer := index $serializers $sname -}} + {{ $rtype = $serializer.Type -}} + {{ end }} + {{ $fstruct.Name }} {{ $rtype -}} `yaml:"{{ $fstruct.Name | snakeCase -}}" mapstructure:"{{ $fstruct.Name | snakeCase -}}" json:"{{ $fstruct.Name | snakeCase -}}"` + {{- end }} +} + +func UnmarshalFixturesFromMessagePack(source []byte) ([]{{$PublicStructName}}FT, error) { + var fts []{{$PublicStructName}}FT + if err := msgpack.Unmarshal(source, &fts); err != nil { + return nil, err + } + + return fts, nil +} + +func UnmarshalFixtures(source []byte) []*{{$PublicStructName}} { + var fixtures []{{$PublicStructName}}FT + + if err := yaml.Unmarshal(source, &fixtures); err != nil { + log.Fatalf("unmarshal {{$PublicStructName}}FT fixture: %v", err) + } + + objs := make([]*{{$PublicStructName}}, 0, len(fixtures)) + + for _, ft := range fixtures { + + o := New(context.Background()) + {{- range $ind, $fstruct := .FieldList }} + if err := o.Set{{$fstruct.Name}}(ft.{{$fstruct.Name}}); err != nil { + log.Fatalf("can't set value %v to field {{$fstruct.Name}} of {{$PublicStructName}} fixture: %s", ft.{{$fstruct.Name}}, err) + } + {{- end }} + + objs = append(objs, o) + } + + return objs +} \ No newline at end of file diff --git a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl new file mode 100644 index 0000000..ead5655 --- /dev/null +++ b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl @@ -0,0 +1,72 @@ +package {{ .FixturePkg }} + +import ( + _ "embed" + "context" + "fmt" + "log" + "sync" + + "gopkg.in/yaml.v3" + + "github.com/mailru/activerecord/pkg/activerecord" + +{{- range $ind, $imp := .Imports }} +{{ if ne $imp.ImportName "" }}{{- $imp.ImportName }} {{ end }}"{{ $imp.Path }}" +{{- end }} +) + +{{ $serializers := .Serializers -}} +{{ $PackageName := .ARPkg -}} +{{ $PublicStructName := .ARPkgTitle -}} +{{ $fields := .FieldList }} +{{ $typePK := "" -}} +{{ $fieldNamePK := "" -}} + +{{ range $num, $ind := .Indexes -}} +{{ $lenfld := len $ind.Fields -}} + {{ if $ind.Primary }} + {{ if ne $lenfld 1 }} + {{ $typePK = print $PackageName "." $ind.Type }} + {{ else }} + {{- $typePK = $ind.Type -}} + {{ end }} + {{- $fieldNamePK = $ind.Name -}} + {{ end }} +{{ end }} + +var {{$PackageName}}Once sync.Once +var {{$PackageName}}Store map[{{$typePK}}]int +var {{$PackageName}}Fixtures []*{{$PackageName}}.{{$PublicStructName}} + +//go:embed data/{{$PackageName}}.yaml +var {{$PackageName}}Source []byte + +func init{{$PublicStructName}}() { + {{$PackageName}}Once.Do(func() { + {{$PackageName}}Fixtures = {{$PackageName}}.UnmarshalFixtures({{$PackageName}}Source) + + {{$PackageName}}Store = map[{{$typePK}}]int{} + for i, f := range {{$PackageName}}Fixtures { + if _, ok := {{$PackageName}}Store[f.Primary()]; ok { + log.Fatalf("{{$PackageName}} fixture with {{$fieldNamePK}} %v is duplicated", f.Primary()) + } + + {{$PackageName}}Store[f.Primary()] = i + } + }) +} + + +func Get{{$PublicStructName}}By{{$fieldNamePK}}({{$fieldNamePK}} {{$typePK}}) *{{$PackageName}}.{{$PublicStructName}} { + init{{$PublicStructName}}() + + idx, ex := {{$PackageName}}Store[{{$fieldNamePK}}] + if !ex { + log.Fatalf("{{$PublicStructName}} fixture with {{$fieldNamePK}} %v not found", {{$fieldNamePK}}) + } + + res := {{$PackageName}}Fixtures[idx] + + return res +} \ No newline at end of file diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl new file mode 100644 index 0000000..0309e22 --- /dev/null +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -0,0 +1,210 @@ +package {{ .ARPkg }} + +import ( + "bytes" + "context" + "fmt" + "log" +{{ if eq .Server.Conf "" -}} + "time" +{{ end }} + "strings" + + "github.com/mailru/activerecord/pkg/activerecord" + "github.com/mailru/activerecord/pkg/tarantool" + tarantool2 "github.com/tarantool/go-tarantool" + + +{{- range $ind, $imp := .Imports }} +{{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}" +{{- end }} +{{- range $i, $imp := addImport .FieldList }} + "{{ $imp }}" +{{- end }} +) + +{{ $pkgName := .ARPkg }} +{{ $serializers := .Serializers -}} +{{ $mutators := .Mutators -}} +{{ $PublicStructName := .ARPkgTitle -}} +{{ $LinkedObject := .LinkedObject }} +{{ $flags := .Flags }} +{{ $fields := .FieldList }} +{{ $procfields := .ProcOutFieldList }} +{{ $procInLen := len .ProcInFieldList }} +{{ $mutatorLen := len .Mutators }} + +{{ if $fields }} +type {{ $PublicStructName }} struct { +tarantool.BaseField +{{- range $ind, $fstruct := .FieldList -}} +{{ $rtype := $fstruct.Format -}} +{{ $serlen := len $fstruct.Serializer -}} +{{ if ne $serlen 0 -}} +{{ $sname := index $fstruct.Serializer 0 -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end }} +field{{ $fstruct.Name }} {{ $rtype -}} +{{ end }} +} + +const ( + namespace uint32 = {{ .Container.ObjectName }} + cntFields uint32 = {{ len .FieldList }} +{{- range $fieldname, $flag := .Flags -}} +{{ range $i, $flagname := $flag.Flags }} +{{ $fieldname }}{{ $flagname }}Flag = 1 << {{ $i -}} +{{ end -}} +{{ end }} +) + + +func New(ctx context.Context) *{{ $PublicStructName }} { + newObj := {{ $PublicStructName }}{} + {{- if $fields }} + newObj.BaseField.UpdateOps = []tarantool2.Op{} + newObj.BaseField.Objects = map[string][]tarantool.ModelStruct{} + {{ end }} + return &newObj +} + +func Create( + ctx context.Context, +{{- range $ind, $fstruct := .FieldList -}} +{{ $rtype := $fstruct.Format -}} +{{ $serlen := len $fstruct.Serializer -}} +{{ if ne $serlen 0 -}} +{{ $sname := index $fstruct.Serializer 0 -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end }} + v{{ $fstruct.Name }} {{ $rtype -}}, +{{- end -}} +) (*{{ $PublicStructName }}, error) { + obj := New(ctx) + + {{ range $ind, $fstruct := .FieldList }} + if err := obj.Set{{$fstruct.Name}}(v{{$fstruct.Name}}); err != nil { + return nil, fmt.Errorf("can't create new {{ $PublicStructName }}: %w", err) + } + {{ end }} + + return obj, nil +} + +func (obj *{{ $PublicStructName }}) PrimaryString() string { + ret := []string{ + {{- range $ind, $fstruct := .FieldList }} + {{- if $fstruct.PrimaryKey }} + obj.Get{{ $fstruct.Name }}(), + {{- end }} + {{- end }} + } + + return strings.Join(ret, ", ") +} + + +{{ $pktype := "" }} +{{ $pklenfld := 1 }} +{{ $pkind := index .Indexes 0 }} +{{ range $num, $ind := .Indexes -}} +{{ $lenfld := len $ind.Fields -}} +{{ if $ind.Primary }} +{{ $pktype = $ind.Type }} +{{ $pklenfld = len $ind.Fields }} +{{ $pkind = $ind }} +func (obj *{{ $PublicStructName }}) Primary() {{ $ind.Type }} { + {{ if ne $lenfld 1 }} + return {{ $ind.Type }}{ + {{- range $_, $fieldNum := $ind.Fields }} + {{- $ifield := index $fields $fieldNum }} + {{ $ifield.Name }}: obj.Get{{ $ifield.Name }}(), + {{- end }} + } + {{ else }} + {{- range $_, $fieldNum := $ind.Fields }} + {{- $ifield := index $fields $fieldNum }} + return obj.Get{{ $ifield.Name }}() + {{- end }} + {{ end -}} +} + +{{ end }} +{{ end }} + + + +{{end}} + +// Getters,Setters and Mutators + +{{ range $ind, $fstruct := .FieldList -}} +{{ $rtype := $fstruct.Format -}} +{{ $sname := $fstruct.Serializer.Name -}} + {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $rtype = $serializer.Type -}} + func Marshal{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) (any, error) { + {{ $serparams := $fstruct.Serializer.Params -}} + pvar, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $fstruct.Name }}) + if err != nil { + return nil, fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err) + } + + return pvar, nil + } + + {{ end -}} + +func (obj *{{ $PublicStructName }}) Get{{ $fstruct.Name }}() {{ $rtype }} { + return obj.field{{ $fstruct.Name }} +} + +func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) error { + {{- if $fstruct.PrimaryKey }} + if obj.BaseField.Exists { + return fmt.Errorf("can't modify field included in primary key") + } + + {{ end -}} + + {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $serparams := $fstruct.Serializer.Params -}} + data, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $fstruct.Name }}) + if err != nil { + return fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err) + } + {{- else }} + data := {{ $fstruct.Name }} + {{ end }} + + {{- if eq $fstruct.Format "string" "[]byte" -}} + {{- if gt $fstruct.Size 0 }} + + if len({{ $fstruct.Name }}) > {{ $fstruct.Size }} { + return fmt.Errorf("max length of field '{{ $PublicStructName }}.{{ $fstruct.Name }}' is '%d' (received '%d')", {{ $fstruct.Size }}, len(data)) + } + {{- else }} + + logger := activerecord.Logger() + + logger.Warn(context.TODO(), "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Size for field '{{ $fstruct.Name }}' not set. Cur field size: %d. Object: '{{ $PublicStructName }}'", len(data))) + {{- end }} + {{- end }} + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{"=", {{ $ind }}, data }) + obj.field{{ $fstruct.Name }} = {{ $fstruct.Name}} + + {{- if ne $fstruct.ObjectLink "" }} + delete(obj.BaseField.Objects, "{{ $fstruct.ObjectLink }}") + {{- end }} + + return nil +} + +{{ end -}} + +// End of Getters, Setters and Mutators diff --git a/pkg/octopus/types.go b/pkg/octopus/types.go index 64767ab..8e9f2ea 100644 --- a/pkg/octopus/types.go +++ b/pkg/octopus/types.go @@ -16,12 +16,6 @@ type TupleData struct { Data [][]byte } -type Ops struct { - Field uint32 - Op OpCode - Value []byte -} - type ModelStruct interface { Insert(ctx context.Context) error Replace(ctx context.Context) error @@ -30,6 +24,12 @@ type ModelStruct interface { Delete(ctx context.Context) error } +type Ops struct { + Field uint32 + Op OpCode + Value []byte +} + type BaseField struct { Collection []ModelStruct UpdateOps []Ops diff --git a/pkg/tarantool/types.go b/pkg/tarantool/types.go new file mode 100644 index 0000000..5dbe6b3 --- /dev/null +++ b/pkg/tarantool/types.go @@ -0,0 +1,24 @@ +package tarantool + +import ( + "context" + + "github.com/tarantool/go-tarantool" +) + +type ModelStruct interface { + Insert(ctx context.Context) error + Replace(ctx context.Context) error + InsertOrReplace(ctx context.Context) error + Update(ctx context.Context) error + Delete(ctx context.Context) error +} + +type BaseField struct { + Collection []ModelStruct + UpdateOps []tarantool.Op + Exists bool + IsReplica bool + ReadOnly bool + Objects map[string][]ModelStruct +} From 9b62f61cd8d80cf97acd15cc17b884007ce2b556 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 22 Feb 2024 06:15:03 +0300 Subject: [PATCH 05/18] fix tarantool2 backend generator --- internal/pkg/checker/checker.go | 39 +- internal/pkg/generator/tarantool.go | 33 ++ .../pkg/generator/tmpl/tarantool/main.tmpl | 539 +++++++++++++++++- pkg/tarantool/sqlbuilder.go | 21 + 4 files changed, 626 insertions(+), 6 deletions(-) create mode 100644 pkg/tarantool/sqlbuilder.go diff --git a/internal/pkg/checker/checker.go b/internal/pkg/checker/checker.go index 807744a..eb40c42 100644 --- a/internal/pkg/checker/checker.go +++ b/internal/pkg/checker/checker.go @@ -216,7 +216,9 @@ func Check(files map[string]*ds.RecordPackage, linkedObjects map[string]string) case "tarantool16": fallthrough case "tarantool2": - fallthrough + if err := checkTarantool(cl); err != nil { + return err + } case "tarantool15": fallthrough case "octopus": @@ -282,3 +284,38 @@ func checkOctopus(cl *ds.RecordPackage) error { return nil } + +//nolint:gocognit,gocyclo +func checkTarantool(cl *ds.RecordPackage) error { + if cl.Server.Host == "" && cl.Server.Conf == "" { + return &arerror.ErrCheckPackageDecl{Pkg: cl.Namespace.PackageName, Err: arerror.ErrCheckServerEmpty} + } + + if cl.Server.Host == "" && cl.Server.Port != "" { + return &arerror.ErrCheckPackageDecl{Pkg: cl.Namespace.PackageName, Err: arerror.ErrCheckPortEmpty} + } + + if cl.Server.Host != "" && cl.Server.Conf != "" { + return &arerror.ErrCheckPackageDecl{Pkg: cl.Namespace.PackageName, Err: arerror.ErrCheckServerConflict} + } + + for _, fl := range cl.Fields { + if (fl.Format == "string" || fl.Format == "[]byte") && fl.Size == 0 { + log.Printf("Warn: field `%s` declaration. Field with type string or []byte not contain size.", fl.Name) + } + } + + for _, ind := range cl.Indexes { + if len(ind.Fields) == 0 { + return &arerror.ErrCheckPackageIndexDecl{Pkg: cl.Namespace.PackageName, Index: ind.Name, Err: arerror.ErrCheckFieldIndexEmpty} + } + } + + for _, fld := range cl.ProcInFields { + if fld.Format != octopus.String && len(fld.Serializer) == 0 { + return &arerror.ErrCheckPackageFieldDecl{Pkg: cl.Namespace.PackageName, Field: fld.Name, Err: arerror.ErrCheckFieldSerializerNotFound} + } + } + + return nil +} diff --git a/internal/pkg/generator/tarantool.go b/internal/pkg/generator/tarantool.go index 25bc39e..7d4680c 100644 --- a/internal/pkg/generator/tarantool.go +++ b/internal/pkg/generator/tarantool.go @@ -4,11 +4,13 @@ import ( "bufio" "bytes" _ "embed" + "log" "strings" "text/template" "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" + "github.com/mailru/activerecord/pkg/octopus" ) //nolint:revive @@ -87,6 +89,14 @@ func GenerateTarantoolFixtureStore(params FixturePkgData) (map[string]bytes.Buff } var Tarantool2TmplFunc = template.FuncMap{ + "packerParam": func(format octopus.Format) TarantoolFormatParam { + ret, ex := PrimitiveTypeFormatConverter[format] + if !ex { + log.Fatalf("packer for type `%s` not found", format) + } + + return ret + }, "addImport": func(flds []ds.FieldDeclaration) (imports []string) { var needStrconv bool @@ -103,3 +113,26 @@ var Tarantool2TmplFunc = template.FuncMap{ return }, } + +type TarantoolFormatParam string + +func (p TarantoolFormatParam) ToString() []string { + return strings.SplitN(string(p), `%%`, 2) +} + +var PrimitiveTypeFormatConverter = map[octopus.Format]TarantoolFormatParam{ + octopus.Bool: "strconv.FormatBool(%%)", + octopus.Uint8: "strconv.FormatUint(uint64(%%), 10)", + octopus.Uint16: "strconv.FormatUint(uint64(%%), 10)", + octopus.Uint32: "strconv.FormatUint(uint64(%%), 10)", + octopus.Uint64: "strconv.FormatUint(%%, 10)", + octopus.Uint: "strconv.FormatUint(uint64(%%), 10)", + octopus.Int8: "strconv.FormatInt(int64(%%), 10)", + octopus.Int16: "strconv.FormatInt(int64(%%), 10)", + octopus.Int32: "strconv.FormatInt(int64(%%), 10)", + octopus.Int64: "strconv.FormatInt(%%, 10)", + octopus.Int: "strconv.FormatInt(int64(%%), 10)", + octopus.Float32: "strconv.FormatFloat(%%, 32)", + octopus.Float64: "strconv.FormatFloat(%%, 64)", + octopus.String: "%%", +} diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index 0309e22..d00ac99 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -13,7 +13,7 @@ import ( "github.com/mailru/activerecord/pkg/activerecord" "github.com/mailru/activerecord/pkg/tarantool" tarantool2 "github.com/tarantool/go-tarantool" - + "gopkg.in/vmihailenco/msgpack.v2" {{- range $ind, $imp := .Imports }} {{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}" @@ -35,6 +35,7 @@ import ( {{ $mutatorLen := len .Mutators }} {{ if $fields }} + type {{ $PublicStructName }} struct { tarantool.BaseField {{- range $ind, $fstruct := .FieldList -}} @@ -50,8 +51,8 @@ field{{ $fstruct.Name }} {{ $rtype -}} } const ( - namespace uint32 = {{ .Container.ObjectName }} - cntFields uint32 = {{ len .FieldList }} + namespace = "{{ .Container.ObjectName }}" + cntFields uint32 = {{ len .FieldList }} {{- range $fieldname, $flag := .Flags -}} {{ range $i, $flagname := $flag.Flags }} {{ $fieldname }}{{ $flagname }}Flag = 1 << {{ $i -}} @@ -59,6 +60,19 @@ const ( {{ end }} ) +{{ if eq .Server.Conf "" -}} +var boxOption, _ = tarantool.NewOptions( + "{{ .Server.Host }}:{{ .Server.Port }}", + activerecord.ModeMaster, + tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}, time.Millisecond * {{ .Server.Timeout }}), +) + +var clusterInfo = activerecord.NewClusterInfo( + activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}), +) +{{ else}} +var cfgName = "{{.Server.Conf }}" +{{ end }} func New(ctx context.Context) *{{ $PublicStructName }} { newObj := {{ $PublicStructName }}{} @@ -93,11 +107,72 @@ func Create( return obj, nil } +func (obj *{{ $PublicStructName }}) packTuple() (any, error) { + tuple := make([]any, 0, cntFields) + + var ( + v any + err error + ) + + {{- range $ind, $fstruct := .FieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $serlen := len $fstruct.Serializer -}} + {{ if ne $serlen 0 }} + v, err = Marshal{{ $fstruct.Name }}(obj.field{{ $fstruct.Name }}) + if err != nil { + return nil, fmt.Errorf("can't pack tuple field '{{ $fstruct.Name }}': %w", err) + } + {{ else }} + v = obj.field{{ $fstruct.Name }} + {{ end }} + + tuple = append(tuple, v) + {{ end }} + + return tuple, nil +} + + +func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error { + l, err := dec.DecodeArrayLen() + if err != nil { + return err + } + + if l != int(cntFields) { + return fmt.Errorf("unexpected count of fields") + } + + {{ range $ind, $fstruct := .FieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $sname := $fstruct.Serializer.Name -}} + {{ if ne $sname "" -}} + var v{{ $fstruct.Name }} {{ $rtype }} + if err := dec.Decode(&v{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode '{{ $fstruct.Name }}' field: %w", err) + } + + if err := serializer.MapstructureUnmarshal(v{{ $fstruct.Name }}, &obj.field{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't unpack '{{ $fstruct.Name }}' field: %w", err) + } + {{- else }} + if err := dec.Decode(&obj.field{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode field '{{ $fstruct.Name }}': %w", err) + } + {{ end }} + {{ end }} + + return nil +} + func (obj *{{ $PublicStructName }}) PrimaryString() string { ret := []string{ {{- range $ind, $fstruct := .FieldList }} {{- if $fstruct.PrimaryKey }} - obj.Get{{ $fstruct.Name }}(), + {{- $packerparam := packerParam $fstruct.Format }} + {{- $tostr := $packerparam.ToString }} + {{ index $tostr 0 }}obj.Get{{ $fstruct.Name }}(){{ index $tostr 1 }}, {{- end }} {{- end }} } @@ -131,6 +206,20 @@ func (obj *{{ $PublicStructName }}) Primary() {{ $ind.Type }} { {{ end -}} } +func (obj *{{ $PublicStructName }}) packPrimary() []any { + return []any{ + {{- range $_, $fieldNum := $ind.Fields }} + {{- $ifield := index $fields $fieldNum }} + {{ $rtype := $ifield.Format -}} + obj.Get{{ $ifield.Name }}(), + {{- end }} + } +} + +func SelectByPrimary(ctx context.Context, pk {{ $ind.Type }}) (*{{ $PublicStructName }}, error) { + return {{ $ind.Selector }}(ctx, pk) +} + {{ end }} {{ end }} @@ -138,6 +227,118 @@ func (obj *{{ $PublicStructName }}) Primary() {{ $ind.Type }} { {{end}} + +// Induces + +{{ range $num, $ind := .Indexes -}} +{{ $lenfld := len $ind.Fields -}} +{{ if ne $lenfld 1 }} +type {{ $ind.Type }} struct { +{{- range $_, $fieldNum := $ind.Fields }} +{{- $ifield := index $fields $fieldNum }} +{{ $rtype := $ifield.Format -}} +{{ $serlen := len $ifield.Serializer -}} +{{ if ne $serlen 0 -}} +{{ $sname := index $ifield.Serializer 0 -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end }} +{{ $ifield.Name }} {{ $rtype -}} +{{- end }} +} + +type {{ $ind.Type }}s []{{ $ind.Type }} + +func (idx {{ $ind.Type }}) pack() []any { + return []any{ + {{- range $_, $fieldNum := $ind.Fields }} + {{- $ifield := index $fields $fieldNum }} + {{ $rtype := $ifield.Format -}} + idx.{{ $ifield.Name }}, + {{- end }} + } +} + +// возвращает предикат для sql запроса формата IN (?,..) OR IN (?,..) и список параметров для него +func (idxs {{ $ind.Type }}s) buildSQLPredicateIN() (string, []any) { + args := make([]any, 0, len(idxs)) + + var ( + buf strings.Builder + predicate string + ) + + {{- range $_, $fieldNum := $ind.Fields }} + {{- $ifield := index $fields $fieldNum }} + {{ $rtype := $ifield.Format -}} + predicate = tarantool.BuildSQLPredicateIN("{{ $ifield.Name }}", len(idxs)) + buf.WriteString(predicate) + + for _, idx := range idxs { + args = append(args, idx.{{ $ifield.Name }}) + } + + buf.WriteString(" AND ") + {{ end }} + + buf.WriteString(" 1 = 1 ") + + return buf.String(), args +} +{{- else -}} +type {{ $ind.Name }}s []{{ $ind.Type }} + +func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { + args := make([]any, 0, len(idxs)) + for _, key := range idxs { + args = append(args, key) + } + + return tarantool.BuildSQLPredicateIN("{{ $ind.Name }}", len(idxs)), args +} +{{ end }} + +func {{ $ind.Selector }}s(ctx context.Context, keys []{{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ([]*{{ $PublicStructName }}, error) { + ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"{{ $ind.Selector }}s": keys, "Repo": "{{ $PublicStructName }}"}) + + inPredicate, args := {{ if ne $lenfld 1 -}} {{ $ind.Type }} {{- else }} {{ $ind.Name }} {{- end }}s(keys).buildSQLPredicateIN() + + return executeSQL(ctx, "SELECT * FROM \"" + namespace + "\" WHERE " + inPredicate, args) +} + +func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ({{ if $ind.Unique }}{{ else }}[]{{ end }}*{{ $PublicStructName }}, error) { + ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"{{ $ind.Selector }}": key, "Repo": "{{ $PublicStructName }}"}) + + {{ if $ind.Unique }} + limiter := activerecord.EmptyLimiter() + {{ end }} + + selected, err := selectBox(ctx, 0, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) + if err != nil { + return nil, err + } + + {{ if $ind.Unique -}} + if len(selected) > 0 { + if len(selected) > 1 { + activerecord.Logger().Error(ctx, "{{ $PublicStructName }}", "More than one tuple for uniq key ID '%s': %d", key, len(selected)) + } + + return selected[0], nil + } + + return nil, nil + {{- else }} + + return selected, nil + {{- end }} +} + +// template content + +{{ end }} +// End Induces + // Getters,Setters and Mutators {{ range $ind, $fstruct := .FieldList -}} @@ -184,7 +385,7 @@ func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} { {{- if eq $fstruct.Format "string" "[]byte" -}} {{- if gt $fstruct.Size 0 }} - if len({{ $fstruct.Name }}) > {{ $fstruct.Size }} { + if len(data) > {{ $fstruct.Size }} { return fmt.Errorf("max length of field '{{ $PublicStructName }}.{{ $fstruct.Name }}' is '%d' (received '%d')", {{ $fstruct.Size }}, len(data)) } {{- else }} @@ -208,3 +409,331 @@ func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} { {{ end -}} // End of Getters, Setters and Mutators + +func SelectAll(ctx context.Context, limiter activerecord.SelectorLimiter) ([]*{{ $PublicStructName }}, error) { + ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"SelectAll": "", "Repo": "{{ $PublicStructName }}"}) + + res, err := selectBox(ctx, 0, []any{}, tarantool2.IterAll, limiter) + if err != nil { + return res, err + } + + return res, nil +} + +func (obj *{{ $PublicStructName }}) Delete(ctx context.Context) error { + logger := activerecord.Logger() + metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}") + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + metricStatCnt.Inc(ctx, "delete_request", 1) + + if !obj.BaseField.Exists { + return fmt.Errorf("can't delete not exists object") + } + + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "delete_preparebox", 1) + logger.Error(ctx, "PromoBunches", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) + + return err + } + + _, errCall := connection.Delete(namespace, 0, obj.packPrimary()) + if errCall != nil { + metricErrCnt.Inc(ctx, "delete_box", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error delete from box", errCall, connection.Info()) + + return errCall + } + + metricStatCnt.Inc(ctx, "delete_success", 1) + + obj.BaseField.Exists = false + obj.BaseField.UpdateOps = []tarantool2.Op{} + + logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success delete") + + metricTimer.Finish(ctx, "delete") + + return nil +} + +func (obj *{{ $PublicStructName }}) Update(ctx context.Context) error { + logger := activerecord.Logger() + metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}") + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + metricStatCnt.Inc(ctx, "update_request", 1) + + if !obj.BaseField.Exists { + metricErrCnt.Inc(ctx, "update_notexists", 1) + return fmt.Errorf("can't update not exists object") + } + + /* if obj.BaseField.Repaired { + metricStatCnt.Inc(ctx, "update_repaired", 1) + logger.Debug(ctx, "", obj.PrimaryString(), "Flag 'Repaired' is true! Insert instead Update") + + return obj.Replace(ctx) + }*/ + + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "update_preparebox", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) + return err + } + + if len(obj.BaseField.UpdateOps) == 0 { + metricStatCnt.Inc(ctx, "update_empty", 1) + logger.Debug(ctx, "", obj.PrimaryString(), "Empty update") + + return nil + } + + _, errCall := connection.Update(namespace, 0, obj.packPrimary(), obj.UpdateOps) + if errCall != nil { + metricErrCnt.Inc(ctx, "update_box", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error update ia a box", errCall, connection.Info()) + return errCall + } + + metricTimer.Timing(ctx, "update_box") + + obj.BaseField.UpdateOps = []tarantool2.Op{} + + logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success update") + + metricStatCnt.Inc(ctx, "update_success", 1) + metricTimer.Finish(ctx, "update") + + return nil +} + +func (obj *{{ $PublicStructName }}) Insert(ctx context.Context) error { + logger := activerecord.Logger() + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + metricStatCnt.Inc(ctx, "insert_request", 1) + + if obj.BaseField.Exists { + metricErrCnt.Inc(ctx, "insert_exists", 1) + return fmt.Errorf("can't insert already exists object") + } + + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) + return err + } + + tuple, err := obj.packTuple() + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_packfield", 1) + + return err + } + + _, errCall := connection.Insert(namespace, tuple) + if errCall != nil { + metricErrCnt.Inc(ctx, "insertreplace_box", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error insert into box", errCall, connection.Info()) + + return errCall + } + + if err == nil { + metricStatCnt.Inc(ctx, "insert_success", 1) + } + + obj.UpdateOps = []tarantool2.Op{} + obj.BaseField.Exists = true + + return err +} + +func (obj *{{ $PublicStructName }}) Replace(ctx context.Context) error { + logger := activerecord.Logger() + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + metricStatCnt.Inc(ctx, "replace_request", 1) + + if !obj.BaseField.Exists { + metricErrCnt.Inc(ctx, "replace_notexists", 1) + return fmt.Errorf("can't replace not exists object") + } + + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) + + return err + } + + tuple, err := obj.packTuple() + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_packfield", 1) + + return err + } + + _, errCall := connection.Replace(namespace, tuple) + if errCall != nil { + metricErrCnt.Inc(ctx, "insertreplace_box", 1) + logger.Error(ctx, "PromoBunches", obj.PrimaryString(), "Error replace on box", errCall, connection.Info()) + + return errCall + } + + if err == nil { + metricStatCnt.Inc(ctx, "replace_success", 1) + } + + obj.UpdateOps = []tarantool2.Op{} + obj.BaseField.Exists = true + + return err +} + +func (obj *{{ $PublicStructName }}) InsertOrReplace(ctx context.Context) error { + logger := activerecord.Logger() + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + metricStatCnt.Inc(ctx, "insertorreplace_request", 1) + + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) + return err + } + + tuple, err := obj.packTuple() + if err != nil { + metricErrCnt.Inc(ctx, "insertreplace_packfield", 1) + + return err + } + + _, errCall := connection.Upsert(namespace, tuple, obj.UpdateOps) + if errCall != nil { + metricErrCnt.Inc(ctx, "insertreplace_box", 1) + logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error upsert box", errCall, connection.Info()) + + return errCall + } + + if err == nil { + metricStatCnt.Inc(ctx, "insertorreplace_success", 1) + } + + obj.UpdateOps = []tarantool2.Op{} + obj.BaseField.Exists = true + + return err +} + +func selectBox(ctx context.Context, indexnum uint32, keys []interface{}, iterType uint32, limiter activerecord.SelectorLimiter) ([]*{{ $PublicStructName }}, error) { + logger := activerecord.Logger() + ctx = logger.SetLoggerValueToContext(ctx, activerecord.ValueLogPrefix{"limiter": limiter.String()}) + metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}") + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "select_preparebox", 1) + logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) + + return nil, err + } + + var res []*{{ $PublicStructName }} + + limit := limiter.Limit() + if limiter.Limit() == 0 { + limit = math.MaxInt32 + } + + errCall := connection.SelectTyped(namespace, indexnum, limiter.Offset(), limit, iterType, keys, &res) + if errCall != nil { + metricErrCnt.Inc(ctx, "select_box", 1) + logger.Error(ctx, "Error select from box", errCall, connection.Info()) + + return nil, errCall + } + + metricTimer.Timing(ctx, "select_box") + metricStatCnt.Inc(ctx, "select_tuples_res", float64(len(res))) + + if limiter.FullfillWarn() && len(res) == int(limiter.Limit()) { + logger.Warn(ctx, "Select limit reached. Result may less than db records.") + } + + mode, ok := connection.InstanceMode().(activerecord.ServerModeType) + if !ok || mode == activerecord.ModeReplica { + if !ok { + logger.Error(ctx, "Invalid server mode type: %T", connection.InstanceMode()) + } + + for _, r := range res { + r.BaseField.IsReplica = true + r.BaseField.ReadOnly = true + } + } + + for _, r := range res { + r.BaseField.Exists = true + } + + logger.Debug(ctx, "Success select") + + metricTimer.Finish(ctx, "select") + + return res, nil +} + +func executeSQL(ctx context.Context, sqlText string, args []any) ([]*{{ $PublicStructName }}, error) { + logger := activerecord.Logger() + metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}") + metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") + + connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "execute_preparebox", 1) + logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) + + return nil, err + } + + var res []*{{ $PublicStructName }} + + if _, _, errCall := connection.ExecuteTyped(sqlText, args, &res); err != nil { + metricErrCnt.Inc(ctx, "execute_box", 1) + logger.Error(ctx, "Error execute from box", errCall, connection.Info()) + + return nil, errCall + } + + for _, r := range res { + r.BaseField.Exists = true + } + + metricStatCnt.Inc(ctx, "execute_tuples_res", float64(len(res))) + + logger.Debug(ctx, "Success execute") + + metricTimer.Finish(ctx, "execute") + + return res, nil +} \ No newline at end of file diff --git a/pkg/tarantool/sqlbuilder.go b/pkg/tarantool/sqlbuilder.go new file mode 100644 index 0000000..13c3847 --- /dev/null +++ b/pkg/tarantool/sqlbuilder.go @@ -0,0 +1,21 @@ +package tarantool + +import "strings" + +func BuildSQLPredicateIN(fieldname string, fieldCndt int) string { + if fieldCndt == 0 { + return "" + } + + var b strings.Builder + b.Grow(len(fieldname) + 2*fieldCndt + 10) + b.WriteString(" \"" + fieldname + "\" IN (?") + + for i := 0; i < fieldCndt-1; i++ { + b.WriteString(", ?") + } + + b.WriteString(")") + + return b.String() +} From 71b109d4c9cf74e02a2c74a6112cbcb88e5fe2e1 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 22 Feb 2024 19:22:50 +0300 Subject: [PATCH 06/18] fix tarantool2 backend generator --- go.mod | 42 +++++++-- go.sum | 88 ++++++++++++++++--- .../pkg/generator/tmpl/tarantool/main.tmpl | 9 +- 3 files changed, 112 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 465df18..1c1e745 100644 --- a/go.mod +++ b/go.mod @@ -9,21 +9,45 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 github.com/tarantool/go-tarantool v1.6.0 - golang.org/x/mod v0.7.0 - golang.org/x/net v0.7.0 - golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 - golang.org/x/tools v0.5.0 + gitlab.corp.mail.ru/cloud/go/neobank.git v1.5.0 + golang.org/x/mod v0.9.0 + golang.org/x/net v0.15.0 + golang.org/x/sys v0.12.0 + golang.org/x/text v0.13.0 + golang.org/x/time v0.3.0 + golang.org/x/tools v0.7.0 + gopkg.in/vmihailenco/msgpack.v2 v2.9.2 + gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.3.1 // indirect + github.com/dlclark/regexp2 v1.8.1 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/errors v0.6.1 // indirect + github.com/go-faster/jx v1.0.0 // indirect + github.com/go-faster/yaml v0.4.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/ogen-go/ogen v0.62.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/stretchr/objx v0.5.0 // indirect + go.opentelemetry.io/otel v1.14.0 // indirect + go.opentelemetry.io/otel/metric v0.37.0 // indirect + go.opentelemetry.io/otel/trace v1.14.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect + golang.org/x/sync v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - gopkg.in/vmihailenco/msgpack.v2 v2.9.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 8eb6c71..1a78296 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,56 @@ +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0= +github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI= +github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY= +github.com/go-faster/jx v1.0.0 h1:HE+ms2e6ZGkZ6u13t8u+onBinrPvIPI+0hWXGELm74g= +github.com/go-faster/jx v1.0.0/go.mod h1:zm8SlkwK+H0TYNKYtVJ/7cWFS7soJBQWhcPctKyYL/4= +github.com/go-faster/yaml v0.4.3 h1:j7blP1oLA/2aBQEaWUibtrNNIayr49VGHGpR076NB8k= +github.com/go-faster/yaml v0.4.3/go.mod h1:K2zdBSnXHZ6/rz8iQ1yxgY+R+ytdlZPzdro0NB8EYxw= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 h1:x3Zw96Gt6HbEPUWsTbQYj/nfaNv5lWHy6CeEkl8gwqw= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45/go.mod h1:guLmlFj8yjd0hoz+QWxRU4Gn+VOb2nOQZ4EqRmMHarw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/ogen-go/ogen v0.62.0 h1:RNsrAbso1DGpxZO5RCL5wd8pDh+sTsyUrYJovdJ3FuQ= +github.com/ogen-go/ogen v0.62.0/go.mod h1:Rn43MIqVcT8utwLi45lv7e/a4kPRk+klLsWsgB1z9GQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= @@ -29,31 +61,59 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarantool/go-tarantool v1.6.0 h1:D/GW7hw9r8MbvSfcHqr6tT7brO7nqwhtWKJMj6OtArw= github.com/tarantool/go-tarantool v1.6.0/go.mod h1:SFamRDArn3Be+qwzMzdzQqGz9/D9mgSb3xCpKxbqMjQ= +gitlab.corp.mail.ru/cloud/go/neobank.git v1.5.0 h1:6Ho55WZUiacZwH0zKo1N4Tcrbx10MHW53lsHDD/DIu8= +gitlab.corp.mail.ru/cloud/go/neobank.git v1.5.0/go.mod h1:i9L0NTXPPTDc8uoH1DS0666Ws+YZJ+fLAvUpvc6/a5E= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/vmihailenco/msgpack.v2 v2.9.2 h1:gjPqo9orRVlSAH/065qw3MsFCDpH7fa1KpiizXyllY4= gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index d00ac99..054c07e 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -130,7 +130,7 @@ func (obj *{{ $PublicStructName }}) packTuple() (any, error) { tuple = append(tuple, v) {{ end }} - return tuple, nil + return tuple, err } @@ -286,6 +286,8 @@ func (idxs {{ $ind.Type }}s) buildSQLPredicateIN() (string, []any) { return buf.String(), args } {{- else -}} +{{ $ifld := index $ind.Fields 0 }} +{{ $ifield := index $fields $ifld }} type {{ $ind.Name }}s []{{ $ind.Type }} func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { @@ -294,7 +296,7 @@ func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { args = append(args, key) } - return tarantool.BuildSQLPredicateIN("{{ $ind.Name }}", len(idxs)), args + return tarantool.BuildSQLPredicateIN("{{ $ifield.Name }}", len(idxs)), args } {{ end }} @@ -312,8 +314,7 @@ func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind. {{ if $ind.Unique }} limiter := activerecord.EmptyLimiter() {{ end }} - - selected, err := selectBox(ctx, 0, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) + selected, err := selectBox(ctx, {{$ind.Num}}, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) if err != nil { return nil, err } From 19ecc3284abfcb82e30510eefd4eb256e9eab09b Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 22 Feb 2024 19:22:50 +0300 Subject: [PATCH 07/18] fix tarantool2 backend generator --- go.mod | 16 ++++---- go.sum | 38 ++++++++++++------- .../pkg/generator/tmpl/tarantool/main.tmpl | 9 +++-- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 465df18..eb774cc 100644 --- a/go.mod +++ b/go.mod @@ -9,21 +9,23 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 github.com/tarantool/go-tarantool v1.6.0 - golang.org/x/mod v0.7.0 - golang.org/x/net v0.7.0 - golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 - golang.org/x/tools v0.5.0 + golang.org/x/mod v0.9.0 + golang.org/x/net v0.15.0 + golang.org/x/sys v0.12.0 + golang.org/x/text v0.13.0 + golang.org/x/time v0.3.0 + golang.org/x/tools v0.7.0 gotest.tools v2.2.0+incompatible ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.3.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/vmihailenco/msgpack.v2 v2.9.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8eb6c71..6a83ddb 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,21 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45 h1:x3Zw96Gt6HbEPUWsTbQYj/nfaNv5lWHy6CeEkl8gwqw= github.com/mailru/mapstructure v0.0.0-20230117153631-a4140f9ccc45/go.mod h1:guLmlFj8yjd0hoz+QWxRU4Gn+VOb2nOQZ4EqRmMHarw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -30,25 +35,30 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/tarantool/go-tarantool v1.6.0 h1:D/GW7hw9r8MbvSfcHqr6tT7brO7nqwhtWKJMj6OtArw= github.com/tarantool/go-tarantool v1.6.0/go.mod h1:SFamRDArn3Be+qwzMzdzQqGz9/D9mgSb3xCpKxbqMjQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index d00ac99..054c07e 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -130,7 +130,7 @@ func (obj *{{ $PublicStructName }}) packTuple() (any, error) { tuple = append(tuple, v) {{ end }} - return tuple, nil + return tuple, err } @@ -286,6 +286,8 @@ func (idxs {{ $ind.Type }}s) buildSQLPredicateIN() (string, []any) { return buf.String(), args } {{- else -}} +{{ $ifld := index $ind.Fields 0 }} +{{ $ifield := index $fields $ifld }} type {{ $ind.Name }}s []{{ $ind.Type }} func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { @@ -294,7 +296,7 @@ func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { args = append(args, key) } - return tarantool.BuildSQLPredicateIN("{{ $ind.Name }}", len(idxs)), args + return tarantool.BuildSQLPredicateIN("{{ $ifield.Name }}", len(idxs)), args } {{ end }} @@ -312,8 +314,7 @@ func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind. {{ if $ind.Unique }} limiter := activerecord.EmptyLimiter() {{ end }} - - selected, err := selectBox(ctx, 0, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) + selected, err := selectBox(ctx, {{$ind.Num}}, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) if err != nil { return nil, err } From fe79944c25cf0461a5049187b713143bb2333b27 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Mon, 26 Feb 2024 18:54:06 +0300 Subject: [PATCH 08/18] tarantool2 backend generator flags and mutators --- internal/pkg/generator/tarantool.go | 5 + .../pkg/generator/tmpl/tarantool/main.tmpl | 128 +++++++++++++++++- pkg/iproto/util/text/text.go | 10 ++ 3 files changed, 140 insertions(+), 3 deletions(-) diff --git a/internal/pkg/generator/tarantool.go b/internal/pkg/generator/tarantool.go index 7d4680c..38d5e82 100644 --- a/internal/pkg/generator/tarantool.go +++ b/internal/pkg/generator/tarantool.go @@ -10,6 +10,7 @@ import ( "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" + "github.com/mailru/activerecord/pkg/iproto/util/text" "github.com/mailru/activerecord/pkg/octopus" ) @@ -112,6 +113,10 @@ var Tarantool2TmplFunc = template.FuncMap{ return }, + "trimPrefix": strings.TrimPrefix, + "hasPrefix": strings.HasPrefix, + "lowerCase": strings.ToLower, + "snakeToCamelCase": text.SnakeToCamelCase, } type TarantoolFormatParam string diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index 054c07e..170cd12 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -271,7 +271,7 @@ func (idxs {{ $ind.Type }}s) buildSQLPredicateIN() (string, []any) { {{- range $_, $fieldNum := $ind.Fields }} {{- $ifield := index $fields $fieldNum }} {{ $rtype := $ifield.Format -}} - predicate = tarantool.BuildSQLPredicateIN("{{ $ifield.Name }}", len(idxs)) + predicate = tarantool.BuildSQLPredicateIN("{{ $ifield.Name | lowerCase -}}", len(idxs)) buf.WriteString(predicate) for _, idx := range idxs { @@ -296,7 +296,7 @@ func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) { args = append(args, key) } - return tarantool.BuildSQLPredicateIN("{{ $ifield.Name }}", len(idxs)), args + return tarantool.BuildSQLPredicateIN("{{ $ifield.Name | lowerCase -}}", len(idxs)), args } {{ end }} @@ -335,11 +335,59 @@ func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind. {{- end }} } -// template content {{ end }} // End Induces + +// linked objects +{{ range $name, $fobj := .FieldObject -}} +{{ $linkedobj := index $LinkedObject $fobj.ObjectName }} +func (obj *{{ $PublicStructName }}) Get{{ $name }}(ctx context.Context) ({{ if not $fobj.Unique }}[]{{ end }}*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}, error){ + {{- if $fobj.Unique }} + if ret, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(ret) == 1 { + return ret[0].(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}), nil + } + + ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}()) + if err != nil { + return nil, err + } + + obj.BaseField.Objects["{{ $name }}"] = []tarantool.ModelStruct{ret} + {{- else }} + + var ret []*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }} + + if retI, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(retI) > 0 { + for _, ri := range retI { + ret = append(ret, ri.(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }})) + } + + return ret, nil + } + + ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}(), activerecord.NewLimiter(100)) //ToDo default limit for multi object + if err != nil { + return nil, err + } + + if len(ret) == 100 { + activerecord.Logger().Warn(ctx, "limit for multiple linked object riched '{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}' '{{ $PublicStructName }}'") + } + + for _, r := range ret { + obj.BaseField.Objects["{{ $name }}"] = append(obj.BaseField.Objects["{{ $name }}"], r) + } + {{- end }} + + return ret, nil +} + +{{ end -}} +// End linked objects + + // Getters,Setters and Mutators {{ range $ind, $fstruct := .FieldList -}} @@ -407,6 +455,80 @@ func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} { return nil } +{{- range $i, $mut := $fstruct.Mutators -}} +{{ $mtype := $fstruct.Format }} + +func (obj *{{ $PublicStructName }}) {{ $mut | snakeToCamelCase }}{{ $fstruct.Name }}(mutArg {{ $mtype }}) error { + {{- if eq $mut "inc" }} + if mutArg == 0 { + return nil + } + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "+", Arg: mutArg}) + obj.field{{ $fstruct.Name }} += mutArg + {{- else if eq $mut "dec" }} + if mutArg == 0 { + return nil + } + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "-", Arg: mutArg}) + obj.field{{ $fstruct.Name }} -= mutArg + {{- else if eq $mut "and" }} + if obj.field{{ $fstruct.Name }} == 0 || obj.field{{ $fstruct.Name }} & mutArg == obj.field{{ $fstruct.Name }} { + return nil + } + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "&", Arg: mutArg}) + obj.field{{ $fstruct.Name }} &= mutArg + {{- else if eq $mut "or" "set_bit" }} + if mutArg == 0 || obj.field{{ $fstruct.Name }} | mutArg == obj.field{{ $fstruct.Name }} { + return nil + } + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "|", Arg: mutArg}) + obj.field{{ $fstruct.Name }} |= mutArg + {{- else if eq $mut "clear_bit" }} + if mutArg == 0 || obj.field{{ $fstruct.Name }} & ^mutArg == obj.field{{ $fstruct.Name }} { + return nil + } + + mutArg &= ^mutArg + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "=", Arg: mutArg}) + obj.field{{ $fstruct.Name }} = mutArg + {{- else if eq $mut "xor" }} + if mutArg == 0 || obj.field{{ $fstruct.Name }} ^ mutArg == obj.field{{ $fstruct.Name }} { + return nil + } + + obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "^", Arg: mutArg}) + obj.field{{ $fstruct.Name }} ^= mutArg + {{- else }} + Unknown mutator type in template!!! + {{- end }} + + return nil +} +{{- end }} + +{{- $fl := index $flags $fstruct.Name }} +{{- if $fl }} +{{- range $i, $flag := $fl.Flags }} + +func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}{{ $flag }}() error { + return obj.SetBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag ) +} + +func (obj *{{ $PublicStructName }}) Clear{{ $fstruct.Name }}{{ $flag }}() error { + return obj.ClearBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag ) +} + +func (obj *{{ $PublicStructName }}) Is{{ $fstruct.Name }}{{ $flag }}() bool { + return obj.Get{{ $fstruct.Name }}() & {{ $fstruct.Name }}{{ $flag }}Flag == {{ $fstruct.Name }}{{ $flag }}Flag +} +{{- end }} +{{- end }} + {{ end -}} // End of Getters, Setters and Mutators diff --git a/pkg/iproto/util/text/text.go b/pkg/iproto/util/text/text.go index 311bf81..9be38c8 100644 --- a/pkg/iproto/util/text/text.go +++ b/pkg/iproto/util/text/text.go @@ -3,6 +3,8 @@ package text import ( "bytes" + "regexp" + "strings" "unicode" ) @@ -80,3 +82,11 @@ func ToSnakeCase(name string) string { return ret.String() } + +var snakePattern = regexp.MustCompile("(^[A-Za-z])|_([A-Za-z])") + +func SnakeToCamelCase(str string) string { + return snakePattern.ReplaceAllStringFunc(str, func(s string) string { + return strings.ToUpper(strings.Replace(s, "_", "", -1)) + }) +} From d464c67f637313a5dee6ea7706b7a766247b9818 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Mon, 26 Feb 2024 18:59:16 +0300 Subject: [PATCH 09/18] fix --- go.mod | 28 ++----------------- .../pkg/generator/tmpl/tarantool/main.tmpl | 6 ++-- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 1c1e745..eb774cc 100644 --- a/go.mod +++ b/go.mod @@ -9,45 +9,23 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 github.com/tarantool/go-tarantool v1.6.0 - gitlab.corp.mail.ru/cloud/go/neobank.git v1.5.0 golang.org/x/mod v0.9.0 golang.org/x/net v0.15.0 golang.org/x/sys v0.12.0 golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.7.0 - gopkg.in/vmihailenco/msgpack.v2 v2.9.2 - gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.8.1 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-faster/errors v0.6.1 // indirect - github.com/go-faster/jx v1.0.0 // indirect - github.com/go-faster/yaml v0.4.3 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect - github.com/ogen-go/ogen v0.62.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/segmentio/asm v1.2.0 // indirect github.com/stretchr/objx v0.5.0 // indirect - go.opentelemetry.io/otel v1.14.0 // indirect - go.opentelemetry.io/otel/metric v0.37.0 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect - golang.org/x/sync v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/vmihailenco/msgpack.v2 v2.9.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index 170cd12..7ae4ae9 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -148,12 +148,14 @@ func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error { {{ $rtype := $fstruct.Format -}} {{ $sname := $fstruct.Serializer.Name -}} {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $serparams := $fstruct.Serializer.Params }} var v{{ $fstruct.Name }} {{ $rtype }} if err := dec.Decode(&v{{ $fstruct.Name }}); err != nil { return fmt.Errorf("can't decode '{{ $fstruct.Name }}' field: %w", err) } - if err := serializer.MapstructureUnmarshal(v{{ $fstruct.Name }}, &obj.field{{ $fstruct.Name }}); err != nil { + if err := {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}v{{ $fstruct.Name }}, &obj.field{{ $fstruct.Name }}); err != nil { return fmt.Errorf("can't unpack '{{ $fstruct.Name }}' field: %w", err) } {{- else }} @@ -314,7 +316,7 @@ func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind. {{ if $ind.Unique }} limiter := activerecord.EmptyLimiter() {{ end }} - selected, err := selectBox(ctx, {{$ind.Num}}, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool.IterEq, limiter) + selected, err := selectBox(ctx, {{$ind.Num}}, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool2.IterEq, limiter) if err != nil { return nil, err } From 061ac6e240979137fae95c3203ee3c2a1dc7f00d Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Tue, 27 Feb 2024 06:15:13 +0300 Subject: [PATCH 10/18] customize repository --- internal/app/argen.go | 43 ++++++++++++++----- .../pkg/generator/tmpl/tarantool/main.tmpl | 25 ++++++++++- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/internal/app/argen.go b/internal/app/argen.go index 479c1ef..6d57340 100644 --- a/internal/app/argen.go +++ b/internal/app/argen.go @@ -209,9 +209,6 @@ func (a *ArGen) saveGenerateResult(name, dst string, genRes []generator.Generate // Процесс генерации пакетов по подготовленным данным func (a *ArGen) generate() error { - metadata := generator.MetaData{ - AppInfo: a.appInfo.String(), - } // Запускаем цикл с проходом по всем полученным файлам для генерации // результирующих пакетов for name, cl := range a.packagesParsed { @@ -230,17 +227,22 @@ func (a *ArGen) generate() error { if err := a.saveGenerateResult(name, a.dst, genRes); err != nil { return fmt.Errorf("error save result: %w", err) } - - metadata.Namespaces = append(metadata.Namespaces, cl) } - genRes, genErr := generator.GenerateMeta(metadata) - if genErr != nil { - return fmt.Errorf("generate meta error: %s", genErr) + metadata, err := a.prepareMetaData() + if err != nil { + return fmt.Errorf("prepare metadata generate error: %s", err) } - if err := a.saveGenerateResult("meta", a.dst, genRes); err != nil { - return fmt.Errorf("error save meta result: %w", err) + if len(metadata.Namespaces) > 0 { + genRes, genErr := generator.GenerateMeta(metadata) + if genErr != nil { + return fmt.Errorf("generate meta error: %s", genErr) + } + + if err := a.saveGenerateResult("meta", a.dst, genRes); err != nil { + return fmt.Errorf("error save meta result: %w", err) + } } if a.skipGenerateFixture() { @@ -248,7 +250,7 @@ func (a *ArGen) generate() error { } // Генерация пакета со сторами фикстур для тестов - err := a.prepareFixturesStorage() + err = a.prepareFixturesStorage() if err != nil { return fmt.Errorf("prepare fixture store error: %s", err) } @@ -517,3 +519,22 @@ func (a *ArGen) getExists() ([]string, error) { return existsFile, nil } + +func (a *ArGen) prepareMetaData() (generator.MetaData, error) { + metadata := generator.MetaData{ + AppInfo: a.appInfo.String(), + } + + for _, cl := range a.packagesParsed { + for _, backend := range cl.Backends { + switch backend { + case "tarantool15": + fallthrough + case "octopus": + metadata.Namespaces = append(metadata.Namespaces, cl) + } + } + } + + return metadata, nil +} diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index 7ae4ae9..23a9fc8 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -458,8 +458,28 @@ func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} { } {{- range $i, $mut := $fstruct.Mutators -}} -{{ $mtype := $fstruct.Format }} +{{ $customMutator := index $mutators $mut -}} + {{- if $customMutator.Name }} + {{ range $i, $f := $customMutator.PartialFields }} +// Set{{ $customMutator.Name }}{{ $f.Name }} is a stub for backport compatibility +func (obj *{{ $PublicStructName }}) Set{{ $customMutator.Name }}{{ $f.Name }}({{ $f.Name }} {{ $f.Type }}) error { + pVar := obj.Get{{ $fstruct.Name }}() + {{ $underlyingType := trimPrefix (printf "%s" $rtype) "*"}} + {{- $isPointer := hasPrefix (printf "%s" $rtype) "*" -}} + {{- if $isPointer -}} + if pVar == nil { + pVar = new({{$underlyingType}}) + } + {{ end}} + + pVar.{{ $f.Name }} = {{ $f.Name }} + + return obj.Set{{ $fstruct.Name }}(pVar) +} + {{ end }} + {{ else }} + {{ $mtype := $fstruct.Format }} func (obj *{{ $PublicStructName }}) {{ $mut | snakeToCamelCase }}{{ $fstruct.Name }}(mutArg {{ $mtype }}) error { {{- if eq $mut "inc" }} if mutArg == 0 { @@ -511,7 +531,8 @@ func (obj *{{ $PublicStructName }}) {{ $mut | snakeToCamelCase }}{{ $fstruct.Nam return nil } -{{- end }} + {{- end }} +{{ end}} {{- $fl := index $flags $fstruct.Name }} {{- if $fl }} From cc5908d3233571433f46452e640c4fa2aac0e37e Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Tue, 27 Feb 2024 19:43:07 +0300 Subject: [PATCH 11/18] fix fixture generator --- internal/app/argen.go | 25 +++++- internal/pkg/generator/fixture.go | 81 +++++++++++++++++++ internal/pkg/generator/generator.go | 55 +++++-------- internal/pkg/generator/octopus_b_test.go | 6 +- internal/pkg/generator/tmpl/fixture_meta.tmpl | 45 +++++++++++ internal/pkg/generator/tmpl/meta.tmpl | 2 +- .../pkg/generator/tmpl/octopus/fixture.tmpl | 10 +-- .../generator/tmpl/octopus/fixturestore.tmpl | 2 +- .../pkg/generator/tmpl/tarantool/fixture.tmpl | 38 ++++++++- .../tmpl/tarantool/fixturestore.tmpl | 16 +++- internal/pkg/testutil/fixture.go | 1 - 11 files changed, 227 insertions(+), 54 deletions(-) create mode 100644 internal/pkg/generator/tmpl/fixture_meta.tmpl delete mode 100644 internal/pkg/testutil/fixture.go diff --git a/internal/app/argen.go b/internal/app/argen.go index 6d57340..2ecfaf2 100644 --- a/internal/app/argen.go +++ b/internal/app/argen.go @@ -240,7 +240,7 @@ func (a *ArGen) generate() error { return fmt.Errorf("generate meta error: %s", genErr) } - if err := a.saveGenerateResult("meta", a.dst, genRes); err != nil { + if genErr := a.saveGenerateResult("meta", a.dst, genRes); genErr != nil { return fmt.Errorf("error save meta result: %w", err) } } @@ -255,7 +255,7 @@ func (a *ArGen) generate() error { return fmt.Errorf("prepare fixture store error: %s", err) } - dir, pkg := filepath.Split(a.dstFixture) + fixtureDir, fxtPkg := filepath.Split(a.dstFixture) for name, cl := range a.packagesParsed { // Подготовка информации по ссылкам на другие пакеты @@ -265,16 +265,33 @@ func (a *ArGen) generate() error { } // Процесс генерации - genRes, genErr := generator.GenerateFixture(a.appInfo.String(), *cl, name, pkg) + genRes, genErr := generator.GenerateFixture(a.appInfo.String(), *cl, name, fxtPkg) if genErr != nil { return fmt.Errorf("generate %s fixture store error: %w", name, genErr) } - if err := a.saveGenerateResult(name, dir, genRes); err != nil { + if err := a.saveGenerateResult(name, fixtureDir, genRes); err != nil { return fmt.Errorf("error save generated %s fixture result: %w", name, err) } } + namespaces := map[string][]*ds.RecordPackage{} + + for _, cl := range a.packagesParsed { + for _, backend := range cl.Backends { + namespaces[backend] = append(namespaces[backend], cl) + } + } + + genRes, genErr := generator.GenerateFixtureMeta(namespaces, a.appInfo.String(), fxtPkg) + if genErr != nil { + return fmt.Errorf("generate fixture meta error: %s", genErr) + } + + if err := a.saveGenerateResult("fixture_meta", fixtureDir, genRes); err != nil { + return fmt.Errorf("error save fixture meta result: %w", err) + } + return nil } diff --git a/internal/pkg/generator/fixture.go b/internal/pkg/generator/fixture.go index 03eaf5e..67c2af5 100644 --- a/internal/pkg/generator/fixture.go +++ b/internal/pkg/generator/fixture.go @@ -1,9 +1,13 @@ package generator import ( + "bufio" + "bytes" _ "embed" + "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" + "golang.org/x/tools/imports" ) type FixturePkgData struct { @@ -22,3 +26,80 @@ type FixturePkgData struct { Imports []ds.ImportDeclaration AppInfo string } + +type FixtureMetaData struct { + MetaData + FixturePkg string +} + +//nolint:revive +//go:embed tmpl/fixture_meta.tmpl +var fixtureMetaTmpl string + +func generateFixtureMeta(params FixtureMetaData) (*bytes.Buffer, *arerror.ErrGeneratorFile) { + metaWriter := new(bytes.Buffer) + metaFile := bufio.NewWriter(metaWriter) + + if err := GenerateByTmpl(metaFile, params, "fixture_meta", fixtureMetaTmpl); err != nil { + return nil, &arerror.ErrGeneratorFile{Name: "repository.go", Backend: "fixture_meta", Filename: "repository.go", Err: err} + } + + metaFile.Flush() + + return metaWriter, nil +} + +func GenerateFixtureMeta(packageNamespaces map[string][]*ds.RecordPackage, appInfo, pkgFixture string) ([]GenerateFile, error) { + var ret = make([]GenerateFile, 0, len(packageNamespaces)) + + for backend, namespaces := range packageNamespaces { + metaData := FixtureMetaData{ + MetaData: MetaData{ + Namespaces: namespaces, + AppInfo: appInfo, + }, + FixturePkg: pkgFixture, + } + var generated *bytes.Buffer + + switch backend { + case "tarantool15": + fallthrough + case "octopus": + fallthrough + case "tarantool16": + fallthrough + case "tarantool2": + var err *arerror.ErrGeneratorFile + + generated, err = generateFixtureMeta(metaData) + if err != nil { + err.Name = "fixture_meta" + return nil, err + } + case "postgres": + return nil, &arerror.ErrGeneratorFile{Name: "fixture_meta", Backend: backend, Err: arerror.ErrGeneratorBackendNotImplemented} + default: + return nil, &arerror.ErrGeneratorFile{Name: "fixture_meta", Backend: backend, Err: arerror.ErrGeneratorBackendUnknown} + } + + genRes := GenerateFile{ + Dir: pkgFixture, + Name: "stores.go", + Backend: "fixture_meta", + } + + genData := generated.Bytes() + + var err error + + genRes.Data, err = imports.Process("", genData, nil) + if err != nil { + return nil, &arerror.ErrGeneratorFile{Name: "repository.go", Backend: "fixture_meta", Filename: genRes.Name, Err: ErrorLine(err, string(genData))} + } + + ret = append(ret, genRes) + } + + return ret, nil +} diff --git a/internal/pkg/generator/generator.go b/internal/pkg/generator/generator.go index a21b6b9..c77585a 100644 --- a/internal/pkg/generator/generator.go +++ b/internal/pkg/generator/generator.go @@ -243,6 +243,25 @@ func ErrorLine(errIn error, genData string) error { func GenerateFixture(appInfo string, cl ds.RecordPackage, pkg string, pkgFixture string) ([]GenerateFile, error) { var ret []GenerateFile + params := FixturePkgData{ + FixturePkg: pkgFixture, + ARPkg: pkg, + ARPkgTitle: cl.Namespace.PublicName, + FieldList: cl.Fields, + FieldMap: cl.FieldsMap, + FieldObject: cl.FieldsObjectMap, + ProcInFieldList: cl.ProcInFields, + ProcOutFieldList: cl.ProcOutFields.List(), + Container: cl.Namespace, + Indexes: cl.Indexes, + Serializers: cl.SerializerMap, + Mutators: cl.MutatorMap, + Imports: cl.Imports, + AppInfo: appInfo, + } + + log.Printf("Generate package (%v)", cl) + for _, backend := range cl.Backends { var generated map[string]bytes.Buffer @@ -250,24 +269,6 @@ func GenerateFixture(appInfo string, cl ds.RecordPackage, pkg string, pkgFixture case "tarantool15": fallthrough case "octopus": - params := FixturePkgData{ - FixturePkg: pkgFixture, - ARPkg: pkg, - ARPkgTitle: cl.Namespace.PublicName, - FieldList: cl.Fields, - FieldMap: cl.FieldsMap, - FieldObject: cl.FieldsObjectMap, - ProcInFieldList: cl.ProcInFields, - ProcOutFieldList: cl.ProcOutFields.List(), - Container: cl.Namespace, - Indexes: cl.Indexes, - Serializers: cl.SerializerMap, - Mutators: cl.MutatorMap, - Imports: cl.Imports, - AppInfo: appInfo, - } - - log.Printf("Generate package (%v)", cl) var err *arerror.ErrGeneratorPhases @@ -279,24 +280,6 @@ func GenerateFixture(appInfo string, cl ds.RecordPackage, pkg string, pkgFixture case "tarantool16": fallthrough case "tarantool2": - params := FixturePkgData{ - FixturePkg: pkgFixture, - ARPkg: pkg, - ARPkgTitle: cl.Namespace.PublicName, - FieldList: cl.Fields, - FieldMap: cl.FieldsMap, - FieldObject: cl.FieldsObjectMap, - ProcInFieldList: cl.ProcInFields, - ProcOutFieldList: cl.ProcOutFields.List(), - Container: cl.Namespace, - Indexes: cl.Indexes, - Serializers: cl.SerializerMap, - Mutators: cl.MutatorMap, - Imports: cl.Imports, - AppInfo: appInfo, - } - - log.Printf("Generate package (%v)", cl) var err *arerror.ErrGeneratorPhases diff --git a/internal/pkg/generator/octopus_b_test.go b/internal/pkg/generator/octopus_b_test.go index a502571..4601b08 100644 --- a/internal/pkg/generator/octopus_b_test.go +++ b/internal/pkg/generator/octopus_b_test.go @@ -151,7 +151,7 @@ func TestGenerateOctopus(t *testing.T) { "fixture": { `type FooFT struct {`, `func MarshalFixtures(objs []*Foo) ([]byte, error) {`, - `func UnmarshalFixtures(source []byte) []*Foo {`, + `func UnmarshalFromYaml(source []byte) []*Foo {`, `func (objs FooList) String() string {`, }, }, @@ -205,7 +205,7 @@ func TestGenerateOctopus(t *testing.T) { `type FooFTPK struct {`, `type FooFT struct {`, `func MarshalFixtures(objs []*Foo) ([]byte, error) {`, - `func UnmarshalFixtures(source []byte) []*Foo {`, + `func UnmarshalFromYaml(source []byte) []*Foo {`, `func (objs FooList) String() string {`, }, }, @@ -289,7 +289,7 @@ func TestGenerateOctopus(t *testing.T) { `type FooFTPK struct {`, `type FooFT struct {`, `func MarshalFixtures(objs []*Foo) ([]byte, error) {`, - `func UnmarshalFixtures(source []byte) []*Foo {`, + `func UnmarshalFromYaml(source []byte) []*Foo {`, `func (objs FooList) String() string {`, }, }, diff --git a/internal/pkg/generator/tmpl/fixture_meta.tmpl b/internal/pkg/generator/tmpl/fixture_meta.tmpl new file mode 100644 index 0000000..fa1e746 --- /dev/null +++ b/internal/pkg/generator/tmpl/fixture_meta.tmpl @@ -0,0 +1,45 @@ +package {{ .FixturePkg }} + +import ( + "context" + "fmt" +) + +type FixtureMeta struct { + StoreIterator func(it func(any) error) error + Unpacker func(ctx context.Context, source []byte) (res []any, err error) + PrimaryKeyFields []string +} + +// NSFixtures Репозиторий сторов фикстур +type NSFixtures map[string]FixtureMeta + +{{ $nss := .Namespaces }} +var NamespaceFixtures = NSFixtures{ + {{ range $_, $ns := $nss -}} + "{{ $ns.Namespace.ObjectName }}": FixtureMeta{ + StoreIterator:{{ $ns.Namespace.PublicName }}Iterator(), + Unpacker: func(ctx context.Context, source []byte) (res []any, err error) { + fxts, err := {{ $ns.Namespace.ObjectName }}.UnmarshalFixtures(source) + if err != nil { + return nil, fmt.Errorf("can't decode tuple: %s", err) + } + + for _, v := range fxts { + res = append(res, v) + } + + return + }, + PrimaryKeyFields: []string{ + {{- if $ns.Indexes }} + {{- $pk := index $ns.Indexes 0 }} + {{- range $_, $fieldNum := $pk.Fields }} + {{- $ifield := index $ns.Fields $fieldNum }} + "{{$ifield.Name}}", + {{- end }} + {{ end -}} + }, + }, + {{ end }} +} \ No newline at end of file diff --git a/internal/pkg/generator/tmpl/meta.tmpl b/internal/pkg/generator/tmpl/meta.tmpl index 8e8ce37..2f57a5a 100644 --- a/internal/pkg/generator/tmpl/meta.tmpl +++ b/internal/pkg/generator/tmpl/meta.tmpl @@ -46,7 +46,7 @@ var NamespacePackages = NSPackage { return {{ $ns.Namespace.PackageName }}.MarshalFixtures([]*{{ $ns.Namespace.PackageName }}.{{ $ns.Namespace.PublicName }}{obj}) }, FixtureUnpacker: func(ctx context.Context, source []byte) (res []any, err error) { - fxts, err := {{ $ns.Namespace.PackageName }}.UnmarshalFixturesFromJSON(source) + fxts, err := {{ $ns.Namespace.PackageName }}.UnmarshalFixtures(source) if err != nil { return nil, fmt.Errorf("can't decode tuple: %s", err) } diff --git a/internal/pkg/generator/tmpl/octopus/fixture.tmpl b/internal/pkg/generator/tmpl/octopus/fixture.tmpl index f42cbea..f408f4d 100644 --- a/internal/pkg/generator/tmpl/octopus/fixture.tmpl +++ b/internal/pkg/generator/tmpl/octopus/fixture.tmpl @@ -78,7 +78,7 @@ func MarshalFixtures(objs []*{{$PublicStructName}}) ([]byte, error) { return yaml.Marshal(fts) } -func UnmarshalFixtures(source []byte) []*{{$PublicStructName}} { +func UnmarshalFromYaml(source []byte) []*{{$PublicStructName}} { var fixtures []{{$PublicStructName}}FT if err := yaml.Unmarshal(source, &fixtures); err != nil { @@ -108,7 +108,7 @@ func UnmarshalFixtures(source []byte) []*{{$PublicStructName}} { return objs } -func UnmarshalFixturesFromJSON(source []byte) ([]{{$PublicStructName}}FT, error) { +func UnmarshalFixtures(source []byte) ([]{{$PublicStructName}}FT, error) { source = bytes.TrimLeft(source, " \t\r\n") if len(source) > 0 && source[0] == '{' { @@ -187,7 +187,7 @@ func MarshalFixtures(objs []*{{$PublicStructName}}) ([]byte, error) { return yaml.Marshal(fts) } -func UnmarshalFixtures(source []byte) []*{{$PublicStructName}} { +func UnmarshalFromYaml(source []byte) []*{{$PublicStructName}} { var fixtures []{{$PublicStructName}}FT if err := yaml.Unmarshal(source, &fixtures); err != nil { @@ -296,7 +296,7 @@ func UnmarshalUpdateFixtures(source []byte) []*{{$PublicStructName}} { } func UnmarshalInsertReplaceFixtures(source []byte) []*{{$PublicStructName}} { - return UnmarshalFixtures(source) + return UnmarshalFromYaml(source) } func SetFixtureUpdateOptions(obj *{{$PublicStructName}}, updateOptions []{{$PublicStructName}}UpdateFixtureOptions) { @@ -317,5 +317,5 @@ func SetFixtureUpdateOptions(obj *{{$PublicStructName}}, updateOptions []{{$Pub {{ end }} func UnmarshalDeleteFixtures(source []byte) []*{{$PublicStructName}} { - return UnmarshalFixtures(source) + return UnmarshalFromYaml(source) } diff --git a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl index 0581d90..f906f79 100644 --- a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl @@ -41,7 +41,7 @@ var {{$PackageName}}Source []byte func init{{$PublicStructName}}() { {{$PackageName}}Once.Do(func() { - {{$PackageName}}Fixtures = {{$PackageName}}.UnmarshalFixtures({{$PackageName}}Source) + {{$PackageName}}Fixtures = {{$PackageName}}.UnmarshalFromYaml({{$PackageName}}Source) {{$PackageName}}Store = map[{{$typePK}}]int{} for i, f := range {{$PackageName}}Fixtures { diff --git a/internal/pkg/generator/tmpl/tarantool/fixture.tmpl b/internal/pkg/generator/tmpl/tarantool/fixture.tmpl index 11f6cc6..2f55f06 100644 --- a/internal/pkg/generator/tmpl/tarantool/fixture.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/fixture.tmpl @@ -33,7 +33,7 @@ type {{ $PublicStructName }}FT struct { {{- end }} } -func UnmarshalFixturesFromMessagePack(source []byte) ([]{{$PublicStructName}}FT, error) { +func UnmarshalFixtures(source []byte) ([]{{$PublicStructName}}FT, error) { var fts []{{$PublicStructName}}FT if err := msgpack.Unmarshal(source, &fts); err != nil { return nil, err @@ -42,7 +42,41 @@ func UnmarshalFixturesFromMessagePack(source []byte) ([]{{$PublicStructName}}FT, return fts, nil } -func UnmarshalFixtures(source []byte) []*{{$PublicStructName}} { +func (obj *{{ $PublicStructName }}FT) DecodeMsgpack(dec *msgpack.Decoder) error { + l, err := dec.DecodeArrayLen() + if err != nil { + return err + } + + if l != {{ len .FieldList }} { + return fmt.Errorf("unexpected count of fields") + } + + {{ range $ind, $fstruct := .FieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $sname := $fstruct.Serializer.Name -}} + {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $serparams := $fstruct.Serializer.Params }} + var v{{ $fstruct.Name }} {{ $rtype }} + if err := dec.Decode(&v{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode '{{ $fstruct.Name }}' field: %w", err) + } + + if err := {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}v{{ $fstruct.Name }}, &obj.{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't unpack '{{ $fstruct.Name }}' field: %w", err) + } + {{- else }} + if err := dec.Decode(&obj.{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode field '{{ $fstruct.Name }}': %w", err) + } + {{ end }} + {{ end }} + + return nil +} + +func UnmarshalFromYaml(source []byte) []*{{$PublicStructName}} { var fixtures []{{$PublicStructName}}FT if err := yaml.Unmarshal(source, &fixtures); err != nil { diff --git a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl index ead5655..96a0380 100644 --- a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl @@ -44,7 +44,7 @@ var {{$PackageName}}Source []byte func init{{$PublicStructName}}() { {{$PackageName}}Once.Do(func() { - {{$PackageName}}Fixtures = {{$PackageName}}.UnmarshalFixtures({{$PackageName}}Source) + {{$PackageName}}Fixtures = {{$PackageName}}.UnmarshalFromYaml({{$PackageName}}Source) {{$PackageName}}Store = map[{{$typePK}}]int{} for i, f := range {{$PackageName}}Fixtures { @@ -69,4 +69,18 @@ func Get{{$PublicStructName}}By{{$fieldNamePK}}({{$fieldNamePK}} {{$typePK}}) *{ res := {{$PackageName}}Fixtures[idx] return res +} + +func {{$PublicStructName}}Iterator() func(it func(any) error) error { + return func(it func(e any) error) error { + init{{$PublicStructName}}() + + for _, e := range {{$PackageName}}Fixtures { + if err := it(e); err != nil { + return err + } + } + + return nil + } } \ No newline at end of file diff --git a/internal/pkg/testutil/fixture.go b/internal/pkg/testutil/fixture.go deleted file mode 100644 index 110b2e6..0000000 --- a/internal/pkg/testutil/fixture.go +++ /dev/null @@ -1 +0,0 @@ -package testutil From 85a91cb09c0a7d29e313956dc1256afbe17f5e58 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Wed, 28 Feb 2024 06:29:32 +0300 Subject: [PATCH 12/18] fix fixture generator --- internal/pkg/generator/tmpl/fixture_meta.tmpl | 4 ++-- internal/pkg/generator/tmpl/octopus/fixture.tmpl | 8 ++++---- internal/pkg/generator/tmpl/octopus/fixturestore.tmpl | 2 +- internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/pkg/generator/tmpl/fixture_meta.tmpl b/internal/pkg/generator/tmpl/fixture_meta.tmpl index fa1e746..fea1629 100644 --- a/internal/pkg/generator/tmpl/fixture_meta.tmpl +++ b/internal/pkg/generator/tmpl/fixture_meta.tmpl @@ -18,9 +18,9 @@ type NSFixtures map[string]FixtureMeta var NamespaceFixtures = NSFixtures{ {{ range $_, $ns := $nss -}} "{{ $ns.Namespace.ObjectName }}": FixtureMeta{ - StoreIterator:{{ $ns.Namespace.PublicName }}Iterator(), + StoreIterator:{{ $ns.Namespace.PublicName }}StoreIterator(), Unpacker: func(ctx context.Context, source []byte) (res []any, err error) { - fxts, err := {{ $ns.Namespace.ObjectName }}.UnmarshalFixtures(source) + fxts, err := {{ $ns.Namespace.PackageName }}.UnmarshalFixtures(source) if err != nil { return nil, fmt.Errorf("can't decode tuple: %s", err) } diff --git a/internal/pkg/generator/tmpl/octopus/fixture.tmpl b/internal/pkg/generator/tmpl/octopus/fixture.tmpl index f408f4d..7b5459a 100644 --- a/internal/pkg/generator/tmpl/octopus/fixture.tmpl +++ b/internal/pkg/generator/tmpl/octopus/fixture.tmpl @@ -159,7 +159,7 @@ type {{ $PublicStructName }}FT struct { {{- end }} } -func UnmarshalFixturesFromJSON(source []byte) ([]{{$PublicStructName}}FT, error) { +func UnmarshalFixtures(source []byte) ([]{{$PublicStructName}}FT, error) { source = bytes.TrimLeft(source, " \t\r\n") if len(source) > 0 && source[0] == '{' { @@ -262,7 +262,7 @@ type {{ $PublicStructName }}UpdateFixtureOptions struct { {{ end }} {{- end }} -func UnmarshalUpdateFixtures(source []byte) []*{{$PublicStructName}} { +func UnmarshalUpdateFromYaml(source []byte) []*{{$PublicStructName}} { var fixtures []{{$PublicStructName}}UpdateFT if err := yaml.Unmarshal(source, &fixtures); err != nil { @@ -295,7 +295,7 @@ func UnmarshalUpdateFixtures(source []byte) []*{{$PublicStructName}} { return objs } -func UnmarshalInsertReplaceFixtures(source []byte) []*{{$PublicStructName}} { +func UnmarshalInsertReplaceFromYaml(source []byte) []*{{$PublicStructName}} { return UnmarshalFromYaml(source) } @@ -316,6 +316,6 @@ func SetFixtureUpdateOptions(obj *{{$PublicStructName}}, updateOptions []{{$Pub } {{ end }} -func UnmarshalDeleteFixtures(source []byte) []*{{$PublicStructName}} { +func UnmarshalDeleteFromYaml(source []byte) []*{{$PublicStructName}} { return UnmarshalFromYaml(source) } diff --git a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl index f906f79..4ed8dac 100644 --- a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl @@ -128,7 +128,7 @@ var {{$PackageName}}{{ $mockOperation }}Source []byte func init{{$mockOperation}}{{$PublicStructName}}() { {{$PackageName}}{{ $mockOperation }}Once.Do(func() { - {{$PackageName}}{{$mockOperation}}Fixtures = {{$PackageName}}.Unmarshal{{$mockOperation}}Fixtures({{$PackageName}}{{ $mockOperation }}Source) + {{$PackageName}}{{$mockOperation}}Fixtures = {{$PackageName}}.Unmarshal{{$mockOperation}}FromYaml({{$PackageName}}{{ $mockOperation }}Source) {{$PackageName}}{{$mockOperation}}Store = map[{{$typePK}}]int{} for i, f := range {{$PackageName}}{{$mockOperation}}Fixtures { diff --git a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl index 96a0380..9a24f24 100644 --- a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl @@ -71,7 +71,7 @@ func Get{{$PublicStructName}}By{{$fieldNamePK}}({{$fieldNamePK}} {{$typePK}}) *{ return res } -func {{$PublicStructName}}Iterator() func(it func(any) error) error { +func {{$PublicStructName}}StoreIterator() func(it func(any) error) error { return func(it func(e any) error) error { init{{$PublicStructName}}() From 06fbae457a9b1a1253d13497cff7c516ab124a17 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Wed, 28 Feb 2024 13:12:22 +0300 Subject: [PATCH 13/18] lua procedure generator --- internal/pkg/arerror/generator.go | 1 + internal/pkg/generator/tarantool.go | 15 +- .../tmpl/tarantool/fixturestore.tmpl | 6 +- .../generator/tmpl/tarantool/procedure.tmpl | 240 ++++++++++++++++++ 4 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/generator/tmpl/tarantool/procedure.tmpl diff --git a/internal/pkg/arerror/generator.go b/internal/pkg/arerror/generator.go index fd79327..df10f45 100644 --- a/internal/pkg/arerror/generator.go +++ b/internal/pkg/arerror/generator.go @@ -7,6 +7,7 @@ var ErrGeneratorBackendNotImplemented = errors.New("backend not implemented") var ErrGeneragorGetTmplLine = errors.New("can't get error lines") var ErrGeneragorEmptyTmplLine = errors.New("tmpl lines not set") var ErrGeneragorErrorLineNotFound = errors.New("template lines not found in error") +var ErrGeneratorTemplateUnkhown = errors.New("template unknown") // Описание ошибки генерации type ErrGeneratorPkg struct { diff --git a/internal/pkg/generator/tarantool.go b/internal/pkg/generator/tarantool.go index 38d5e82..86299b2 100644 --- a/internal/pkg/generator/tarantool.go +++ b/internal/pkg/generator/tarantool.go @@ -18,6 +18,10 @@ import ( //go:embed tmpl/tarantool/main.tmpl var tarantoolRootRepositoryTmpl string +//nolint:revive +//go:embed tmpl/tarantool/procedure.tmpl +var tarantoolProcRepositoryTmpl string + //nolint:revive //go:embed tmpl/tarantool/fixture.tmpl var tarantoolFixtureRepositoryTmpl string @@ -26,9 +30,18 @@ func GenerateTarantool(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGen mainWriter := bytes.Buffer{} fixtureWriter := bytes.Buffer{} + var repositoryTmpl string + if len(params.FieldList) > 0 { + repositoryTmpl = tarantoolRootRepositoryTmpl + } else if len(params.ProcOutFieldList) > 0 { + repositoryTmpl = tarantoolProcRepositoryTmpl + } else { + return nil, &arerror.ErrGeneratorPhases{Backend: "tarantool", Err: arerror.ErrGeneratorTemplateUnkhown} + } + octopusFile := bufio.NewWriter(&mainWriter) - err := GenerateByTmpl(octopusFile, params, "tarantool", tarantoolRootRepositoryTmpl, Tarantool2TmplFunc) + err := GenerateByTmpl(octopusFile, params, "tarantool", repositoryTmpl, Tarantool2TmplFunc) if err != nil { return nil, err } diff --git a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl index 9a24f24..8e38349 100644 --- a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl @@ -23,6 +23,8 @@ import ( {{ $typePK := "" -}} {{ $fieldNamePK := "" -}} +{{ if $fields }} + {{ range $num, $ind := .Indexes -}} {{ $lenfld := len $ind.Fields -}} {{ if $ind.Primary }} @@ -83,4 +85,6 @@ func {{$PublicStructName}}StoreIterator() func(it func(any) error) error { return nil } -} \ No newline at end of file +} + +{{ end }} \ No newline at end of file diff --git a/internal/pkg/generator/tmpl/tarantool/procedure.tmpl b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl new file mode 100644 index 0000000..7a102f3 --- /dev/null +++ b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl @@ -0,0 +1,240 @@ +package {{ .ARPkg }} + +import ( + "bytes" + "context" + "fmt" + "log" +{{ if eq .Server.Conf "" -}} + "time" +{{ end }} + "strings" + + "github.com/mailru/activerecord/pkg/activerecord" + "github.com/mailru/activerecord/pkg/tarantool" + tarantool2 "github.com/tarantool/go-tarantool" + "gopkg.in/vmihailenco/msgpack.v2" + +{{- range $ind, $imp := .Imports }} +{{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}" +{{- end }} +{{- range $i, $imp := addImport .FieldList }} + "{{ $imp }}" +{{- end }} +) + +{{ $pkgName := .ARPkg }} +{{ $serializers := .Serializers -}} +{{ $mutators := .Mutators -}} +{{ $PublicStructName := .ARPkgTitle -}} +{{ $LinkedObject := .LinkedObject }} +{{ $flags := .Flags }} +{{ $fields := .FieldList }} +{{ $procfields := .ProcOutFieldList }} +{{ $procInLen := len .ProcInFieldList }} +{{ $mutatorLen := len .Mutators }} + +{{ if $procfields }} +// proc struct +type {{ $PublicStructName }} struct { +params {{ $PublicStructName }}Params +{{- range $ind, $fstruct := .ProcOutFieldList }} +{{ $rtype := $fstruct.Format -}} +{{ $serlen := len $fstruct.Serializer -}} +{{ if ne $serlen 0 -}} +{{ $sname := index $fstruct.Serializer 0 -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end -}} +field{{- $fstruct.Name }} {{ $rtype -}} +{{ end }} +} + +type {{ $PublicStructName }}List []*{{ $PublicStructName }} + +const ( + procName string = "{{ .Container.ObjectName }}" + cntOutFields uint32 = {{ len .ProcOutFieldList }} +) + +{{ if eq .Server.Conf "" -}} +var boxOption, _ = tarantool.NewOptions( + "{{ .Server.Host }}:{{ .Server.Port }}", + activerecord.ModeMaster, + tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}, time.Millisecond * {{ .Server.Timeout }}), +) + +var clusterInfo = activerecord.NewClusterInfo( + activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}), +) +{{ else}} +var cfgName = "{{.Server.Conf }}" +{{ end }} + +func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error { + l, err := dec.DecodeArrayLen() + if err != nil { + return err + } + + if l != int(cntOutFields) { + return fmt.Errorf("unexpected count of fields") + } + + {{ range $ind, $fstruct := .ProcOutFieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $sname := $fstruct.Serializer.Name -}} + {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $serparams := $fstruct.Serializer.Params }} + var v{{ $fstruct.Name }} {{ $rtype }} + if err := dec.Decode(&v{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode '{{ $fstruct.Name }}' field: %w", err) + } + + if err := {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}v{{ $fstruct.Name }}, &obj.field{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't unpack '{{ $fstruct.Name }}' field: %w", err) + } + {{- else }} + if err := dec.Decode(&obj.field{{ $fstruct.Name }}); err != nil { + return fmt.Errorf("can't decode field '{{ $fstruct.Name }}': %w", err) + } + {{ end }} + {{ end }} + + return nil +} + +{{- range $ind, $fstruct := .ProcOutFieldList -}} +{{ $rtype := $fstruct.Format -}} +{{ $sname := $fstruct.Serializer.Name -}} +{{ if ne $sname "" -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end }} +func (obj *{{ $PublicStructName }}) Get{{ $fstruct.Name }}() {{ $rtype }} { + return obj.field{{ $fstruct.Name }} +} +{{ end }} + +type {{ $PublicStructName }}Params struct { + {{- range $ind, $fstruct := .ProcInFieldList -}} + {{ $rtype := $fstruct.Format -}} + {{ $serlen := len $fstruct.Serializer -}} + {{ if ne $serlen 0 -}} + {{ $sname := index $fstruct.Serializer 0 -}} + {{ $serializer := index $serializers $sname -}} + {{ $rtype = $serializer.Type -}} + {{ end }} + {{ $fstruct.Name }} {{ $rtype -}} + {{ end }} +} + +func (obj *{{ $PublicStructName }}) GetParams() {{ $PublicStructName }}Params { + return obj.params +} + +func (obj *{{ $PublicStructName }}) setParams(params {{ $PublicStructName }}Params) error { + obj.params = params + + return nil +} + +{{ if ne $procInLen 0 }} +func (obj *{{ $PublicStructName }}Params) arrayValues() ([]string, error) { + ret := []string{} + {{ range $ind, $fstruct := .ProcInFieldList -}} + {{ $sname := $fstruct.Serializer.Name -}} + {{ $bvar := $fstruct.Name -}} + {{ if ne $sname "" -}} + {{ $serializer := index $serializers $sname -}} + {{ $serparams := $fstruct.Serializer.Params -}} + pvar{{ $fstruct.Name }}, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}obj.{{ $bvar }}) + if err != nil { + return nil, fmt.Errorf("error marshal param field {{ $fstruct.Name }}: %w", err) + } + + {{ if eq $fstruct.Format "[]string" }} + ret = append(ret, pvar{{ $fstruct.Name }}...) + {{ else }} + ret = append(ret, string(pvar{{ $fstruct.Name }})) + {{- end }} + {{- else -}} + ret = append(ret, string(obj.{{ $fstruct.Name }})) + {{- end }} + {{ end }} + return ret, nil +} +{{ end }} + +func (obj {{ $PublicStructName }}Params) PK() string { + return fmt.Sprint({{ if ne $procInLen 0 }}obj.arrayValues(){{ end }}) +} + +func Call(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}) (*{{ $PublicStructName }}, error) { + return call(ctx{{ if ne $procInLen 0 }}, params{{ end }}, activerecord.ReplicaOrMasterInstanceType) +} + +func CallOnMaster(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}) (*{{ $PublicStructName }}, error) { + return call(ctx{{ if ne $procInLen 0 }}, params{{ end }}, activerecord.MasterInstanceType) +} + +func call(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}, instanceType activerecord.ShardInstanceType) (*{{ $PublicStructName }}, error) { + logger := activerecord.Logger() + ctx = logger.SetLoggerValueToContext(ctx, map[string]interface{}{"LuaProc": procName}) + metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") + metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") + + metricTimer.Timing(ctx, "call_proc") + + connection, err := tarantool.Box(ctx, 0, instanceType, cfgName, nil) + if err != nil { + metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) + logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) + + return nil, err + } + + var args []string + + args, err = params.arrayValues() + if err != nil { + metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) + + return nil, fmt.Errorf("Error parse args of procedure %s: %w", procName, err) + } + + var res *{{ $PublicStructName }} + + errCall := connection.Call17Typed(procName, args, &res) + if errCall != nil { + metricErrCnt.Inc(ctx, "call_proc", 1) + logger.Error(ctx, "Error execute from box", errCall, connection.Info()) + + return nil, fmt.Errorf("call lua procedure %s: %w", procName, errCall) + } + + + metricTimer.Finish(ctx, "call_proc") + + return res, nil +} + +{{ range $ind, $fstruct := .ProcOutFieldList -}} +{{ $packerparam := packerParam $fstruct.Format -}} +{{ $rtype := $fstruct.Format -}} +{{ $sname := $fstruct.Serializer.Name -}} +{{ if ne $sname "" -}} +{{ $serializer := index $serializers $sname -}} +{{ $rtype = $serializer.Type -}} +{{ end -}} +func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) error { + obj.field{{ $fstruct.Name }} = {{ $fstruct.Name}} + + return nil +} + +{{ end }} +// end proc struct + +{{end}} \ No newline at end of file From 019ee8d3ef6d58527b566b7782b33959083eafa3 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Wed, 28 Feb 2024 13:48:14 +0300 Subject: [PATCH 14/18] fix lua procedure template --- internal/pkg/generator/tarantool.go | 24 +++++++++++-------- internal/pkg/generator/tmpl/fixture_meta.tmpl | 4 +++- .../tmpl/tarantool/fixturestore.tmpl | 7 +++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/internal/pkg/generator/tarantool.go b/internal/pkg/generator/tarantool.go index 86299b2..0cba23c 100644 --- a/internal/pkg/generator/tarantool.go +++ b/internal/pkg/generator/tarantool.go @@ -27,8 +27,9 @@ var tarantoolProcRepositoryTmpl string var tarantoolFixtureRepositoryTmpl string func GenerateTarantool(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGeneratorPhases) { + ret := map[string]bytes.Buffer{} + mainWriter := bytes.Buffer{} - fixtureWriter := bytes.Buffer{} var repositoryTmpl string if len(params.FieldList) > 0 { @@ -48,18 +49,21 @@ func GenerateTarantool(params PkgData) (map[string]bytes.Buffer, *arerror.ErrGen octopusFile.Flush() - fixtureFile := bufio.NewWriter(&fixtureWriter) + ret["tarantool"] = mainWriter - err = GenerateByTmpl(fixtureFile, params, "tarantool", tarantoolFixtureRepositoryTmpl, Tarantool2TmplFunc) - if err != nil { - return nil, err - } + if len(params.FieldList) > 0 { + fixtureWriter := bytes.Buffer{} - fixtureFile.Flush() + fixtureFile := bufio.NewWriter(&fixtureWriter) - ret := map[string]bytes.Buffer{ - "tarantool": mainWriter, - "fixture": fixtureWriter, + err = GenerateByTmpl(fixtureFile, params, "tarantool", tarantoolFixtureRepositoryTmpl, Tarantool2TmplFunc) + if err != nil { + return nil, err + } + + fixtureFile.Flush() + + ret["fixture"] = fixtureWriter } return ret, nil diff --git a/internal/pkg/generator/tmpl/fixture_meta.tmpl b/internal/pkg/generator/tmpl/fixture_meta.tmpl index fea1629..9c552cb 100644 --- a/internal/pkg/generator/tmpl/fixture_meta.tmpl +++ b/internal/pkg/generator/tmpl/fixture_meta.tmpl @@ -17,6 +17,7 @@ type NSFixtures map[string]FixtureMeta {{ $nss := .Namespaces }} var NamespaceFixtures = NSFixtures{ {{ range $_, $ns := $nss -}} + {{- if $ns.Fields }} "{{ $ns.Namespace.ObjectName }}": FixtureMeta{ StoreIterator:{{ $ns.Namespace.PublicName }}StoreIterator(), Unpacker: func(ctx context.Context, source []byte) (res []any, err error) { @@ -42,4 +43,5 @@ var NamespaceFixtures = NSFixtures{ }, }, {{ end }} -} \ No newline at end of file + {{ end }} +} diff --git a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl index 8e38349..9ad44e0 100644 --- a/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/fixturestore.tmpl @@ -1,5 +1,9 @@ package {{ .FixturePkg }} +{{ $fields := .FieldList }} + +{{ if $fields }} + import ( _ "embed" "context" @@ -19,12 +23,9 @@ import ( {{ $serializers := .Serializers -}} {{ $PackageName := .ARPkg -}} {{ $PublicStructName := .ARPkgTitle -}} -{{ $fields := .FieldList }} {{ $typePK := "" -}} {{ $fieldNamePK := "" -}} -{{ if $fields }} - {{ range $num, $ind := .Indexes -}} {{ $lenfld := len $ind.Fields -}} {{ if $ind.Primary }} From f09955dcf7c115e43559516906d4f32ebbd0b1d8 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:47:27 +0300 Subject: [PATCH 15/18] fix lua procedure template --- .../pkg/generator/tmpl/tarantool/procedure.tmpl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/pkg/generator/tmpl/tarantool/procedure.tmpl b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl index 7a102f3..51aa460 100644 --- a/internal/pkg/generator/tmpl/tarantool/procedure.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl @@ -72,12 +72,21 @@ var cfgName = "{{.Server.Conf }}" {{ end }} func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error { - l, err := dec.DecodeArrayLen() + rowCnt, err := dec.DecodeArrayLen() if err != nil { return err } - if l != int(cntOutFields) { + if rowCnt != 1 { + return fmt.Errorf("unexpected response rows count: %d", rowCnt) + } + + rowFieldCount, err := dec.DecodeArrayLen() + if err != nil { + return err + } + + if rowFieldCount != int(cntOutFields) { return fmt.Errorf("unexpected count of fields") } From d0f6efd4baba145db01add902de3518509145eae Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 29 Feb 2024 04:12:41 +0300 Subject: [PATCH 16/18] fix lua procedure template --- internal/pkg/generator/tmpl/octopus/fixturestore.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl index 4ed8dac..be93b06 100644 --- a/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl +++ b/internal/pkg/generator/tmpl/octopus/fixturestore.tmpl @@ -192,9 +192,9 @@ func GetUpdate{{$PublicStructName}}FixtureBy{{ $fieldNamePK }}(ctx context.Conte } func {{$PublicStructName}}StoreIterator() func(it func(any) error) error { - init{{$PublicStructName}}() - return func(it func(e any) error) error { + init{{$PublicStructName}}() + for _, e := range {{$PackageName}}Fixtures { if err := it(e); err != nil { return err From b449160c75329bc4be7ab67791ac34f5df930e43 Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:00:53 +0300 Subject: [PATCH 17/18] add secure connection --- .../pkg/generator/tmpl/tarantool/main.tmpl | 23 +++++++++++-------- .../generator/tmpl/tarantool/procedure.tmpl | 11 +++++---- pkg/activerecord/cluster.go | 11 ++++++++- pkg/activerecord/cluster_test.go | 6 +++++ pkg/tarantool/box.go | 2 +- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index 23a9fc8..c48a891 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -64,15 +64,18 @@ const ( var boxOption, _ = tarantool.NewOptions( "{{ .Server.Host }}:{{ .Server.Port }}", activerecord.ModeMaster, - tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}, time.Millisecond * {{ .Server.Timeout }}), + tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}), ) +var optionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) { + return boxOption, nil +} + var clusterInfo = activerecord.NewClusterInfo( activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}), ) -{{ else}} -var cfgName = "{{.Server.Conf }}" {{ end }} +var cfgName = "{{.Server.Conf }}" func New(ctx context.Context) *{{ $PublicStructName }} { newObj := {{ $PublicStructName }}{} @@ -579,7 +582,7 @@ func (obj *{{ $PublicStructName }}) Delete(ctx context.Context) error { return fmt.Errorf("can't delete not exists object") } - connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "delete_preparebox", 1) logger.Error(ctx, "PromoBunches", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) @@ -627,7 +630,7 @@ func (obj *{{ $PublicStructName }}) Update(ctx context.Context) error { return obj.Replace(ctx) }*/ - connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "update_preparebox", 1) logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) @@ -672,7 +675,7 @@ func (obj *{{ $PublicStructName }}) Insert(ctx context.Context) error { return fmt.Errorf("can't insert already exists object") } - connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) @@ -716,7 +719,7 @@ func (obj *{{ $PublicStructName }}) Replace(ctx context.Context) error { return fmt.Errorf("can't replace not exists object") } - connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) @@ -756,7 +759,7 @@ func (obj *{{ $PublicStructName }}) InsertOrReplace(ctx context.Context) error { metricStatCnt.Inc(ctx, "insertorreplace_request", 1) - connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) @@ -795,7 +798,7 @@ func selectBox(ctx context.Context, indexnum uint32, keys []interface{}, iterTyp metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") - connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "select_preparebox", 1) logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) @@ -854,7 +857,7 @@ func executeSQL(ctx context.Context, sqlText string, args []any) ([]*{{ $PublicS metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}") metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}") - connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "execute_preparebox", 1) logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) diff --git a/internal/pkg/generator/tmpl/tarantool/procedure.tmpl b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl index 51aa460..b1aedd9 100644 --- a/internal/pkg/generator/tmpl/tarantool/procedure.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/procedure.tmpl @@ -61,15 +61,18 @@ const ( var boxOption, _ = tarantool.NewOptions( "{{ .Server.Host }}:{{ .Server.Port }}", activerecord.ModeMaster, - tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}, time.Millisecond * {{ .Server.Timeout }}), + tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}), ) +var optionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) { + return boxOption, nil +} + var clusterInfo = activerecord.NewClusterInfo( activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}), ) -{{ else}} -var cfgName = "{{.Server.Conf }}" {{ end }} +var cfgName = "{{.Server.Conf }}" func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error { rowCnt, err := dec.DecodeArrayLen() @@ -196,7 +199,7 @@ func call(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructNa metricTimer.Timing(ctx, "call_proc") - connection, err := tarantool.Box(ctx, 0, instanceType, cfgName, nil) + connection, err := tarantool.Box(ctx, 0, instanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}}) if err != nil { metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) diff --git a/pkg/activerecord/cluster.go b/pkg/activerecord/cluster.go index b442d1c..64edd6b 100644 --- a/pkg/activerecord/cluster.go +++ b/pkg/activerecord/cluster.go @@ -43,6 +43,8 @@ type ShardInstanceConfig struct { Mode ServerModeType PoolSize int Addr string + User string + Password string } // Структура описывающая инстанс в кластере @@ -322,7 +324,10 @@ func getShardInfoFromCfg(ctx context.Context, path string, globParam MapGlobPara shardTimeout := cfg.GetDuration(ctx, path+"/Timeout", globParam.Timeout) shardPoolSize := cfg.GetInt(ctx, path+"/PoolSize", globParam.PoolSize) - // информация по местерам + user, _ := cfg.GetStringIfExists(ctx, path+"/user") + password, _ := cfg.GetStringIfExists(ctx, path+"/password") + + // информация по мастерам master, exMaster := cfg.GetStringIfExists(ctx, path+"/master") if !exMaster { master, exMaster = cfg.GetStringIfExists(ctx, path) @@ -342,6 +347,8 @@ func getShardInfoFromCfg(ctx context.Context, path string, globParam MapGlobPara Mode: ModeMaster, PoolSize: shardPoolSize, Timeout: shardTimeout, + User: user, + Password: password, } opt, err := optionCreator(shardCfg) @@ -370,6 +377,8 @@ func getShardInfoFromCfg(ctx context.Context, path string, globParam MapGlobPara Mode: ModeReplica, PoolSize: shardPoolSize, Timeout: shardTimeout, + User: user, + Password: password, } opt, err := optionCreator(shardCfg) diff --git a/pkg/activerecord/cluster_test.go b/pkg/activerecord/cluster_test.go index 67e8082..75b40f3 100644 --- a/pkg/activerecord/cluster_test.go +++ b/pkg/activerecord/cluster_test.go @@ -36,6 +36,8 @@ func TestGetClusterInfoFromCfg(t *testing.T) { mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/master").Return("", false) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig").Return("host1,host2", true) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/replica").Return("", false) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/user").Return("", false) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/password").Return("", false) }, args: args{ ctx: ctx, @@ -80,6 +82,8 @@ func TestGetClusterInfoFromCfg(t *testing.T) { mockConfig.EXPECT().GetDurationIfExists(mock.Anything, mock.Anything).Return(0, false) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/master").Return("host2", true) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/replica").Return("host1", true) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/user").Return("", false) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/password").Return("", false) }, args: args{ ctx: ctx, @@ -126,6 +130,8 @@ func TestGetClusterInfoFromCfg(t *testing.T) { mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/master").Return("", false) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig").Return("host1", true) mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/replica").Return("host2", true) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/user").Return("", false) + mockConfig.EXPECT().GetStringIfExists(mock.Anything, "testconfig/password").Return("", false) }, args: args{ ctx: ctx, diff --git a/pkg/tarantool/box.go b/pkg/tarantool/box.go index 6f025ef..5afabc4 100644 --- a/pkg/tarantool/box.go +++ b/pkg/tarantool/box.go @@ -8,7 +8,7 @@ import ( ) var DefaultOptionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) { - return NewOptions(sic.Addr, sic.Mode, WithTimeout(sic.Timeout)) + return NewOptions(sic.Addr, sic.Mode, WithTimeout(sic.Timeout), WithCredential(sic.User, sic.Password)) } func Box(ctx context.Context, shard int, instType activerecord.ShardInstanceType, configPath string, optionCreator func(activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error)) (*Connection, error) { From 14eb25c8493e40251f4559d5d111e3ec3013366c Mon Sep 17 00:00:00 2001 From: ebirukov <15173395+ebirukov@users.noreply.github.com> Date: Thu, 7 Mar 2024 07:49:30 +0300 Subject: [PATCH 18/18] bugfix linked objects reference --- internal/pkg/generator/tmpl/tarantool/main.tmpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/pkg/generator/tmpl/tarantool/main.tmpl b/internal/pkg/generator/tmpl/tarantool/main.tmpl index c48a891..a1da49a 100644 --- a/internal/pkg/generator/tmpl/tarantool/main.tmpl +++ b/internal/pkg/generator/tmpl/tarantool/main.tmpl @@ -841,6 +841,7 @@ func selectBox(ctx context.Context, indexnum uint32, keys []interface{}, iterTyp } for _, r := range res { + r.BaseField.Objects = map[string][]tarantool.ModelStruct{} r.BaseField.Exists = true } @@ -876,6 +877,7 @@ func executeSQL(ctx context.Context, sqlText string, args []any) ([]*{{ $PublicS for _, r := range res { r.BaseField.Exists = true + r.BaseField.Objects = map[string][]tarantool.ModelStruct{} } metricStatCnt.Inc(ctx, "execute_tuples_res", float64(len(res)))