github.com/mailru/activerecord@v1.12.2/internal/pkg/generator/tmpl/octopus/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/iproto/iproto" 14 "github.com/mailru/activerecord/pkg/activerecord" 15 "github.com/mailru/activerecord/pkg/octopus" 16 {{- range $ind, $imp := .Imports }} 17 {{ if ne $imp.ImportName "" }}{{ $imp.ImportName }} {{ end }}"{{ $imp.Path }}" 18 {{- end }} 19 {{- range $i, $imp := addImport .FieldList }} 20 "{{ $imp }}" 21 {{- end }} 22 ) 23 {{ $pkgName := .ARPkg }} 24 {{ $serializers := .Serializers -}} 25 {{ $mutators := .Mutators -}} 26 {{ $PublicStructName := .ARPkgTitle -}} 27 {{ $LinkedObject := .LinkedObject }} 28 {{ $flags := .Flags }} 29 {{ $fields := .FieldList }} 30 {{ $procfields := .ProcOutFieldList }} 31 {{ $procInLen := len .ProcInFieldList }} 32 {{ $mutatorLen := len .Mutators }} 33 34 {{ if ne $mutatorLen 0 -}} 35 type Mutators struct { 36 {{- range $i, $mut := $mutators }} 37 {{$mut.Name}} octopus.MutatorField 38 field{{ $mut.Name }}Original {{$mut.Type}} 39 {{- end }} 40 } 41 {{ end -}} 42 43 {{ if $fields }} 44 type {{ $PublicStructName }} struct { 45 octopus.BaseField 46 {{- if ne $mutatorLen 0 }} 47 Mutators 48 {{- end -}} 49 {{- range $ind, $fstruct := .FieldList -}} 50 {{ $rtype := $fstruct.Format -}} 51 {{ $serlen := len $fstruct.Serializer -}} 52 {{ if ne $serlen 0 -}} 53 {{ $sname := index $fstruct.Serializer 0 -}} 54 {{ $serializer := index $serializers $sname -}} 55 {{ $rtype = $serializer.Type -}} 56 {{ end }} 57 field{{ $fstruct.Name }} {{ $rtype -}} 58 {{ end }} 59 } 60 61 type {{ $PublicStructName }}List []*{{ $PublicStructName }} 62 63 const ( 64 namespace uint32 = {{ .Container.ObjectName }} 65 cntFields uint32 = {{ len .FieldList }} 66 {{- range $fieldname, $flag := .Flags -}} 67 {{ range $i, $flagname := $flag.Flags }} 68 {{ $fieldname }}{{ $flagname }}Flag = 1 << {{ $i -}} 69 {{ end -}} 70 {{ end }} 71 ) 72 73 {{ if .Triggers.RepairTuple.Params.Defaults -}} 74 var defaultValue = [][]byte{ 75 {{- $notfirst := false -}} 76 {{ range $ind, $fstruct := .FieldList -}} 77 {{ $packerparam := packerParam $fstruct.Format -}} 78 {{ if $notfirst }},{{ end -}} 79 {{ $notfirst = true }} 80 {{ $packerparam.DefaultValue -}} 81 {{ end -}} 82 } 83 {{- end }} 84 {{end}} 85 86 {{ if $procfields }} 87 // proc struct 88 type {{ $PublicStructName }} struct { 89 params {{ $PublicStructName }}Params 90 {{- range $ind, $fstruct := .ProcOutFieldList }} 91 {{ $rtype := $fstruct.Format -}} 92 {{ $serlen := len $fstruct.Serializer -}} 93 {{ if ne $serlen 0 -}} 94 {{ $sname := index $fstruct.Serializer 0 -}} 95 {{ $serializer := index $serializers $sname -}} 96 {{ $rtype = $serializer.Type -}} 97 {{ end -}} 98 field{{- $fstruct.Name }} {{ $rtype -}} 99 {{ end }} 100 } 101 102 type {{ $PublicStructName }}List []*{{ $PublicStructName }} 103 104 const ( 105 procName string = "{{ .Container.ObjectName }}" 106 cntOutFields uint32 = {{ len .ProcOutFieldList }} 107 ) 108 109 {{- range $ind, $fstruct := .ProcOutFieldList -}} 110 {{ $rtype := $fstruct.Format -}} 111 {{ $sname := $fstruct.Serializer.Name -}} 112 {{ if ne $sname "" -}} 113 {{ $serializer := index $serializers $sname -}} 114 {{ $rtype = $serializer.Type -}} 115 {{ end }} 116 func (obj *{{ $PublicStructName }}) Get{{ $fstruct.Name }}() {{ $rtype }} { 117 return obj.field{{ $fstruct.Name }} 118 } 119 {{ end }} 120 121 type {{ $PublicStructName }}Params struct { 122 {{- range $ind, $fstruct := .ProcInFieldList -}} 123 {{ $rtype := $fstruct.Format -}} 124 {{ $serlen := len $fstruct.Serializer -}} 125 {{ if ne $serlen 0 -}} 126 {{ $sname := index $fstruct.Serializer 0 -}} 127 {{ $serializer := index $serializers $sname -}} 128 {{ $rtype = $serializer.Type -}} 129 {{ end }} 130 {{ $fstruct.Name }} {{ $rtype -}} 131 {{ end }} 132 } 133 134 func (obj *{{ $PublicStructName }}) GetParams() {{ $PublicStructName }}Params { 135 return obj.params 136 } 137 138 func (obj *{{ $PublicStructName }}) setParams(params {{ $PublicStructName }}Params) error { 139 obj.params = params 140 141 return nil 142 } 143 144 {{ if ne $procInLen 0 }} 145 func (obj *{{ $PublicStructName }}Params) arrayValues() ([]string, error) { 146 ret := []string{} 147 {{ range $ind, $fstruct := .ProcInFieldList -}} 148 {{ $sname := $fstruct.Serializer.Name -}} 149 {{ $bvar := $fstruct.Name -}} 150 {{ if ne $sname "" -}} 151 {{ $serializer := index $serializers $sname -}} 152 {{ $serparams := $fstruct.Serializer.Params -}} 153 pvar{{ $fstruct.Name }}, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}obj.{{ $bvar }}) 154 if err != nil { 155 return nil, fmt.Errorf("error marshal param field {{ $fstruct.Name }}: %w", err) 156 } 157 158 {{ if eq $fstruct.Format "[]string" }} 159 ret = append(ret, pvar{{ $fstruct.Name }}...) 160 {{ else }} 161 ret = append(ret, string(pvar{{ $fstruct.Name }})) 162 {{- end }} 163 {{- else -}} 164 ret = append(ret, string(obj.{{ $fstruct.Name }})) 165 {{- end }} 166 {{ end }} 167 return ret, nil 168 } 169 {{ end }} 170 171 func (obj {{ $PublicStructName }}Params) PK() string { 172 return fmt.Sprint({{ if ne $procInLen 0 }}obj.arrayValues(){{ end }}) 173 } 174 175 func Call(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}) (*{{ $PublicStructName }}, error) { 176 return call(ctx{{ if ne $procInLen 0 }}, params{{ end }}, activerecord.ReplicaOrMasterInstanceType) 177 } 178 179 func CallOnMaster(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}) (*{{ $PublicStructName }}, error) { 180 return call(ctx{{ if ne $procInLen 0 }}, params{{ end }}, activerecord.MasterInstanceType) 181 } 182 183 func call(ctx context.Context{{ if ne $procInLen 0 }}, params {{ $PublicStructName }}Params{{ end }}, instanceType activerecord.ShardInstanceType) (*{{ $PublicStructName }}, error) { 184 logger := activerecord.Logger() 185 ctx = logger.SetLoggerValueToContext(ctx, map[string]interface{}{"LuaProc": procName}) 186 metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") 187 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 188 189 metricTimer.Timing(ctx, "call_proc") 190 191 connection, err := octopus.Box(ctx, 0, instanceType, "arcfg", nil) 192 if err != nil { 193 metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) 194 logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) 195 196 return nil, err 197 } 198 199 var args []string 200 {{ if ne $procInLen 0 }} 201 args, err = params.arrayValues() 202 if err != nil { 203 metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) 204 return nil, fmt.Errorf("Error parse args of procedure %s: %w", procName, err) 205 } 206 {{ end }} 207 208 td, err := octopus.CallLua(ctx, connection, procName, args...) 209 if err != nil { 210 metricErrCnt.Inc(ctx, "call_proc", 1) 211 return nil, fmt.Errorf("call lua procedure %s: %w", procName, err) 212 } 213 214 if len(td) != 1 { 215 return nil, fmt.Errorf("invalid response len from lua call: %d. Only one tuple supported", len(td)) 216 } 217 218 ret, err := TupleToStruct(ctx, td[0]) 219 if err != nil { 220 metricErrCnt.Inc(ctx, "call_proc_preparebox", 1) 221 logger.Error(ctx, "Error in response: ", err) 222 223 return nil, err 224 } 225 226 metricTimer.Finish(ctx, "call_proc") 227 228 activerecord.Logger().CollectQueries(ctx, CallMockerLogger({{ if ne $procInLen 0 }}params, {{ end }}{{ $PublicStructName }}List([]*{{ $PublicStructName }}{ret}))) 229 230 return ret, nil 231 } 232 233 func TupleToStruct(ctx context.Context, tuple octopus.TupleData) (*{{ $PublicStructName }}, error) { 234 if tuple.Cnt < cntOutFields { 235 return nil, fmt.Errorf("not enought selected fields %d in response tuple: %d but expected %d fields", tuple.Cnt, tuple.Cnt, cntOutFields) 236 } 237 238 np := {{ $PublicStructName }}{} 239 240 {{ range $ind, $fstruct := .ProcOutFieldList -}} 241 val{{ $fstruct.Name }}, err := Unpack{{ $fstruct.Name -}}(bytes.NewReader(tuple.Data[{{$ind}}])) 242 if err != nil { 243 return nil, err 244 } 245 246 np.field{{ $fstruct.Name }} = val{{ $fstruct.Name }} 247 {{ end }} 248 249 return &np, nil 250 } 251 252 {{ range $ind, $fstruct := .ProcOutFieldList -}} 253 {{ $packerparam := packerParam $fstruct.Format -}} 254 {{ $rtype := $fstruct.Format -}} 255 {{ $sname := $fstruct.Serializer.Name -}} 256 {{ if ne $sname "" -}} 257 {{ $serializer := index $serializers $sname -}} 258 {{ $rtype = $serializer.Type -}} 259 {{ end -}} 260 func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) error { 261 obj.field{{ $fstruct.Name }} = {{ $fstruct.Name}} 262 263 return nil 264 } 265 266 func Unpack{{ $fstruct.Name }}(r *bytes.Reader) (ret {{ $rtype }}, errRet error) { 267 var {{ $fstruct.Name }} {{ if ne $packerparam.UnpackType "" }}{{ $packerparam.UnpackType }}{{ else }}{{ $fstruct.Format }}{{ end }} 268 {{ $isPointer := hasPrefix (printf "%s" $rtype) "*" }} 269 270 err := {{ $packerparam.UnpackFunc }}(r, &{{ $fstruct.Name }}, iproto.ModeDefault) 271 if err != nil { 272 errRet = fmt.Errorf("error unpack field {{ $fstruct.Name }} in tuple: '%w'", err) 273 return 274 } 275 276 bvar := {{ if ne $packerparam.UnpackConvFunc "" -}} 277 {{ $packerparam.UnpackConvFunc }}({{ $fstruct.Name }}) 278 {{ else -}} 279 {{ $fstruct.Name }} 280 {{ end -}} 281 282 {{ $underlyingType := trimPrefix (printf "%s" $rtype) "*"}} 283 {{ if ne $sname "" -}} 284 {{ $serializer := index $serializers $sname -}} 285 {{ $serparams := $fstruct.Serializer.Params }} 286 287 var svar {{$rtype}} 288 289 err = {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}bvar, &svar) 290 if err != nil { 291 errRet = fmt.Errorf("error unmarshal field {{ $fstruct.Name }}: %w", err) 292 return 293 } 294 295 {{ else -}} 296 svar := bvar 297 298 {{ end -}} 299 300 return svar, nil 301 } 302 303 func pack{{ $fstruct.Name }}(w []byte, {{ $fstruct.Name }} {{ $rtype }}) ([]byte, error) { 304 {{ $bvar := $packerparam.PackConvFunc $fstruct.Name -}} 305 {{ if ne $sname "" -}} 306 {{ $serializer := index $serializers $sname -}} 307 {{ $serparams := $fstruct.Serializer.Params -}} 308 pvar, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $bvar }}) 309 if err != nil { 310 return nil, fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err) 311 } 312 {{- else -}} 313 pvar := {{ $bvar }} 314 {{- end }} 315 316 return {{ $packerparam.PackFunc }}(w, pvar, iproto.ModeDefault), nil 317 } 318 {{ end }} 319 // end proc struct 320 321 {{end}} 322 323 {{ if eq .Server.Conf "" -}} 324 var boxOption, _ = octopus.NewOptions( 325 "{{ .Server.Host }}:{{ .Server.Port }}", 326 octopus.ModeMaster, 327 octopus.WithTimeout(time.Millisecond * {{ .Server.Timeout }}, time.Millisecond * {{ .Server.Timeout }}), 328 ) 329 330 var clusterInfo = activerecord.NewClusterInfo( 331 activerecord.WithShard([]activerecord.OptionInterface{boxOption}, []activerecord.OptionInterface{}), 332 ){{ end }} 333 334 func New(ctx context.Context) *{{ $PublicStructName }} { 335 newObj := {{ $PublicStructName }}{} 336 {{- if $fields }} 337 newObj.BaseField.UpdateOps = []octopus.Ops{} 338 newObj.BaseField.ExtraFields = [][]byte{} 339 newObj.BaseField.Objects = map[string][]octopus.ModelStruct{} 340 {{ end }} 341 {{- if ne $mutatorLen 0 -}} 342 {{- range $i, $mut := $mutators }} 343 newObj.{{$mut.Name}}.PartialFields = map[string]any{} 344 {{ if ne $mut.Update "" -}} 345 newObj.{{$mut.Name}}.OpFunc = map[octopus.OpCode]string{octopus.OpUpdate: "{{$mut.Update}}"} 346 {{ end }} 347 {{ if ne $mut.Replace "" -}} 348 newObj.{{$mut.Name}}.OpFunc = map[octopus.OpCode]string{octopus.OpInsert: "{{$mut.Replace}}"} 349 {{ end }} 350 {{- end }} 351 {{ end }} 352 return &newObj 353 } 354 355 {{- if .Triggers.RepairTuple }} 356 func repairTuple(ctx context.Context, tuple *octopus.TupleData) error { 357 {{- if .Triggers.RepairTuple.ImportName }} 358 logger := activerecord.Logger() 359 360 logger.Debug(ctx, "{{ $PublicStructName }}", "Repair trigger called") 361 362 err := {{ .Triggers.RepairTuple.ImportName }}.{{ .Triggers.RepairTuple.Func }}(tuple, cntFields) 363 if err != nil { 364 return fmt.Errorf("trigger can't repair tuple %w", err) 365 } 366 {{- else if .Triggers.RepairTuple.Params.Defaults }} 367 logger := activerecord.Logger() 368 369 logger.Warn(ctx, "{{ $PublicStructName }}", "Repair trigger set defaults") 370 for f := tuple.Cnt; f < cntFields; f++ { 371 tuple.Data = append(tuple.Data, defaultValue[f]) 372 } 373 tuple.Cnt = cntFields 374 {{- end }} 375 376 return nil 377 } 378 {{- end }} 379 380 {{ if $fields }} 381 func TupleToStruct(ctx context.Context, tuple octopus.TupleData) (*{{ $PublicStructName }}, error) { 382 np := New(ctx) 383 384 {{ range $ind, $fstruct := .FieldList -}} 385 val{{ $fstruct.Name }}, err := Unpack{{ $fstruct.Name -}}(bytes.NewReader(tuple.Data[{{$ind}}])) 386 if err != nil { 387 return nil, err 388 } 389 390 np.Set{{ $fstruct.Name }}(val{{ $fstruct.Name }}) 391 {{ end }} 392 393 np.BaseField.Exists = true 394 np.BaseField.UpdateOps = []octopus.Ops{} 395 {{if gt $mutatorLen 0}} 396 np.ClearMutatorUpdateOpts() 397 {{end}} 398 399 if tuple.Cnt > cntFields { 400 logger := activerecord.Logger() 401 402 logger.Warn(ctx, "{{ $PublicStructName }}", np.PrimaryString(), "Extra fields") 403 404 np.BaseField.ExtraFields = tuple.Data[cntFields:] 405 } 406 407 return np, nil 408 } 409 410 func NewFromBox(ctx context.Context, tuples []octopus.TupleData) ([]*{{ $PublicStructName }}, error) { 411 logger := activerecord.Logger() 412 413 logger.Debug(ctx, "{{ $PublicStructName }}", fmt.Sprintf("Cnt tuples %d", len(tuples))) 414 415 ret := make([]*{{ $PublicStructName }}, 0, len(tuples)) 416 417 for num, tuple := range tuples { 418 var repaired bool 419 {{- if .Triggers.RepairTuple }} 420 421 if tuple.Cnt != cntFields { 422 err := repairTuple(ctx, &tuple) 423 if err != nil { 424 logger.Error(ctx, "{{ $PublicStructName }}", fmt.Errorf("%d tuple in response has %d fields but expected: %d. Repair fault: %w", num, tuple.Cnt, cntFields, err)) 425 continue 426 } 427 428 repaired = true 429 } 430 {{- end }} 431 432 if tuple.Cnt < cntFields { 433 return nil, fmt.Errorf("not enought selected fields %d in response tuple: %d but expected %d fields", tuple.Cnt, num, cntFields) 434 } 435 436 np, err := TupleToStruct(ctx, tuple) 437 {{- if .Triggers.RepairTuple }} 438 if err != nil { 439 logger.Warn(ctx, "{{ $PublicStructName }}", fmt.Sprintf("error unpack tuple %s. Try to repair", err)) 440 441 err = repairTuple(ctx, &tuple) 442 if err != nil { 443 logger.Error(ctx, "{{ $PublicStructName }}", fmt.Sprintf("can't repair: %s", err)) 444 continue 445 } 446 447 repaired = true 448 449 np, err = TupleToStruct(ctx, tuple) 450 } 451 {{- end }} 452 if err != nil { 453 logger.Error(ctx, "{{ $PublicStructName }}", fmt.Sprintf("error unpack tuple %s", err)) 454 return nil, err 455 } 456 457 np.BaseField.Repaired = repaired 458 ret = append(ret, np) 459 } 460 461 return ret, nil 462 } 463 {{ end -}} 464 465 {{ range $ind, $fstruct := .FieldList -}} 466 {{ $packerparam := packerParam $fstruct.Format -}} 467 {{ $rtype := $fstruct.Format -}} 468 {{ $sname := $fstruct.Serializer.Name -}} 469 {{ if ne $sname "" -}} 470 {{ $serializer := index $serializers $sname -}} 471 {{ $rtype = $serializer.Type -}} 472 func Marshal{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) (any, error) { 473 {{ $serparams := $fstruct.Serializer.Params -}} 474 {{ $bvar := $packerparam.PackConvFunc $fstruct.Name -}} 475 pvar, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $bvar }}) 476 if err != nil { 477 return nil, fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err) 478 } 479 480 return pvar, nil 481 } 482 483 {{ end -}} 484 func pack{{ $fstruct.Name }}(w []byte, {{ $fstruct.Name }} {{ $rtype }}) ([]byte, error) { 485 {{ $bvar := $packerparam.PackConvFunc $fstruct.Name -}} 486 {{ if ne $sname "" -}} 487 {{ $serializer := index $serializers $sname -}} 488 {{ $serparams := $fstruct.Serializer.Params -}} 489 pvar, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $bvar }}) 490 if err != nil { 491 return nil, fmt.Errorf("error marshal field {{ $fstruct.Name }}: %w", err) 492 } 493 {{- else -}} 494 pvar := {{ $bvar }} 495 {{- end }} 496 497 return {{ $packerparam.PackFunc }}(w, pvar, iproto.ModeDefault), nil 498 } 499 500 func Unpack{{ $fstruct.Name }}(r *bytes.Reader) (ret {{ $rtype }}, errRet error) { 501 var {{ $fstruct.Name }} {{ if ne $packerparam.UnpackType "" }}{{ $packerparam.UnpackType }}{{ else }}{{ $fstruct.Format }}{{ end }} 502 {{ $isPointer := hasPrefix (printf "%s" $rtype) "*" }} 503 504 err := {{ $packerparam.UnpackFunc }}(r, &{{ $fstruct.Name }}, iproto.ModeDefault) 505 if err != nil { 506 errRet = fmt.Errorf("error unpack field {{ $fstruct.Name }} in tuple: '%w'", err) 507 return 508 } 509 510 bvar := {{ if ne $packerparam.UnpackConvFunc "" -}} 511 {{ $packerparam.UnpackConvFunc }}({{ $fstruct.Name }}) 512 {{ else -}} 513 {{ $fstruct.Name }} 514 {{ end -}} 515 516 {{ $underlyingType := trimPrefix (printf "%s" $rtype) "*"}} 517 {{ if ne $sname "" -}} 518 {{ $serializer := index $serializers $sname -}} 519 {{ $serparams := $fstruct.Serializer.Params }} 520 521 var svar {{ $rtype }} 522 523 err = {{ $serializer.ImportName }}.{{ $serializer.Unmarshaler }}({{ $serparams }}bvar, &svar) 524 if err != nil { 525 errRet = fmt.Errorf("error unmarshal field {{ $fstruct.Name }}: %w", err) 526 return 527 } 528 529 {{ else -}} 530 svar := bvar 531 532 {{ end -}} 533 534 return svar, nil 535 } 536 537 func (obj *{{ $PublicStructName }}) Get{{ $fstruct.Name }}() {{ $rtype }} { 538 return obj.field{{ $fstruct.Name }} 539 } 540 541 func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}({{ $fstruct.Name }} {{ $rtype }}) error { 542 {{- if $fstruct.PrimaryKey }} 543 if obj.BaseField.Exists { 544 return fmt.Errorf("can't modify field included in primary key") 545 } 546 547 {{ end -}} 548 data, err := pack{{ $fstruct.Name }}([]byte{}, {{ $fstruct.Name }}) 549 if err != nil { 550 return err 551 } 552 553 {{- if eq $fstruct.Format "string" "[]byte" -}} 554 {{- if gt $fstruct.Size 0 }} 555 556 if len(data) > {{ $fstruct.Size }} { 557 return fmt.Errorf("max length of field '{{ $PublicStructName }}.{{ $fstruct.Name }}' is '%d' (received '%d')", {{ $fstruct.Size }}, len(data)) 558 } 559 {{- else }} 560 561 logger := activerecord.Logger() 562 563 logger.Warn(context.TODO(), "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Size for field '{{ $fstruct.Name }}' not set. Cur field size: %d. Object: '{{ $PublicStructName }}'", len(data))) 564 {{- end }} 565 {{- end }} 566 567 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpSet, Value: data}) 568 569 {{- range $i, $mut := $fstruct.Mutators -}} 570 {{ $customMutator := index $mutators $mut -}} 571 {{ $pfLen := len $customMutator.PartialFields }} 572 {{ if and (eq $pfLen 0) (ne $customMutator.Update "") }} 573 obj.BaseField.UpdateOps = []octopus.Ops{} 574 data = octopus.PackLua("{{$customMutator.Update}}", obj.PrimaryString(), {{ $fstruct.Name}}) 575 obj.{{ $customMutator.Name }}.UpdateOps = append(obj.{{ $customMutator.Name }}.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpUpdate, Value: data}) 576 {{ else if ne $pfLen 0 }} 577 {{ $isPointer := hasPrefix (printf "%s" $rtype) "*" }} 578 {{ if $isPointer }} 579 if {{ $fstruct.Name }} != nil { 580 {{- range $i, $pf := $customMutator.PartialFields }} 581 if obj.Set{{ $customMutator.Name }}{{ $pf.Name }}({{ $fstruct.Name }}.{{$pf.Name}}); err != nil { 582 return err 583 } 584 {{ end -}} 585 } 586 {{ else }} 587 {{- range $i, $pf := $customMutator.PartialFields }} 588 if obj.Set{{ $customMutator.Name }}{{ $pf.Name }}({{ $fstruct.Name }}.{{$pf.Name}}); err != nil { 589 return err 590 } 591 {{ end }} 592 {{ end }} 593 obj.field{{ $customMutator.Name }}Original = obj.field{{ $fstruct.Name }} 594 {{ end }} 595 {{ end }} 596 obj.field{{ $fstruct.Name }} = {{ $fstruct.Name}} 597 598 {{- if ne $fstruct.ObjectLink "" }} 599 delete(obj.BaseField.Objects, "{{ $fstruct.ObjectLink }}") 600 {{- end }} 601 602 return nil 603 } 604 {{ range $i, $mut := $fstruct.Mutators -}} 605 {{ $customMutator := index $mutators $mut -}} 606 {{ $pfLen := len $customMutator.PartialFields }} 607 {{- if $customMutator.Name }} 608 609 {{ if ne $pfLen 0 }} 610 func (obj *{{ $PublicStructName }}) pack{{ $fstruct.Name }}PartialFields(op octopus.OpCode) error { 611 pfs := obj.Mutators.{{ $customMutator.Name }}.PartialFields 612 if len(pfs) == 0 { 613 return nil 614 } 615 616 var ( 617 mutatorArgs []string 618 err error 619 ) 620 621 switch op { 622 {{ if ne $customMutator.Update "" -}} 623 case octopus.OpUpdate: 624 mutatorArgs, err = {{ $customMutator.ImportName }}.{{ $PublicStructName }}{{ $customMutator.Name }}Update(obj.field{{ $customMutator.Name }}Original, pfs) 625 {{ end }} 626 {{ if ne $customMutator.Replace "" -}} 627 case octopus.OpInsert: 628 mutatorArgs, err = {{ $customMutator.ImportName }}.{{ $PublicStructName }}{{ $customMutator.Name }}Replace(obj.field{{ $customMutator.Name }}Original, pfs) 629 {{ end }} 630 } 631 632 if err != nil { 633 return err 634 } 635 636 data := octopus.PackLua(obj.Mutators.{{ $customMutator.Name }}.OpFunc[op], append([]string{obj.PrimaryString()}, mutatorArgs...)...) 637 638 {{- if eq $fstruct.Format "string" "[]byte" -}} 639 {{- if gt $fstruct.Size 0 }} 640 641 if len(data) > {{ $fstruct.Size }} { 642 return fmt.Errorf("max length of field '{{ $PublicStructName }}.{{ $fstruct.Name }}' is '%d' (received '%d')", {{ $fstruct.Size }}, len(data)) 643 } 644 {{- else }} 645 646 logger := activerecord.Logger() 647 648 logger.Warn(context.TODO(), "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Size for field '{{ $fstruct.Name }}' not set. Cur field size: %d. Object: '{{ $PublicStructName }}'", len(data))) 649 {{- end }} 650 {{- end }} 651 652 obj.{{ $customMutator.Name }}.UpdateOps = []octopus.Ops{} 653 654 obj.{{ $customMutator.Name }}.UpdateOps = append(obj.{{ $customMutator.Name }}.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpUpdate, Value: data}) 655 656 return nil 657 } 658 {{ end }} 659 660 {{ range $i, $f := $customMutator.PartialFields }} 661 662 func (obj *{{ $PublicStructName }}) Set{{ $customMutator.Name }}{{ $f.Name }}({{ $f.Name }} {{ $f.Type }}) error { 663 obj.Mutators.{{ $customMutator.Name }}.PartialFields["{{ $f.Name }}"] = {{ $f.Name }} 664 665 if err := obj.pack{{ $fstruct.Name }}PartialFields(octopus.OpUpdate); err != nil { 666 return fmt.Errorf("pack {{ $customMutator.Name }}{{ $f.Name }}: %w", err) 667 } 668 669 return nil 670 } 671 {{ end }} 672 {{else}} 673 {{ $mutatorparam := mutatorParam $mut $fstruct.Format -}} 674 {{ $mtype := $fstruct.Format }} 675 676 func (obj *{{ $PublicStructName }}) {{ $mutatorparam.Name }}{{ $fstruct.Name }}(mutArg {{ $mtype }}) error { 677 {{- if eq $mutatorparam.Name "Inc" }} 678 if mutArg == 0 { 679 return nil 680 } 681 682 if uint64({{ $packerparam.MaxValue }} - obj.field{{ $fstruct.Name }}) < uint64(mutArg) { 683 return fmt.Errorf("overflow type '{{ $fstruct.Format }}' after Inc %d", mutArg) 684 } 685 686 data := iproto.PackUint32([]byte{}, uint32(mutArg), iproto.ModeDefault) 687 688 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpAdd, Value: data}) 689 obj.field{{ $fstruct.Name }} += {{ $packerparam.MutatorTypeConv }}(mutArg) 690 {{- else if eq $mutatorparam.Name "Dec" }} 691 if mutArg == 0 { 692 return nil 693 } 694 695 if uint64(obj.field{{ $fstruct.Name }} - {{ $packerparam.MinValue }}) < uint64(mutArg) { 696 return fmt.Errorf("overflow type '{{ $fstruct.Format }}' after Dec %d", mutArg) 697 } 698 699 data := iproto.PackUint32([]byte{}, uint32(-mutArg), iproto.ModeDefault) 700 701 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpAdd, Value: data}) 702 obj.field{{ $fstruct.Name }} -= {{ $packerparam.MutatorTypeConv }}(mutArg) 703 {{- else if eq $mutatorparam.Name "And" }} 704 if obj.field{{ $fstruct.Name }} == 0 || obj.field{{ $fstruct.Name }} & mutArg == obj.field{{ $fstruct.Name }} { 705 return nil 706 } 707 708 data := iproto.PackUint32([]byte{}, uint32(mutArg), iproto.ModeDefault) 709 710 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpAnd, Value: data}) 711 obj.field{{ $fstruct.Name }} &= mutArg 712 {{- else if eq $mutatorparam.Name "Or" "SetBit" }} 713 if mutArg == 0 || obj.field{{ $fstruct.Name }} | mutArg == obj.field{{ $fstruct.Name }} { 714 return nil 715 } 716 717 data := iproto.PackUint32([]byte{}, uint32(mutArg), iproto.ModeDefault) 718 719 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpOr, Value: data}) 720 obj.field{{ $fstruct.Name }} |= mutArg 721 {{- else if eq $mutatorparam.Name "ClearBit" }} 722 if mutArg == 0 || obj.field{{ $fstruct.Name }} & ^mutArg == obj.field{{ $fstruct.Name }} { 723 return nil 724 } 725 726 data := iproto.PackUint32([]byte{}, uint32(^mutArg), iproto.ModeDefault) 727 728 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpAnd, Value: data}) 729 obj.field{{ $fstruct.Name }} &= ^mutArg 730 {{- else if eq $mutatorparam.Name "Xor" }} 731 if mutArg == 0 || obj.field{{ $fstruct.Name }} ^ mutArg == obj.field{{ $fstruct.Name }} { 732 return nil 733 } 734 735 data := iproto.PackUint32([]byte{}, uint32(mutArg), iproto.ModeDefault) 736 737 obj.BaseField.UpdateOps = append(obj.BaseField.UpdateOps, octopus.Ops{Field: {{ $ind }}, Op: octopus.OpXor, Value: data}) 738 obj.field{{ $fstruct.Name }} ^= mutArg 739 {{- else }} 740 Unknown mutator type in template!!! 741 {{- end }} 742 743 return nil 744 } 745 {{- end }} 746 {{- end }} 747 {{- $fl := index $flags $fstruct.Name }} 748 {{- if $fl }} 749 {{- range $i, $flag := $fl.Flags }} 750 751 func (obj *{{ $PublicStructName }}) Set{{ $fstruct.Name }}{{ $flag }}() error { 752 return obj.SetBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag ) 753 } 754 755 func (obj *{{ $PublicStructName }}) Clear{{ $fstruct.Name }}{{ $flag }}() error { 756 return obj.ClearBit{{ $fstruct.Name }}( {{ $fstruct.Name }}{{ $flag }}Flag ) 757 } 758 759 func (obj *{{ $PublicStructName }}) Is{{ $fstruct.Name }}{{ $flag }}() bool { 760 return obj.Get{{ $fstruct.Name }}() & {{ $fstruct.Name }}{{ $flag }}Flag == {{ $fstruct.Name }}{{ $flag }}Flag 761 } 762 {{- end }} 763 {{- end }} 764 765 {{ end -}} 766 767 {{ if $fields }} 768 func selectBox (ctx context.Context, indexnum uint32, keysPacked [][][]byte, limiter activerecord.SelectorLimiter) ([]*{{ $PublicStructName }}, error) { 769 logger := activerecord.Logger() 770 ctx = logger.SetLoggerValueToContext(ctx, activerecord.ValueLogPrefix{"limiter": limiter.String()}) 771 metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") 772 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 773 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 774 775 w := octopus.PackSelect(namespace, indexnum, limiter.Offset(), limiter.Limit(), keysPacked) 776 777 metricTimer.Timing(ctx, "select_pack") 778 metricStatCnt.Inc(ctx, "select_keys", float64(len(keysPacked))) 779 780 logger.Debug(ctx, fmt.Sprintf("Select packed tuple: '% X'", w)) 781 782 connection, err := octopus.Box(ctx, 0, activerecord.ReplicaOrMasterInstanceType, "arcfg", nil) 783 if err != nil { 784 metricErrCnt.Inc(ctx, "select_preparebox", 1) 785 logger.Error(ctx, fmt.Sprintf("Error get box '%s'", err)) 786 787 return nil, err 788 } 789 790 respBytes, errCall := connection.Call(ctx, octopus.RequestTypeSelect, w) 791 if errCall != nil { 792 metricErrCnt.Inc(ctx, "select_box", 1) 793 logger.Error(ctx, "Error select from box", errCall, connection.Info()) 794 795 return nil, errCall 796 } 797 798 metricTimer.Timing(ctx, "select_box") 799 800 logger.Debug(ctx, fmt.Sprintf("Response from box '%X'", respBytes)) 801 802 tuplesData, err := octopus.ProcessResp(respBytes, 0) 803 if err != nil { 804 metricErrCnt.Inc(ctx, "select_resp", 1) 805 logger.Error(ctx, "Error parse response: ", err) 806 807 return nil, err 808 } 809 810 metricTimer.Timing(ctx, "select_process") 811 metricStatCnt.Inc(ctx, "select_tuples_res", float64(len(tuplesData))) 812 813 nps, err := NewFromBox(ctx, tuplesData) 814 if err != nil { 815 metricErrCnt.Inc(ctx, "select_preparebox", 1) 816 logger.Error(ctx, "Error in response: ", err) 817 818 return nil, err 819 } 820 821 metricTimer.Timing(ctx, "select_newobj") 822 823 if limiter.FullfillWarn() && len(nps) == int(limiter.Limit()) { 824 logger.Warn(ctx, "Select limit reached. Result may less than db records.") 825 } 826 827 mode, ok := connection.InstanceMode().(activerecord.ServerModeType) 828 if !ok || mode == activerecord.ModeReplica { 829 if !ok { 830 logger.Error(ctx, "Invalid server mode type: %T", connection.InstanceMode()) 831 } 832 833 for npNum := range nps { 834 nps[npNum].IsReplica = true 835 nps[npNum].Readonly = true 836 } 837 } 838 839 logger.Debug(ctx, "Success select") 840 841 metricTimer.Finish(ctx, "select") 842 843 return nps, nil 844 } 845 {{ end }} 846 847 {{ if $fields }} // indexes 848 {{ $pktype := "" }} 849 {{ $pklenfld := 1 }} 850 {{ $pkind := index .Indexes 0 }} 851 {{ range $num, $ind := .Indexes -}} 852 {{ $lenfld := len $ind.Fields -}} 853 {{ if $ind.Primary }} 854 {{ $pktype = $ind.Type }} 855 {{ $pklenfld = len $ind.Fields }} 856 {{ $pkind = $ind }} 857 func (obj *{{ $PublicStructName }}) Primary() {{ $ind.Type }} { 858 {{ if ne $lenfld 1 }} 859 return {{ $ind.Type }}{ 860 {{- range $_, $fieldNum := $ind.Fields }} 861 {{- $ifield := index $fields $fieldNum }} 862 {{ $ifield.Name }}: obj.Get{{ $ifield.Name }}(), 863 {{- end }} 864 } 865 {{ else }} 866 {{- range $_, $fieldNum := $ind.Fields }} 867 {{- $ifield := index $fields $fieldNum }} 868 return obj.Get{{ $ifield.Name }}() 869 {{- end }} 870 {{ end -}} 871 } 872 873 func SelectByPrimary(ctx context.Context, pk {{ $ind.Type }}) (*{{ $PublicStructName }}, error) { 874 return {{ $ind.Selector }}(ctx, pk) 875 } 876 {{ end }} 877 {{ end }} 878 879 {{ range $num, $ind := .Indexes -}} 880 {{ $lenfld := len $ind.Fields -}} 881 {{ if ne $lenfld 1 }} 882 type {{ $ind.Type }} struct { 883 {{- range $_, $fieldNum := $ind.Fields }} 884 {{- $ifield := index $fields $fieldNum }} 885 {{ $rtype := $ifield.Format -}} 886 {{ $serlen := len $ifield.Serializer -}} 887 {{ if ne $serlen 0 -}} 888 {{ $sname := index $ifield.Serializer 0 -}} 889 {{ $serializer := index $serializers $sname -}} 890 {{ $rtype = $serializer.Type -}} 891 {{ end }} 892 {{ $ifield.Name }} {{ $rtype -}} 893 {{- end }} 894 } 895 {{ end -}} 896 897 func PackKeyIndex{{ $ind.Name }}(ctx context.Context, keys []{{ $ind.Type }}) ([][][]byte, error) { 898 keysPacked := [][][]byte{} 899 900 for _, key := range keys { 901 keysField := [][]byte{} 902 {{ if ne $lenfld 1 -}} 903 {{ range $numf, $ifld := $ind.Fields -}} 904 {{ $sfield := index $fields $ifld -}} 905 {{ $packerparam := packerParam $sfield.Format -}} 906 {{ $packparam := printf "key.%s" $sfield.Name -}} 907 {{ $serlen := len $sfield.Serializer }} 908 {{ if ne $serlen 0 }} 909 {{ $sname := index $sfield.Serializer 0 -}} 910 {{ $serializer := index $serializers $sname -}} 911 {{ $serparams := $sfield.Serializer.Params -}} 912 skey, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $packparam }}) 913 if err != nil { 914 return nil, err 915 } 916 {{ $packparam = "skey" }} 917 {{ end }} 918 919 keysField = append(keysField, {{ $packerparam.PackFunc }}([]byte{}, {{ $packerparam.PackConvFunc $packparam }}, iproto.ModeDefault)) 920 {{ end -}} 921 {{ else -}} 922 {{ $ifield := index $ind.Fields 0 -}} 923 {{ $sfield := index $fields $ifield -}} 924 {{ $packerparam := packerParam $sfield.Format -}} 925 keysField = append(keysField, {{ $packerparam.PackFunc }}([]byte{}, {{ $packerparam.PackConvFunc "key" }}, iproto.ModeDefault)) 926 {{ end -}} 927 keysPacked = append(keysPacked, keysField) 928 } 929 930 return keysPacked, nil 931 } 932 func UnpackKeyIndex{{ $ind.Name }}(packedKeys [][][]byte) ([]{{ $ind.Type }}, error) { 933 ret := []{{ $ind.Type }}{} 934 935 for _, packedKey := range packedKeys { 936 {{ if ne $lenfld 1 }} 937 newIField := {{ $ind.Type }}{} 938 939 var err error 940 941 {{- range $num, $fieldNum := $ind.Fields }} 942 {{- $ifield := index $fields $fieldNum }} 943 newIField.{{ $ifield.Name }}, err = Unpack{{ $ifield.Name }}(bytes.NewReader(packedKey[{{$num}}])) 944 if err != nil { 945 return nil, fmt.Errorf("can't unpack index: %s", err) 946 } 947 {{ end }} 948 {{ else }} 949 {{- $fieldNum := index $ind.Fields 0 }} 950 {{- $ifield := index $fields $fieldNum }} 951 newIField, err := Unpack{{ $ifield.Name }}(bytes.NewReader(packedKey[0])) 952 if err != nil { 953 return nil, fmt.Errorf("can't unpack index: %s", err) 954 } 955 {{ end }} 956 ret = append(ret, newIField) 957 } 958 959 return ret, nil 960 } 961 /* 962 963 keysPacked := [][][]byte{} 964 965 for _, key := range keys { 966 keysField := [][]byte{} 967 {{ if ne $lenfld 1 -}} 968 {{ range $numf, $ifld := $ind.Fields -}} 969 {{ $sfield := index $fields $ifld -}} 970 {{ $packerparam := packerParam $sfield.Format -}} 971 {{ $packparam := printf "key.%s" $sfield.Name -}} 972 {{ $serlen := len $sfield.Serializer }} 973 {{ if ne $serlen 0 }} 974 {{ $sname := index $sfield.Serializer 0 -}} 975 {{ $serializer := index $serializers $sname -}} 976 {{ $serparams := $sfield.Serializer.Params -}} 977 skey, err := {{ $serializer.ImportName }}.{{ $serializer.Marshaler }}({{ $serparams }}{{ $packparam }}) 978 if err != nil { 979 return nil, err 980 } 981 {{ $packparam = "skey" }} 982 {{ end }} 983 984 keysField = append(keysField, {{ $packerparam.PackFunc }}([]byte{}, {{ $packerparam.PackConvFunc $packparam }}, iproto.ModeDefault)) 985 {{ end -}} 986 {{ else -}} 987 {{ $ifield := index $ind.Fields 0 -}} 988 {{ $sfield := index $fields $ifield -}} 989 {{ $packerparam := packerParam $sfield.Format -}} 990 keysField = append(keysField, {{ $packerparam.PackFunc }}([]byte{}, {{ $packerparam.PackConvFunc "key" }}, iproto.ModeDefault)) 991 {{ end -}} 992 keysPacked = append(keysPacked, keysField) 993 } 994 995 return keysPacked, nil 996 } 997 */ 998 func {{ $ind.Selector }}s(ctx context.Context, keys []{{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ([]*{{ $PublicStructName }}, error) { 999 ctx = activerecord.Logger().SetLoggerValueToContext(ctx, map[string]interface{}{"{{ $ind.Selector }}s": keys, "Repo": "{{ $PublicStructName }}" }) 1000 1001 keysPacked, err := PackKeyIndex{{ $ind.Name }}(ctx, keys) 1002 if err != nil { 1003 return nil, fmt.Errorf("can't pack index key: %s", err) 1004 } 1005 1006 {{ if $ind.Unique -}} 1007 limiter := activerecord.EmptyLimiter() 1008 {{ end }} 1009 1010 res, err := selectBox(ctx, {{ $ind.Num }}, keysPacked, limiter) 1011 if err != nil { 1012 return res, err 1013 } 1014 1015 activerecord.Logger().CollectQueries(ctx, {{ $ind.Selector }}MockerLogger(keys, {{ $PublicStructName }}List(res){{ if not $ind.Unique }}, limiter {{ end }})) 1016 1017 return res, err 1018 } 1019 1020 func {{ $ind.Selector }}(ctx context.Context, key {{ $ind.Type }}{{ if not $ind.Unique }}, limiter activerecord.SelectorLimiter{{ end }}) ({{ if $ind.Unique }}{{ else }}[]{{ end }}*{{ $PublicStructName }}, error) { 1021 selected, err := {{ $ind.Selector }}s(ctx, []{{ $ind.Type }}{key}{{ if not $ind.Unique }}, limiter{{ end }}) 1022 if err != nil { 1023 return nil, err 1024 } 1025 1026 {{ if $ind.Unique -}} 1027 if len(selected) > 0 { 1028 if len(selected) > 1 { 1029 activerecord.Logger().Error(ctx, "{{ $PublicStructName }}", "More than one tuple for uniq key ID '%s': %d", key, len(selected)) 1030 } 1031 1032 return selected[0], nil 1033 } 1034 1035 return nil, nil 1036 {{- else }} 1037 1038 return selected, nil 1039 {{- end }} 1040 } 1041 {{ end }} 1042 {{ end }}// end indexes 1043 {{ range $name, $fobj := .FieldObject -}} 1044 {{ $linkedobj := index $LinkedObject $fobj.ObjectName }} 1045 func (obj *{{ $PublicStructName }}) Get{{ $name }}(ctx context.Context) ({{ if not $fobj.Unique }}[]{{ end }}*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}, error){ 1046 {{- if $fobj.Unique }} 1047 if ret, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(ret) == 1 { 1048 return ret[0].(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}), nil 1049 } 1050 1051 ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}()) 1052 if err != nil { 1053 return nil, err 1054 } 1055 1056 obj.BaseField.Objects["{{ $name }}"] = []octopus.ModelStruct{ret} 1057 {{- else }} 1058 1059 var ret []*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }} 1060 1061 if retI, ok := obj.BaseField.Objects["{{ $name }}"]; ok && len(retI) > 0 { 1062 for _, ri := range retI { 1063 ret = append(ret, ri.(*{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }})) 1064 } 1065 1066 return ret, nil 1067 } 1068 1069 ret, err := {{ $linkedobj.Namespace.PackageName }}.SelectBy{{ $fobj.Key }}(ctx, obj.Get{{ $fobj.Field }}(), activerecord.NewLimiter(100)) //ToDo default limit for multi object 1070 if err != nil { 1071 return nil, err 1072 } 1073 1074 if len(ret) == 100 { 1075 activerecord.Logger().Warn(ctx, "limit for multiple linked object riched '{{ $linkedobj.Namespace.PackageName }}.{{ $linkedobj.Namespace.PublicName }}' '{{ $PublicStructName }}'") 1076 } 1077 1078 for _, r := range ret { 1079 obj.BaseField.Objects["{{ $name }}"] = append(obj.BaseField.Objects["{{ $name }}"], r) 1080 } 1081 {{- end }} 1082 1083 return ret, nil 1084 } 1085 1086 {{ end -}} 1087 1088 {{ if $fields }} 1089 func (obj *{{ $PublicStructName }}) Equal (anotherObjI any) bool { 1090 anotherObj, ok := anotherObjI.(*{{ $PublicStructName }}) 1091 if !ok { 1092 return false 1093 } 1094 1095 var dataObj []byte 1096 var dataAnotherObj []byte 1097 var err error 1098 1099 {{- range $ind, $fstruct := .FieldList }} 1100 dataObj, err = pack{{ $fstruct.Name }}([]byte{}, obj.Get{{ $fstruct.Name }}()) 1101 if err != nil { 1102 return false 1103 } 1104 1105 dataAnotherObj, err = pack{{ $fstruct.Name }}([]byte{}, anotherObj.Get{{ $fstruct.Name }}()) 1106 if err != nil { 1107 return false 1108 } 1109 1110 if string(dataObj) != string(dataAnotherObj) { 1111 return false 1112 } 1113 {{ end }} 1114 1115 return true 1116 } 1117 1118 func (obj *{{ $PublicStructName }}) PrimaryString() string { 1119 ret := []string{ 1120 {{- range $ind, $fstruct := .FieldList }} 1121 {{- if $fstruct.PrimaryKey }} 1122 {{- $packerparam := packerParam $fstruct.Format }} 1123 {{- $tostr := $packerparam.ToString }} 1124 {{ index $tostr 0 }}obj.Get{{ $fstruct.Name }}(){{ index $tostr 1 }}, 1125 {{- end }} 1126 {{- end }} 1127 } 1128 1129 return strings.Join(ret, ", ") 1130 } 1131 1132 {{ $pktype := "" }} 1133 {{ $pklenfld := 1 }} 1134 {{ $pkind := index .Indexes 0 }} 1135 {{ range $num, $ind := .Indexes -}} 1136 {{ $lenfld := len $ind.Fields -}} 1137 {{ if $ind.Primary }} 1138 {{ $pktype = $ind.Type }} 1139 {{ $pklenfld = len $ind.Fields }} 1140 {{ $pkind = $ind }} 1141 func (obj *{{ $PublicStructName }}) packPk() ([][]byte, error) { 1142 packedPk := [][]byte{} 1143 1144 var ( 1145 data []byte 1146 err error 1147 ) 1148 {{ if ne $lenfld 1 }} 1149 {{- range $_, $fieldNum := $ind.Fields }} 1150 {{- $ifield := index $fields $fieldNum }} 1151 1152 data, err = pack{{ $ifield.Name }}([]byte{}, obj.Get{{ $ifield.Name }}()) 1153 if err != nil { 1154 return [][]byte{}, err 1155 } 1156 1157 packedPk = append(packedPk, data) 1158 {{- end }} 1159 {{ else }} 1160 {{- range $_, $fieldNum := $ind.Fields }} 1161 {{- $ifield := index $fields $fieldNum }} 1162 1163 data, err = pack{{ $ifield.Name }}([]byte{}, obj.Get{{ $ifield.Name }}()) 1164 if err != nil { 1165 return [][]byte{}, err 1166 } 1167 1168 packedPk = append(packedPk, data) 1169 {{- end }} 1170 {{ end }} 1171 1172 return packedPk, nil 1173 } 1174 {{ end }} 1175 {{ end }} 1176 1177 func (obj *{{ $PublicStructName }}) Delete(ctx context.Context) error { 1178 logger := activerecord.Logger() 1179 metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") 1180 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 1181 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 1182 1183 metricStatCnt.Inc(ctx, "delete_request", 1) 1184 1185 if !obj.BaseField.Exists { 1186 return fmt.Errorf("can't delete not exists object") 1187 } 1188 1189 pk, err := obj.packPk() 1190 if err != nil { 1191 metricErrCnt.Inc(ctx, "delete_pack", 1) 1192 return fmt.Errorf("error delete: %w", err) 1193 } 1194 1195 w := octopus.PackDelete(namespace, pk) 1196 log.Printf("Delete packed tuple: '%X'\n", w) 1197 1198 connection, err := octopus.Box(ctx, 0, activerecord.MasterInstanceType, "arcfg", nil) 1199 if err != nil { 1200 metricErrCnt.Inc(ctx, "delete_preparebox", 1) 1201 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) 1202 1203 return err 1204 } 1205 1206 respBytes, errCall := connection.Call(ctx, octopus.RequestTypeDelete, w) 1207 if errCall != nil { 1208 metricErrCnt.Inc(ctx, "delete_box", 1) 1209 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error delete from box", errCall, connection.Info()) 1210 1211 return errCall 1212 } 1213 1214 metricTimer.Timing(ctx, "delete_box") 1215 1216 logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Response from box '% X'", respBytes)) 1217 1218 _, err = octopus.ProcessResp(respBytes, octopus.NeedRespFlag|octopus.UniqRespFlag) 1219 if err != nil { 1220 metricErrCnt.Inc(ctx, "delete_resp", 1) 1221 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error parse response: ", err) 1222 1223 return err 1224 } 1225 1226 metricStatCnt.Inc(ctx, "delete_success", 1) 1227 1228 obj.BaseField.Exists = false 1229 obj.BaseField.UpdateOps = []octopus.Ops{} 1230 1231 logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success delete") 1232 1233 metricTimer.Finish(ctx, "delete") 1234 1235 return nil 1236 } 1237 1238 func (obj *{{ $PublicStructName }}) Update(ctx context.Context) error { 1239 logger := activerecord.Logger() 1240 metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") 1241 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 1242 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 1243 1244 metricStatCnt.Inc(ctx, "update_request", 1) 1245 1246 if !obj.BaseField.Exists { 1247 metricErrCnt.Inc(ctx, "update_notexists", 1) 1248 return fmt.Errorf("can't update not exists object") 1249 } 1250 1251 if obj.BaseField.Repaired { 1252 metricStatCnt.Inc(ctx, "update_repaired", 1) 1253 logger.Debug(ctx, "", obj.PrimaryString(), "Flag 'Repaired' is true! Insert instead Update") 1254 1255 return obj.Replace(ctx) 1256 } 1257 1258 connection, err := octopus.Box(ctx, 0, activerecord.MasterInstanceType, "arcfg", nil) 1259 if err != nil { 1260 metricErrCnt.Inc(ctx, "update_preparebox", 1) 1261 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) 1262 return err 1263 } 1264 1265 {{if eq $mutatorLen 0}} 1266 if len(obj.BaseField.UpdateOps) == 0 { 1267 metricStatCnt.Inc(ctx, "update_empty", 1) 1268 logger.Debug(ctx, "", obj.PrimaryString(), "Empty update") 1269 1270 return nil 1271 } 1272 {{else}} 1273 if len(obj.BaseField.UpdateOps) > 0 { 1274 {{- end }} 1275 pk, err := obj.packPk() 1276 if err != nil { 1277 metricErrCnt.Inc(ctx, "update_packpk", 1) 1278 return fmt.Errorf("error update: %w", err) 1279 } 1280 1281 w := octopus.PackUpdate(namespace, pk, obj.BaseField.UpdateOps) 1282 1283 log.Printf("Update packed tuple: '%X'\n", w) 1284 1285 respBytes, errCall := connection.Call(ctx, octopus.RequestTypeUpdate, w) 1286 if errCall != nil { 1287 metricErrCnt.Inc(ctx, "update_box", 1) 1288 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error update ia a box", errCall, connection.Info()) 1289 return errCall 1290 } 1291 1292 metricTimer.Timing(ctx, "update_box") 1293 1294 logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Response from box '%X'", respBytes)) 1295 1296 _, err = octopus.ProcessResp(respBytes, octopus.NeedRespFlag|octopus.UniqRespFlag) 1297 if err != nil { 1298 metricErrCnt.Inc(ctx, "update_resp", 1) 1299 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error parse response: ", err) 1300 return err 1301 } 1302 1303 {{if gt $mutatorLen 0}} 1304 } 1305 {{end}} 1306 {{if gt $mutatorLen 0}} 1307 {{ range $ind, $fstruct := .FieldList -}} 1308 {{- range $i, $mut := $fstruct.Mutators -}} 1309 {{ $customMutator := index $mutators $mut -}} 1310 {{ $pfLen := len $customMutator.PartialFields }} 1311 {{ if and (ne $pfLen 0) (ne $customMutator.Update "") $customMutator.Name }} 1312 for _, op := range obj.{{$customMutator.Name}}.UpdateOps { 1313 resp, errCall := connection.Call(ctx, octopus.RequestTypeCall, op.Value) 1314 if errCall != nil { 1315 metricErrCnt.Inc(ctx, "call_proc", 1) 1316 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error call proc in a box", errCall, connection.Info()) 1317 return errCall 1318 } 1319 1320 _, err := octopus.ProcessResp(resp, 0) 1321 if err != nil { 1322 return fmt.Errorf("error unpack lua response: %w", err) 1323 } 1324 } 1325 1326 obj.{{$customMutator.Name}}.UpdateOps = []octopus.Ops{} 1327 obj.{{$customMutator.Name}}.PartialFields = map[string]any{} 1328 {{end}} 1329 {{end}} 1330 {{end}} 1331 {{end}} 1332 1333 obj.BaseField.UpdateOps = []octopus.Ops{} 1334 1335 logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success update") 1336 1337 metricStatCnt.Inc(ctx, "update_success", 1) 1338 metricTimer.Finish(ctx, "update") 1339 1340 return nil 1341 } 1342 1343 func (obj *{{ $PublicStructName }}) Insert(ctx context.Context) error { 1344 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 1345 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 1346 1347 metricStatCnt.Inc(ctx, "insert_request", 1) 1348 1349 if obj.BaseField.Exists { 1350 metricErrCnt.Inc(ctx, "insert_exists", 1) 1351 return fmt.Errorf("can't insert already exists object") 1352 } 1353 1354 err := obj.insertReplace(ctx, octopus.InsertModeInsert) 1355 1356 if err == nil { 1357 metricStatCnt.Inc(ctx, "insert_success", 1) 1358 } 1359 1360 return err 1361 } 1362 1363 func (obj *{{ $PublicStructName }}) Replace(ctx context.Context) error { 1364 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 1365 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 1366 1367 metricStatCnt.Inc(ctx, "replace_request", 1) 1368 1369 if !obj.BaseField.Exists { 1370 metricErrCnt.Inc(ctx, "replace_notexists", 1) 1371 return fmt.Errorf("can't replace not exists object") 1372 } 1373 1374 err := obj.insertReplace(ctx, octopus.InsertModeReplace) 1375 1376 if err == nil { 1377 metricStatCnt.Inc(ctx, "replace_success", 1) 1378 } 1379 1380 return err 1381 } 1382 1383 func (obj *{{ $PublicStructName }}) InsertOrReplace(ctx context.Context) error { 1384 metricStatCnt := activerecord.Metric().StatCount("octopus", "{{ $PublicStructName }}") 1385 1386 metricStatCnt.Inc(ctx, "insertorreplace_request", 1) 1387 1388 err := obj.insertReplace(ctx, octopus.InsertModeInserOrReplace) 1389 1390 if err == nil { 1391 metricStatCnt.Inc(ctx, "insertorreplace_success", 1) 1392 } 1393 1394 return err 1395 } 1396 1397 func (obj *{{ $PublicStructName }}) insertReplace(ctx context.Context, insertMode octopus.InsertMode) error { 1398 var ( 1399 err error 1400 tuple [][]byte 1401 data []byte 1402 ) 1403 1404 metricTimer := activerecord.Metric().Timer("octopus", "{{ $PublicStructName }}") 1405 metricErrCnt := activerecord.Metric().ErrorCount("octopus", "{{ $PublicStructName }}") 1406 1407 {{ range $ind, $fstruct := .FieldList }} 1408 1409 data, err = pack{{ $fstruct.Name }}([]byte{}, obj.Get{{ $fstruct.Name }}()) 1410 if err != nil { 1411 metricErrCnt.Inc(ctx, "insertreplace_packfield", 1) 1412 return err 1413 } 1414 1415 tuple = append(tuple, data) 1416 {{ end }} 1417 1418 metricTimer.Timing(ctx, "insertreplace_packtuple") 1419 1420 if len(obj.BaseField.ExtraFields) > 0 { 1421 tuple = append(tuple, obj.BaseField.ExtraFields...) 1422 } 1423 1424 w := octopus.PackInsertReplace(namespace, insertMode, tuple) 1425 logger := activerecord.Logger() 1426 1427 metricTimer.Timing(ctx, "insertreplace_pack") 1428 logger.Trace(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Insert packed tuple: '%X'", w)) 1429 1430 connection, err := octopus.Box(ctx, 0, activerecord.MasterInstanceType, "arcfg", nil) 1431 if err != nil { 1432 metricErrCnt.Inc(ctx, "insertreplace_preparebox", 1) 1433 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Error get box '%s'", err)) 1434 1435 return err 1436 } 1437 1438 respBytes, errCall := connection.Call(ctx, octopus.RequestTypeInsert, w) 1439 if errCall != nil { 1440 metricErrCnt.Inc(ctx, "insertreplace_box", 1) 1441 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error insert into box", errCall, connection.Info()) 1442 1443 return errCall 1444 } 1445 1446 metricTimer.Timing(ctx, "insertreplace_box") 1447 1448 logger.Trace(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), fmt.Sprintf("Response from box '%X'", respBytes)) 1449 1450 tuplesData, err := octopus.ProcessResp(respBytes, octopus.NeedRespFlag|octopus.UniqRespFlag) 1451 if err != nil { 1452 metricErrCnt.Inc(ctx, "insertreplace_prespreparebox", 1) 1453 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error parse response: ", err) 1454 1455 return err 1456 } 1457 1458 _, err = NewFromBox(ctx, tuplesData) 1459 if err != nil { 1460 metricErrCnt.Inc(ctx, "insertreplace_obj", 1) 1461 logger.Error(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Error in response: ", err) 1462 1463 return err 1464 } 1465 1466 obj.BaseField.Exists = true 1467 obj.BaseField.UpdateOps = []octopus.Ops{} 1468 {{- if gt $mutatorLen 0 }} 1469 obj.ClearMutatorUpdateOpts() 1470 {{- end }} 1471 obj.BaseField.Repaired = false 1472 1473 logger.Debug(ctx, "{{ $PublicStructName }}", obj.PrimaryString(), "Success insert") 1474 1475 metricTimer.Finish(ctx, "insertreplace") 1476 1477 return nil 1478 } 1479 {{ end }} 1480 {{if gt $mutatorLen 0}} 1481 func (obj *{{ $PublicStructName }}) ClearMutatorUpdateOpts() { 1482 {{- range $ind, $fstruct := .FieldList -}} 1483 {{- range $i, $mut := $fstruct.Mutators -}} 1484 {{ $customMutator := index $mutators $mut -}} 1485 {{ if and (ne $customMutator.Update "") $customMutator.Name -}} 1486 obj.{{$customMutator.Name}}.UpdateOps = []octopus.Ops{} 1487 obj.{{$customMutator.Name}}.PartialFields = map[string]any{} 1488 {{- end }} 1489 {{end}} 1490 {{- end -}} 1491 } 1492 {{end}}