github.com/mailru/activerecord@v1.12.2/internal/pkg/generator/tmpl/tarantool/main.tmpl (about)

     1  package {{ .ARPkg }}
     2  
     3  import (
     4      "bytes"
     5      "context"
     6      "fmt"
     7      "log"
     8  {{ if eq .Server.Conf "" -}}
     9      "time"
    10  {{ end }}
    11      "strings"
    12  
    13      "github.com/mailru/activerecord/pkg/activerecord"
    14      "github.com/mailru/activerecord/pkg/tarantool"
    15      tarantool2 "github.com/tarantool/go-tarantool"
    16      "gopkg.in/vmihailenco/msgpack.v2"
    17  
    18  {{- range $ind, $imp := .Imports }}
    19  {{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}"
    20  {{- end }}
    21  {{- range $i, $imp := addImport .FieldList }}
    22      "{{ $imp }}"
    23  {{- end }}
    24  )
    25  
    26  {{ $pkgName := .ARPkg }}
    27  {{ $serializers := .Serializers -}}
    28  {{ $mutators := .Mutators -}}
    29  {{ $PublicStructName := .ARPkgTitle -}}
    30  {{ $LinkedObject := .LinkedObject }}
    31  {{ $flags := .Flags }}
    32  {{ $fields := .FieldList }}
    33  {{ $procfields := .ProcOutFieldList }}
    34  {{ $procInLen := len .ProcInFieldList }}
    35  {{ $mutatorLen := len .Mutators }}
    36  
    37  {{ if $fields }}
    38  
    39  type {{ $PublicStructName }} struct {
    40  tarantool.BaseField
    41  {{- range $ind, $fstruct := .FieldList -}}
    42  {{ $rtype := $fstruct.Format -}}
    43  {{ $serlen := len $fstruct.Serializer -}}
    44  {{ if ne $serlen 0 -}}
    45  {{ $sname := index $fstruct.Serializer 0 -}}
    46  {{ $serializer := index $serializers $sname -}}
    47  {{ $rtype = $serializer.Type -}}
    48  {{ end }}
    49  field{{ $fstruct.Name }} {{ $rtype -}}
    50  {{ end }}
    51  }
    52  
    53  const (
    54      namespace = "{{ .Container.ObjectName }}"
    55  	cntFields uint32 = {{ len .FieldList }}
    56  {{- range $fieldname, $flag := .Flags -}}
    57  {{ range $i, $flagname := $flag.Flags }}
    58  {{ $fieldname }}{{ $flagname }}Flag = 1 << {{ $i -}}
    59  {{ end -}}
    60  {{ end }}
    61  )
    62  
    63  {{ if eq .Server.Conf "" -}}
    64  var boxOption, _ = tarantool.NewOptions(
    65      "{{ .Server.Host }}:{{ .Server.Port }}",
    66      activerecord.ModeMaster,
    67      tarantool.WithTimeout(time.Millisecond * {{ .Server.Timeout }}),
    68  )
    69  
    70  var optionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) {
    71      return boxOption, nil
    72  }
    73  
    74  var clusterInfo = activerecord.NewClusterInfo(
    75      activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}),
    76  )
    77  {{ end }}
    78  var cfgName = "{{.Server.Conf }}"
    79  
    80  func New(ctx context.Context) *{{ $PublicStructName }} {
    81      newObj := {{ $PublicStructName }}{}
    82      {{- if $fields }}
    83      newObj.BaseField.UpdateOps = []tarantool2.Op{}
    84      newObj.BaseField.Objects = map[string][]tarantool.ModelStruct{}
    85      {{ end }}
    86      return &newObj
    87  }
    88  
    89  func Create(
    90  	ctx context.Context,
    91  {{- range $ind, $fstruct := .FieldList -}}
    92  {{ $rtype := $fstruct.Format -}}
    93  {{ $serlen := len $fstruct.Serializer -}}
    94  {{ if ne $serlen 0 -}}
    95  {{ $sname := index $fstruct.Serializer 0 -}}
    96  {{ $serializer := index $serializers $sname -}}
    97  {{ $rtype = $serializer.Type -}}
    98  {{ end }}
    99          v{{ $fstruct.Name }} {{ $rtype -}},
   100  {{- end -}}
   101  ) (*{{ $PublicStructName }}, error) {
   102      obj := New(ctx)
   103  
   104      {{ range $ind, $fstruct := .FieldList }}
   105      if err := obj.Set{{$fstruct.Name}}(v{{$fstruct.Name}}); err != nil {
   106          return nil, fmt.Errorf("can't create new {{ $PublicStructName }}: %w", err)
   107      }
   108      {{ end }}
   109  
   110      return obj, nil
   111  }
   112  
   113  func (obj *{{ $PublicStructName }}) packTuple() (any, error) {
   114      tuple := make([]any, 0, cntFields)
   115  
   116      var (
   117          v any
   118          err error
   119      )
   120  
   121      {{- range $ind, $fstruct := .FieldList -}}
   122      {{ $rtype := $fstruct.Format -}}
   123      {{ $serlen := len $fstruct.Serializer -}}
   124      {{ if ne $serlen 0 }}
   125      v, err = Marshal{{ $fstruct.Name }}(obj.field{{ $fstruct.Name }})
   126      if err != nil {
   127          return nil, fmt.Errorf("can't pack tuple field '{{ $fstruct.Name }}': %w", err)
   128      }
   129  	{{ else }}
   130      v = obj.field{{ $fstruct.Name }}
   131      {{ end }}
   132  
   133      tuple = append(tuple, v)
   134      {{ end }}
   135  
   136      return tuple, err
   137  }
   138  
   139  
   140  func (obj *{{ $PublicStructName }}) DecodeMsgpack(dec *msgpack.Decoder) error {
   141      l, err := dec.DecodeArrayLen()
   142      if err != nil {
   143          return err
   144      }
   145  
   146      if l != int(cntFields) {
   147          return fmt.Errorf("unexpected count of fields")
   148      }
   149  
   150      {{ range $ind, $fstruct := .FieldList -}}
   151      {{ $rtype := $fstruct.Format -}}
   152      {{ $sname := $fstruct.Serializer.Name -}}
   153          {{ if ne $sname "" -}}
   154          {{ $serializer := index $serializers $sname -}}
   155          {{ $serparams := $fstruct.Serializer.Params }}
   156      var v{{ $fstruct.Name }}  {{ $rtype }}
   157      if err := dec.Decode(&v{{ $fstruct.Name }}); err != nil {
   158          return fmt.Errorf("can't decode '{{ $fstruct.Name }}' field: %w", err)
   159      }
   160  
   161      if err := {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}v{{ $fstruct.Name }}, &obj.field{{ $fstruct.Name }}); err != nil {
   162          return fmt.Errorf("can't unpack '{{ $fstruct.Name }}' field: %w", err)
   163      }
   164          {{- else }}
   165      if err := dec.Decode(&obj.field{{ $fstruct.Name }}); err != nil {
   166          return fmt.Errorf("can't decode field '{{ $fstruct.Name }}': %w", err)
   167      }
   168          {{ end }}
   169      {{ end }}
   170  
   171      return nil
   172  }
   173  
   174  func (obj *{{ $PublicStructName }}) PrimaryString() string {
   175      ret := []string{
   176          {{- range $ind, $fstruct := .FieldList }}
   177          {{- if $fstruct.PrimaryKey }}
   178          {{- $packerparam := packerParam $fstruct.Format }}
   179          {{- $tostr := $packerparam.ToString }}
   180          {{ index $tostr 0 }}obj.Get{{ $fstruct.Name }}(){{ index $tostr 1 }},
   181          {{- end }}
   182          {{- end }}
   183      }
   184  
   185      return strings.Join(ret, ", ")
   186  }
   187  
   188  
   189  {{ $pktype := "" }}
   190  {{ $pklenfld := 1 }}
   191  {{ $pkind := index .Indexes 0 }}
   192  {{ range $num, $ind := .Indexes -}}
   193  {{ $lenfld := len $ind.Fields -}}
   194  {{ if $ind.Primary }}
   195  {{ $pktype = $ind.Type }}
   196  {{ $pklenfld = len $ind.Fields }}
   197  {{ $pkind = $ind }}
   198  func (obj *{{ $PublicStructName }}) Primary() {{ $ind.Type }} {
   199      {{ if ne $lenfld 1 }}
   200      return {{ $ind.Type }}{
   201          {{- range $_, $fieldNum := $ind.Fields }}
   202          {{- $ifield := index $fields $fieldNum }}
   203          {{ $ifield.Name }}: obj.Get{{ $ifield.Name }}(),
   204          {{- end }}
   205      }
   206      {{ else }}
   207      {{- range $_, $fieldNum := $ind.Fields }}
   208      {{- $ifield := index $fields $fieldNum }}
   209      return obj.Get{{ $ifield.Name }}()
   210      {{- end }}
   211      {{ end -}}
   212  }
   213  
   214  func (obj *{{ $PublicStructName }}) packPrimary() []any {
   215      return []any{
   216          {{- range $_, $fieldNum := $ind.Fields }}
   217          {{- $ifield := index $fields $fieldNum }}
   218          {{ $rtype := $ifield.Format -}}
   219          obj.Get{{ $ifield.Name }}(),
   220          {{- end }}
   221      }
   222  }
   223  
   224  func SelectByPrimary(ctx context.Context, pk {{ $ind.Type }}) (*{{ $PublicStructName }}, error) {
   225      return {{ $ind.Selector }}(ctx, pk)
   226  }
   227  
   228  {{ end }}
   229  {{ end }}
   230  
   231  
   232  
   233  {{end}}
   234  
   235  
   236  // Induces
   237  
   238  {{ range $num, $ind := .Indexes -}}
   239  {{ $lenfld := len $ind.Fields -}}
   240  {{ if ne $lenfld 1 }}
   241  type {{ $ind.Type }} struct {
   242  {{- range $_, $fieldNum := $ind.Fields }}
   243  {{- $ifield := index $fields $fieldNum }}
   244  {{ $rtype := $ifield.Format -}}
   245  {{ $serlen := len $ifield.Serializer -}}
   246  {{ if ne $serlen 0 -}}
   247  {{ $sname := index $ifield.Serializer 0 -}}
   248  {{ $serializer := index $serializers $sname -}}
   249  {{ $rtype = $serializer.Type -}}
   250  {{ end }}
   251  {{ $ifield.Name }} {{ $rtype -}}
   252  {{- end }}
   253  }
   254  
   255  type {{ $ind.Type }}s []{{ $ind.Type }}
   256  
   257  func (idx {{ $ind.Type }}) pack() []any {
   258  	return []any{
   259          {{- range $_, $fieldNum := $ind.Fields }}
   260          {{- $ifield := index $fields $fieldNum }}
   261          {{ $rtype := $ifield.Format -}}
   262          idx.{{ $ifield.Name }},
   263  		{{- end }}
   264      }
   265  }
   266  
   267  // возвращает предикат для sql запроса формата IN (?,..) OR IN (?,..) и список параметров для него
   268  func (idxs {{ $ind.Type }}s) buildSQLPredicateIN() (string, []any) {
   269      args := make([]any, 0, len(idxs))
   270  
   271      var (
   272      	buf strings.Builder
   273  		predicate string
   274      )
   275  
   276      {{- range $_, $fieldNum := $ind.Fields }}
   277      {{- $ifield := index $fields $fieldNum }}
   278      {{ $rtype := $ifield.Format -}}
   279      predicate = tarantool.BuildSQLPredicateIN("{{ $ifield.Name | lowerCase -}}", len(idxs))
   280      buf.WriteString(predicate)
   281  
   282      for _, idx := range idxs {
   283          args = append(args, idx.{{ $ifield.Name }})
   284      }
   285  
   286      buf.WriteString(" AND ")
   287  	{{ end }}
   288  
   289      buf.WriteString(" 1 = 1 ")
   290  
   291      return buf.String(), args
   292  }
   293  {{- else -}}
   294  {{ $ifld := index $ind.Fields 0 }}
   295  {{ $ifield := index $fields $ifld }}
   296  type {{ $ind.Name }}s []{{ $ind.Type }}
   297  
   298  func (idxs {{ $ind.Name }}s) buildSQLPredicateIN() (string, []any) {
   299      args := make([]any, 0, len(idxs))
   300      for _, key := range idxs {
   301          args = append(args, key)
   302      }
   303  
   304      return tarantool.BuildSQLPredicateIN("{{ $ifield.Name | lowerCase -}}", len(idxs)), args
   305  }
   306  {{ end }}
   307  
   308  func {{ $ind.Selector }}s(ctx context.Context, keys []{{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ([]*{{ $PublicStructName }}, error) {
   309      ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"{{ $ind.Selector }}s": keys, "Repo": "{{ $PublicStructName }}"})
   310  
   311      inPredicate, args := {{ if ne $lenfld 1 -}} {{ $ind.Type }} {{- else }} {{ $ind.Name }} {{- end }}s(keys).buildSQLPredicateIN()
   312  
   313      return executeSQL(ctx, "SELECT * FROM \"" + namespace + "\" WHERE " + inPredicate, args)
   314  }
   315  
   316  func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ({{ if $ind.Unique }}{{ else }}[]{{ end }}*{{ $PublicStructName }}, error) {
   317      ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"{{ $ind.Selector }}": key, "Repo": "{{ $PublicStructName }}"})
   318  
   319      {{ if $ind.Unique }}
   320      limiter := activerecord.EmptyLimiter()
   321      {{ end }}
   322      selected, err := selectBox(ctx, {{$ind.Num}}, {{ if ne $lenfld 1 -}} key.pack() {{- else }} []any{key} {{- end }}, tarantool2.IterEq, limiter)
   323      if err != nil {
   324          return nil, err
   325      }
   326  
   327      {{ if $ind.Unique -}}
   328      if len(selected) > 0 {
   329          if len(selected) > 1 {
   330              activerecord.Logger().Error(ctx, "{{ $PublicStructName }}", "More than one tuple for uniq key ID '%s': %d", key, len(selected))
   331          }
   332  
   333          return selected[0], nil
   334      }
   335  
   336      return nil, nil
   337      {{- else }}
   338  
   339      return selected, nil
   340      {{- end }}
   341  }
   342  
   343  
   344  {{ end }}
   345  // End Induces
   346  
   347  
   348  // linked objects
   349  {{ range $name, $fobj := .FieldObject -}}
   350  {{ $linkedobj := index $LinkedObject $fobj.ObjectName }}
   351  func (obj *{{ $PublicStructName }}) Get{{ $name }}(ctx context.Context) ({{ if not $fobj.Unique }}[]{{ end }}*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}, error){
   352      {{- if $fobj.Unique }}
   353      if ret, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(ret) == 1 {
   354          return ret[0].(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}), nil
   355      }
   356  
   357      ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}())
   358      if err != nil {
   359          return nil, err
   360      }
   361  
   362      obj.BaseField.Objects["{{ $name }}"] = []tarantool.ModelStruct{ret}
   363      {{- else }}
   364  
   365      var ret []*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}
   366  
   367      if retI, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(retI) > 0 {
   368          for _, ri := range retI {
   369              ret = append(ret, ri.(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}))
   370          }
   371  
   372          return ret, nil
   373      }
   374  
   375      ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}(), activerecord.NewLimiter(100)) //ToDo default limit for multi object
   376      if err != nil {
   377          return nil, err
   378      }
   379  
   380      if len(ret) == 100 {
   381          activerecord.Logger().Warn(ctx, "limit for multiple linked object riched '{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}' '{{ $PublicStructName }}'")
   382      }
   383  
   384      for _, r := range ret {
   385          obj.BaseField.Objects["{{ $name }}"] = append(obj.BaseField.Objects["{{ $name }}"], r)
   386      }
   387      {{- end }}
   388  
   389      return ret, nil
   390  }
   391  
   392  {{ end -}}
   393  // End linked objects
   394  
   395  
   396  // Getters,Setters and Mutators
   397  
   398  {{ range $ind, $fstruct := .FieldList -}}
   399  {{ $rtype := $fstruct.Format -}}
   400  {{ $sname := $fstruct.Serializer.Name -}}
   401      {{ if ne $sname "" -}}
   402      {{ $serializer := index $serializers $sname -}}
   403      {{ $rtype = $serializer.Type -}}
   404      func Marshal{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) (any, error) {
   405          {{ $serparams := $fstruct.Serializer.Params -}}
   406          pvar, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $fstruct.Name }})
   407          if err != nil {
   408              return nil, fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err)
   409          }
   410  
   411          return pvar, nil
   412      }
   413  
   414      {{ end -}}
   415  
   416  func (obj *{{ $PublicStructName }}) Get{{ $fstruct.Name }}() {{ $rtype }} {
   417      return obj.field{{ $fstruct.Name }}
   418  }
   419  
   420  func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) error {
   421      {{- if $fstruct.PrimaryKey }}
   422      if obj.BaseField.Exists {
   423          return fmt.Errorf("can't modify field included in primary key")
   424      }
   425  
   426      {{ end -}}
   427  
   428      {{ if ne $sname "" -}}
   429      {{ $serializer := index $serializers $sname -}}
   430      {{ $serparams := $fstruct.Serializer.Params -}}
   431      data, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $fstruct.Name }})
   432      if err != nil {
   433          return fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err)
   434      }
   435      {{- else }}
   436      data := {{ $fstruct.Name }}
   437  	{{ end }}
   438  
   439      {{- if eq $fstruct.Format "string" "[]byte" -}}
   440      {{- if gt $fstruct.Size 0 }}
   441  
   442      if len(data) > {{ $fstruct.Size }} {
   443          return fmt.Errorf("max length of field '{{ $PublicStructName }}.{{ $fstruct.Name }}' is '%d' (received '%d')", {{ $fstruct.Size }}, len(data))
   444      }
   445      {{- else }}
   446  
   447      logger := activerecord.Logger()
   448  
   449      logger.Warn(context.TODO(), "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Size for field '{{ $fstruct.Name }}' not set. Cur field size: %d. Object: '{{ $PublicStructName }}'", len(data)))
   450      {{- end }}
   451      {{- end }}
   452  
   453      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{"=", {{ $ind }}, data })
   454      obj.field{{ $fstruct.Name }} = {{ $fstruct.Name}}
   455  
   456      {{- if ne $fstruct.ObjectLink "" }}
   457              delete(obj.BaseField.Objects, "{{ $fstruct.ObjectLink }}")
   458      {{- end }}
   459  
   460      return nil
   461  }
   462  
   463  {{- range $i, $mut := $fstruct.Mutators -}}
   464  {{ $customMutator := index $mutators $mut -}}
   465      {{- if $customMutator.Name }}
   466  
   467      {{ range $i, $f := $customMutator.PartialFields }}
   468  // Set{{ $customMutator.Name }}{{ $f.Name }} is a stub for backport compatibility
   469  func (obj *{{ $PublicStructName }}) Set{{ $customMutator.Name }}{{ $f.Name }}({{ $f.Name }} {{ $f.Type }}) error {
   470      pVar := obj.Get{{ $fstruct.Name }}()
   471      {{ $underlyingType := trimPrefix (printf "%s" $rtype) "*"}}
   472      {{- $isPointer := hasPrefix (printf "%s" $rtype) "*" -}}
   473      {{- if $isPointer -}}
   474      if pVar == nil {
   475          pVar = new({{$underlyingType}})
   476      }
   477  	{{ end}}
   478  
   479      pVar.{{ $f.Name }} = {{ $f.Name }}
   480  
   481      return obj.Set{{ $fstruct.Name }}(pVar)
   482  }
   483          {{ end }}
   484      {{ else }}
   485      {{ $mtype := $fstruct.Format }}
   486  func (obj *{{ $PublicStructName }}) {{ $mut | snakeToCamelCase }}{{ $fstruct.Name }}(mutArg {{ $mtype }}) error {
   487      {{- if eq $mut "inc" }}
   488      if mutArg == 0 {
   489          return nil
   490      }
   491  
   492      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "+", Arg: mutArg})
   493      obj.field{{ $fstruct.Name }} += mutArg
   494      {{- else if eq $mut "dec" }}
   495      if mutArg == 0 {
   496          return nil
   497      }
   498  
   499      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "-", Arg: mutArg})
   500      obj.field{{ $fstruct.Name }} -= mutArg
   501      {{- else if eq $mut "and" }}
   502      if obj.field{{ $fstruct.Name }} == 0 || obj.field{{ $fstruct.Name }} & mutArg == obj.field{{ $fstruct.Name }} {
   503          return nil
   504      }
   505  
   506      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "&", Arg: mutArg})
   507      obj.field{{ $fstruct.Name }} &= mutArg
   508      {{- else if eq $mut "or" "set_bit" }}
   509      if mutArg == 0 || obj.field{{ $fstruct.Name }} | mutArg == obj.field{{ $fstruct.Name }} {
   510          return nil
   511      }
   512  
   513      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "|", Arg: mutArg})
   514      obj.field{{ $fstruct.Name }} |= mutArg
   515      {{- else if eq $mut "clear_bit" }}
   516      if mutArg == 0 || obj.field{{ $fstruct.Name }} & ^mutArg == obj.field{{ $fstruct.Name }} {
   517          return nil
   518      }
   519  
   520      mutArg &= ^mutArg
   521  
   522      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "=", Arg: mutArg})
   523      obj.field{{ $fstruct.Name }} = mutArg
   524      {{- else if eq $mut "xor" }}
   525      if mutArg == 0 || obj.field{{ $fstruct.Name }} ^ mutArg == obj.field{{ $fstruct.Name }} {
   526          return nil
   527      }
   528  
   529      obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, tarantool2.Op{Field: {{ $ind }}, Op: "^", Arg: mutArg})
   530      obj.field{{ $fstruct.Name }} ^= mutArg
   531      {{- else }}
   532      Unknown mutator type in template!!!
   533      {{- end }}
   534  
   535      return nil
   536  }
   537      {{- end }}
   538  {{ end}}
   539  
   540  {{- $fl := index $flags $fstruct.Name }}
   541  {{- if $fl }}
   542  {{- range $i, $flag := $fl.Flags }}
   543  
   544  func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}{{ $flag }}() error {
   545      return obj.SetBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag )
   546  }
   547  
   548  func (obj *{{ $PublicStructName }}) Clear{{ $fstruct.Name }}{{ $flag }}() error {
   549      return obj.ClearBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag )
   550  }
   551  
   552  func (obj *{{ $PublicStructName }}) Is{{ $fstruct.Name }}{{ $flag }}() bool {
   553      return obj.Get{{ $fstruct.Name }}() & {{ $fstruct.Name }}{{ $flag }}Flag == {{ $fstruct.Name }}{{ $flag }}Flag
   554  }
   555  {{- end }}
   556  {{- end }}
   557  
   558  {{ end -}}
   559  
   560  // End of Getters, Setters and Mutators
   561  
   562  func SelectAll(ctx context.Context, limiter activerecord.SelectorLimiter) ([]*{{ $PublicStructName }}, error) {
   563      ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"SelectAll": "", "Repo": "{{ $PublicStructName }}"})
   564  
   565      res, err := selectBox(ctx, 0, []any{}, tarantool2.IterAll, limiter)
   566      if err != nil {
   567          return res, err
   568      }
   569  
   570      return res, nil
   571  }
   572  
   573  func (obj *{{ $PublicStructName }}) Delete(ctx context.Context) error {
   574      logger := activerecord.Logger()
   575      metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}")
   576      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   577      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   578  
   579      metricStatCnt.Inc(ctx, "delete_request", 1)
   580  
   581      if !obj.BaseField.Exists {
   582          return fmt.Errorf("can't delete not exists object")
   583      }
   584  
   585      connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   586      if err != nil {
   587          metricErrCnt.Inc(ctx, "delete_preparebox", 1)
   588          logger.Error(ctx, "PromoBunches", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err))
   589  
   590          return err
   591      }
   592  
   593      _, errCall := connection.Delete(namespace, 0, obj.packPrimary())
   594      if errCall != nil {
   595          metricErrCnt.Inc(ctx, "delete_box", 1)
   596          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error delete from box", errCall, connection.Info())
   597  
   598          return errCall
   599      }
   600  
   601      metricStatCnt.Inc(ctx, "delete_success", 1)
   602  
   603      obj.BaseField.Exists = false
   604      obj.BaseField.UpdateOps = []tarantool2.Op{}
   605  
   606      logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success delete")
   607  
   608      metricTimer.Finish(ctx, "delete")
   609  
   610      return nil
   611  }
   612  
   613  func (obj *{{ $PublicStructName }}) Update(ctx context.Context) error {
   614      logger := activerecord.Logger()
   615      metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}")
   616      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   617      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   618  
   619      metricStatCnt.Inc(ctx, "update_request", 1)
   620  
   621      if !obj.BaseField.Exists {
   622          metricErrCnt.Inc(ctx, "update_notexists", 1)
   623          return fmt.Errorf("can't update not exists object")
   624      }
   625  
   626      /*	if obj.BaseField.Repaired {
   627      	metricStatCnt.Inc(ctx, "update_repaired", 1)
   628      	logger.Debug(ctx, "", obj.PrimaryString(), "Flag 'Repaired' is true! Insert instead Update")
   629  
   630      	return obj.Replace(ctx)
   631      }*/
   632  
   633      connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   634      if err != nil {
   635          metricErrCnt.Inc(ctx, "update_preparebox", 1)
   636          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err))
   637          return err
   638      }
   639  
   640      if len(obj.BaseField.UpdateOps) == 0 {
   641          metricStatCnt.Inc(ctx, "update_empty", 1)
   642          logger.Debug(ctx, "", obj.PrimaryString(), "Empty update")
   643  
   644          return nil
   645      }
   646  
   647      _, errCall := connection.Update(namespace, 0, obj.packPrimary(), obj.UpdateOps)
   648      if errCall != nil {
   649          metricErrCnt.Inc(ctx, "update_box", 1)
   650          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error update ia a box", errCall, connection.Info())
   651          return errCall
   652      }
   653  
   654      metricTimer.Timing(ctx, "update_box")
   655  
   656      obj.BaseField.UpdateOps = []tarantool2.Op{}
   657  
   658      logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success update")
   659  
   660      metricStatCnt.Inc(ctx, "update_success", 1)
   661      metricTimer.Finish(ctx, "update")
   662  
   663      return nil
   664  }
   665  
   666  func (obj *{{ $PublicStructName }}) Insert(ctx context.Context) error {
   667      logger := activerecord.Logger()
   668      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   669      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   670  
   671      metricStatCnt.Inc(ctx, "insert_request", 1)
   672  
   673      if obj.BaseField.Exists {
   674          metricErrCnt.Inc(ctx, "insert_exists", 1)
   675          return fmt.Errorf("can't insert already exists object")
   676      }
   677  
   678      connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   679      if err != nil {
   680          metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1)
   681          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err))
   682          return err
   683      }
   684  
   685      tuple, err := obj.packTuple()
   686      if err != nil {
   687          metricErrCnt.Inc(ctx, "insertreplace_packfield", 1)
   688  
   689          return err
   690      }
   691  
   692      _, errCall := connection.Insert(namespace, tuple)
   693      if errCall != nil {
   694          metricErrCnt.Inc(ctx, "insertreplace_box", 1)
   695          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error insert into box", errCall, connection.Info())
   696  
   697          return errCall
   698      }
   699  
   700      if err == nil {
   701          metricStatCnt.Inc(ctx, "insert_success", 1)
   702      }
   703  
   704      obj.UpdateOps = []tarantool2.Op{}
   705      obj.BaseField.Exists = true
   706  
   707      return err
   708  }
   709  
   710  func (obj *{{ $PublicStructName }}) Replace(ctx context.Context) error {
   711      logger := activerecord.Logger()
   712      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   713      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   714  
   715      metricStatCnt.Inc(ctx, "replace_request", 1)
   716  
   717      if !obj.BaseField.Exists {
   718          metricErrCnt.Inc(ctx, "replace_notexists", 1)
   719          return fmt.Errorf("can't replace not exists object")
   720      }
   721  
   722      connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   723      if err != nil {
   724          metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1)
   725          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err))
   726  
   727          return err
   728      }
   729  
   730      tuple, err := obj.packTuple()
   731      if err != nil {
   732          metricErrCnt.Inc(ctx, "insertreplace_packfield", 1)
   733  
   734          return err
   735      }
   736  
   737      _, errCall := connection.Replace(namespace, tuple)
   738      if errCall != nil {
   739          metricErrCnt.Inc(ctx, "insertreplace_box", 1)
   740          logger.Error(ctx, "PromoBunches", obj.PrimaryString(), "Error replace on box", errCall, connection.Info())
   741  
   742          return errCall
   743      }
   744  
   745      if err == nil {
   746          metricStatCnt.Inc(ctx, "replace_success", 1)
   747      }
   748  
   749      obj.UpdateOps = []tarantool2.Op{}
   750      obj.BaseField.Exists = true
   751  
   752      return err
   753  }
   754  
   755  func (obj *{{ $PublicStructName }}) InsertOrReplace(ctx context.Context) error {
   756      logger := activerecord.Logger()
   757      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   758      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   759  
   760      metricStatCnt.Inc(ctx, "insertorreplace_request", 1)
   761  
   762      connection, err := tarantool.Box(ctx, 0, activerecord.MasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   763      if err != nil {
   764          metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1)
   765          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err))
   766          return err
   767      }
   768  
   769      tuple, err := obj.packTuple()
   770      if err != nil {
   771          metricErrCnt.Inc(ctx, "insertreplace_packfield", 1)
   772  
   773          return err
   774      }
   775  
   776      _, errCall := connection.Upsert(namespace, tuple, obj.UpdateOps)
   777      if errCall != nil {
   778          metricErrCnt.Inc(ctx, "insertreplace_box", 1)
   779          logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error upsert box", errCall, connection.Info())
   780  
   781          return errCall
   782      }
   783  
   784      if err == nil {
   785          metricStatCnt.Inc(ctx, "insertorreplace_success", 1)
   786      }
   787  
   788      obj.UpdateOps = []tarantool2.Op{}
   789      obj.BaseField.Exists = true
   790  
   791      return err
   792  }
   793  
   794  func selectBox(ctx context.Context, indexnum uint32, keys []interface{}, iterType uint32, limiter activerecord.SelectorLimiter) ([]*{{ $PublicStructName }}, error) {
   795      logger := activerecord.Logger()
   796      ctx = logger.SetLoggerValueToContext(ctx, activerecord.ValueLogPrefix{"limiter": limiter.String()})
   797      metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}")
   798      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   799      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   800  
   801      connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   802      if err != nil {
   803          metricErrCnt.Inc(ctx, "select_preparebox", 1)
   804          logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err))
   805  
   806          return nil, err
   807      }
   808  
   809      var res []*{{ $PublicStructName }}
   810  
   811      limit := limiter.Limit()
   812      if limiter.Limit() == 0 {
   813          limit = math.MaxInt32
   814      }
   815  
   816      errCall := connection.SelectTyped(namespace, indexnum, limiter.Offset(), limit, iterType, keys, &res)
   817      if errCall != nil {
   818          metricErrCnt.Inc(ctx, "select_box", 1)
   819          logger.Error(ctx, "Error select from box", errCall, connection.Info())
   820  
   821          return nil, errCall
   822      }
   823  
   824      metricTimer.Timing(ctx, "select_box")
   825      metricStatCnt.Inc(ctx, "select_tuples_res", float64(len(res)))
   826  
   827      if limiter.FullfillWarn() && len(res) == int(limiter.Limit()) {
   828          logger.Warn(ctx, "Select limit reached. Result may less than db records.")
   829      }
   830  
   831      mode, ok := connection.InstanceMode().(activerecord.ServerModeType)
   832      if !ok || mode == activerecord.ModeReplica {
   833          if !ok {
   834              logger.Error(ctx, "Invalid server mode type: %T", connection.InstanceMode())
   835          }
   836  
   837          for _, r := range res {
   838              r.BaseField.IsReplica = true
   839              r.BaseField.ReadOnly = true
   840          }
   841      }
   842  
   843      for _, r := range res {
   844          r.BaseField.Objects = map[string][]tarantool.ModelStruct{}
   845          r.BaseField.Exists = true
   846      }
   847  
   848      logger.Debug(ctx, "Success select")
   849  
   850      metricTimer.Finish(ctx, "select")
   851  
   852      return res, nil
   853  }
   854  
   855  func executeSQL(ctx context.Context, sqlText string, args []any) ([]*{{ $PublicStructName }}, error) {
   856      logger := activerecord.Logger()
   857      metricTimer := activerecord.Metric().Timer("tarantool", "{{ $PublicStructName }}")
   858      metricStatCnt := activerecord.Metric().StatCount("tarantool", "{{ $PublicStructName }}")
   859      metricErrCnt := activerecord.Metric().ErrorCount("tarantool", "{{ $PublicStructName }}")
   860  
   861      connection, err := tarantool.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, cfgName, {{ if eq .Server.Conf "" -}}optionCreator{{ else }}nil{{ end -}})
   862      if err != nil {
   863          metricErrCnt.Inc(ctx, "execute_preparebox", 1)
   864          logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err))
   865  
   866          return nil, err
   867      }
   868  
   869      var res []*{{ $PublicStructName }}
   870  
   871      if _, _, errCall := connection.ExecuteTyped(sqlText, args, &res); err != nil {
   872          metricErrCnt.Inc(ctx, "execute_box", 1)
   873          logger.Error(ctx, "Error execute from box", errCall, connection.Info())
   874  
   875          return nil, errCall
   876      }
   877  
   878      for _, r := range res {
   879          r.BaseField.Exists = true
   880          r.BaseField.Objects = map[string][]tarantool.ModelStruct{}
   881      }
   882  
   883      metricStatCnt.Inc(ctx, "execute_tuples_res", float64(len(res)))
   884  
   885      logger.Debug(ctx, "Success execute")
   886  
   887      metricTimer.Finish(ctx, "execute")
   888  
   889      return res, nil
   890  }