github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/cmd/protoc-gen-gorony/repo/store/gen.go (about) 1 package store 2 3 import ( 4 "fmt" 5 "strings" 6 "text/template" 7 8 "github.com/jinzhu/inflection" 9 "github.com/ronaksoft/rony/internal/codegen" 10 "github.com/ronaksoft/rony/tools" 11 "google.golang.org/protobuf/compiler/protogen" 12 ) 13 14 /* 15 Creation Time: 2021 - Jul - 08 16 Created by: (ehsan) 17 Maintainers: 18 1. Ehsan N. Moosa (E2) 19 Auditor: Ehsan N. Moosa (E2) 20 Copyright Ronak Software Group 2020 21 */ 22 23 type Generator struct { 24 f *protogen.File 25 g *protogen.GeneratedFile 26 repoPrefix string 27 } 28 29 func New(f *protogen.File, g *protogen.GeneratedFile, repoPrefix string) *Generator { 30 return &Generator{ 31 f: f, 32 g: g, 33 repoPrefix: repoPrefix, 34 } 35 } 36 37 var helperFunctions = map[string]interface{}{ 38 "Singular": func(x string) string { 39 return inflection.Singular(x) 40 }, 41 "Plural": func(x string) string { 42 return inflection.Plural(x) 43 }, 44 "MVName": func(m codegen.ModelKey) string { 45 alias := m.Alias() 46 if alias == "" { 47 alias = m.Names(codegen.PropFilterALL, "", "", "", codegen.None) 48 } 49 sb := strings.Builder{} 50 sb.WriteString(m.Name()) 51 sb.WriteString(alias) 52 53 return sb.String() 54 }, 55 "MVAlias": func(m codegen.ModelKey, prefix string) string { 56 if m.Alias() != "" { 57 return m.Alias() 58 } 59 sb := strings.Builder{} 60 sb.WriteString(prefix) 61 sb.WriteString(m.Names(codegen.PropFilterALL, "", "", "", codegen.None)) 62 63 return sb.String() 64 }, 65 "HasIndex": func(m codegen.MessageArg) bool { 66 for _, f := range m.Fields { 67 if f.HasIndex { 68 return true 69 } 70 } 71 72 return false 73 }, 74 "FuncArgs": func(m codegen.ModelKey, prefix string) string { 75 nc := codegen.None 76 if prefix == "" { 77 nc = codegen.LowerCamelCase 78 } 79 80 return m.NameTypes(codegen.PropFilterALL, prefix, nc, codegen.LangGo) 81 }, 82 "FuncArgsPKs": func(m codegen.ModelKey, prefix string) string { 83 nc := codegen.None 84 if prefix == "" { 85 nc = codegen.LowerCamelCase 86 } 87 88 return m.NameTypes(codegen.PropFilterPKs, prefix, nc, codegen.LangGo) 89 }, 90 "FuncArgsCKs": func(m codegen.ModelKey, prefix string) string { 91 nc := codegen.None 92 if prefix == "" { 93 nc = codegen.LowerCamelCase 94 } 95 96 return m.NameTypes(codegen.PropFilterCKs, prefix, nc, codegen.LangGo) 97 }, 98 "SingletonDBKey": func(arg codegen.MessageArg) string { 99 return fmt.Sprintf("'S', C_%s", 100 arg.Name()) 101 }, 102 "DBKey": func(m codegen.ModelKey, prefix string) string { 103 nc := codegen.None 104 if prefix == "" { 105 nc = codegen.LowerCamelCase 106 } 107 108 return fmt.Sprintf("'M', C_%s, uint64(%d), %s", 109 m.Name(), 110 codegen.CrcHash(tools.StrToByte(m.Names(codegen.PropFilterALL, "", "", ",", codegen.None))), 111 m.Names(codegen.PropFilterALL, prefix, "", ",", nc)) 112 }, 113 "DBKeyPKs": func(m codegen.ModelKey, prefix string) string { 114 nc := codegen.None 115 if prefix == "" { 116 nc = codegen.LowerCamelCase 117 } 118 119 return fmt.Sprintf("'M', C_%s, uint64(%d), %s", 120 m.Name(), 121 codegen.CrcHash(tools.StrToByte(m.Names(codegen.PropFilterALL, "", "", ",", codegen.None))), 122 m.Names(codegen.PropFilterPKs, prefix, "", ",", nc)) 123 }, 124 "DBPrefix": func(m codegen.ModelKey) string { 125 return fmt.Sprintf("'M', C_%s, uint64(%d)", 126 m.Name(), 127 codegen.CrcHash(tools.StrToByte(m.Names(codegen.PropFilterALL, "", "", ",", codegen.None)))) 128 }, 129 "IndexDBKey": func(m codegen.MessageArg, f codegen.FieldArg, prefix, postfix string) string { 130 nc := codegen.None 131 if prefix == "" { 132 nc = codegen.LowerCamelCase 133 } 134 135 return fmt.Sprintf("'I', C_%s, uint64(%d), %s%s%s, %s", 136 m.Name(), codegen.CrcHash([]byte(f.Name())), 137 prefix, f.Name(), postfix, 138 m.Table.Names(codegen.PropFilterALL, prefix, "", ",", nc)) 139 }, 140 "IndexDBPrefix": func(m codegen.MessageArg, f codegen.FieldArg, prefix, postfix string) string { 141 return fmt.Sprintf("'I', C_%s, uint64(%d), %s%s%s", 142 m.Name(), codegen.CrcHash([]byte(f.Name())), 143 prefix, inflection.Singular(f.NameCC()), postfix) 144 }, 145 "String": func(m codegen.ModelKey, prefix, sep string, lcc bool) string { 146 nc := codegen.None 147 if lcc { 148 nc = codegen.LowerCamelCase 149 } 150 151 return m.Names(codegen.PropFilterALL, prefix, "", sep, nc) 152 }, 153 "StringPKs": func(m codegen.ModelKey, prefix, sep string, lcc bool) string { 154 nc := codegen.None 155 if lcc { 156 nc = codegen.LowerCamelCase 157 } 158 159 return m.Names(codegen.PropFilterPKs, prefix, "", sep, nc) 160 }, 161 "StringCKs": func(m codegen.ModelKey, prefix, sep string, lcc bool) string { 162 nc := codegen.None 163 if lcc { 164 nc = codegen.LowerCamelCase 165 } 166 167 return m.Names(codegen.PropFilterCKs, prefix, "", sep, nc) 168 }, 169 "OrderTypes": func(m codegen.MessageArg) map[string]int { 170 var ( 171 uniqueOrders = make(map[string]int) 172 ) 173 for idx, v := range m.Views { 174 uniqueOrders[v.Names(codegen.PropFilterPKs, "", "", "", codegen.None)] = idx 175 } 176 177 return uniqueOrders 178 }, 179 } 180 181 func Generate(g *Generator, arg codegen.MessageArg) { 182 if !arg.IsSingleton && !arg.IsAggregate { 183 return 184 } 185 g.g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/store"}) 186 g.g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/tools"}) 187 g.g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony"}) 188 g.g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/errors"}) 189 190 helperFunctions["RepoName"] = func(name string) string { 191 return fmt.Sprintf("%s%sRepo", name, tools.ToCamel(g.repoPrefix)) 192 } 193 helperFunctions["SingletonName"] = func(name string) string { 194 return fmt.Sprintf("%s%sSingleton", name, tools.ToCamel(g.repoPrefix)) 195 } 196 197 if arg.IsSingleton { 198 g.g.P( 199 codegen.ExecTemplate( 200 template.Must( 201 template.New("genSingleton"). 202 Funcs(helperFunctions). 203 Parse(genSingleton), 204 ), 205 arg, 206 ), 207 ) 208 } else if arg.IsAggregate { 209 g.g.P( 210 codegen.ExecTemplate( 211 template.Must( 212 template.New("genHelpers"). 213 Funcs(helperFunctions). 214 Parse(genHelpers), 215 ), 216 arg, 217 ), 218 ) 219 g.g.P( 220 codegen.ExecTemplate( 221 template.Must( 222 template.New("genPrimaryKey"). 223 Funcs(helperFunctions). 224 Parse(genPrimaryKey), 225 ), 226 arg, 227 ), 228 ) 229 g.g.P( 230 codegen.ExecTemplate( 231 template.Must( 232 template.New("genRepo"). 233 Funcs(helperFunctions). 234 Parse(genRepo), 235 ), 236 arg, 237 ), 238 ) 239 g.g.P( 240 codegen.ExecTemplate( 241 template.Must( 242 template.New("genCreate"). 243 Funcs(helperFunctions). 244 Parse(genCreate), 245 ), 246 arg, 247 ), 248 ) 249 g.g.P( 250 codegen.ExecTemplate( 251 template.Must( 252 template.New("genUpdate"). 253 Funcs(helperFunctions). 254 Parse(genUpdate), 255 ), 256 arg, 257 ), 258 ) 259 g.g.P( 260 codegen.ExecTemplate( 261 template.Must( 262 template.New("genSave"). 263 Funcs(helperFunctions). 264 Parse(genSave), 265 ), 266 arg, 267 ), 268 ) 269 g.g.P( 270 codegen.ExecTemplate( 271 template.Must( 272 template.New("genRead"). 273 Funcs(helperFunctions). 274 Parse(genRead), 275 ), 276 arg, 277 ), 278 ) 279 g.g.P( 280 codegen.ExecTemplate( 281 template.Must( 282 template.New("genDelete"). 283 Funcs(helperFunctions). 284 Parse(genDelete), 285 ), 286 arg, 287 ), 288 ) 289 g.g.P( 290 codegen.ExecTemplate( 291 template.Must( 292 template.New("genList"). 293 Funcs(helperFunctions). 294 Parse(genList), 295 ), 296 arg, 297 ), 298 ) 299 g.g.P( 300 codegen.ExecTemplate( 301 template.Must( 302 template.New("genIter"). 303 Funcs(helperFunctions). 304 Parse(genIter), 305 ), 306 arg, 307 ), 308 ) 309 g.g.P( 310 codegen.ExecTemplate( 311 template.Must( 312 template.New("genListByIndex"). 313 Funcs(helperFunctions). 314 Parse(genListByIndex), 315 ), 316 arg, 317 ), 318 ) 319 } 320 } 321 322 const genSingleton = ` 323 {{$model := .}} 324 {{$repoName := SingletonName .Name}} 325 {{$modelName := .Name}} 326 type {{$repoName}} struct { 327 s *store.Store 328 } 329 330 func New{{$repoName}}(s *store.Store) *{{$repoName}} { 331 return &{{$repoName}}{ 332 s: s, 333 } 334 } 335 336 func (r *{{$repoName}}) SaveWithTxn (txn *rony.StoreTxn, alloc *tools.Allocator, m *{{$modelName}}) (err error) { 337 if alloc == nil { 338 alloc = tools.NewAllocator() 339 defer alloc.ReleaseAll() 340 } 341 342 err = store.Marshal(txn, alloc, m, {{ SingletonDBKey . }}) 343 if err != nil { 344 return 345 } 346 return nil 347 } 348 349 func (r *{{$repoName}}) Save (m *{{$modelName}}) (err error) { 350 alloc := tools.NewAllocator() 351 defer alloc.ReleaseAll() 352 353 return r.s.Update(func(txn *rony.StoreTxn) error { 354 return r.SaveWithTxn(txn, alloc, m) 355 }) 356 } 357 358 func (r *{{$repoName}}) ReadWithTxn ( 359 txn *rony.StoreTxn, alloc *tools.Allocator, m *{{$modelName}}, 360 ) (*{{$modelName}}, error) { 361 if alloc == nil { 362 alloc = tools.NewAllocator() 363 defer alloc.ReleaseAll() 364 } 365 366 err := store.Unmarshal(txn, alloc, m, {{ SingletonDBKey . }}) 367 if err != nil { 368 return nil, err 369 } 370 return m, err 371 } 372 373 func (r *{{$repoName}}) Read (m *{{$modelName}}) (*{{$modelName}}, error) { 374 alloc := tools.NewAllocator() 375 defer alloc.ReleaseAll() 376 377 if m == nil { 378 m = &{{$modelName}}{} 379 } 380 381 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 382 m, err = r.ReadWithTxn(txn, alloc, m) 383 return 384 }) 385 return m, err 386 } 387 388 ` 389 390 const genHelpers = ` 391 {{$model := .}} 392 {{$repoName := RepoName .Name}} 393 {{$modelName := .Name}} 394 {{- range .Fields }} 395 {{- if eq .Cardinality "repeated" }} 396 {{- if not (or (eq .Kind "message") (eq .Kind "group")) }} 397 {{- if eq .Kind "bytes" }} 398 func (x *{{$modelName}}) Has{{Singular .Name}}(xx {{.GoKind}}) bool { 399 for idx := range x.{{.Name}} { 400 if bytes.Equal(x.{{.Name}}[idx], xx) { 401 return true 402 } 403 } 404 return false 405 } 406 407 {{- else if eq .Kind "enum" }} 408 func (x *{{$modelName}}) Has{{Singular .Name}} (xx {{.GoKind}}) bool { 409 for idx := range x.{{.Name}} { 410 if x.{{.Name}}[idx] == xx { 411 return true 412 } 413 } 414 return false 415 } 416 417 {{- else }} 418 func (x *{{$modelName}})Has{{Singular .Name}} (xx {{.GoKind}}) bool { 419 for idx := range x.{{.Name}} { 420 if x.{{.Name}}[idx] == xx { 421 return true 422 } 423 } 424 return false 425 } 426 427 {{- end }} 428 {{- end }} 429 {{- end }} 430 {{ end }} 431 ` 432 433 const genRepo = ` 434 {{$repoName := RepoName .Name}} 435 type {{$repoName}} struct { 436 s *store.Store 437 } 438 439 func New{{$repoName}}(s *store.Store) *{{$repoName}} { 440 return &{{$repoName}}{ 441 s: s, 442 } 443 } 444 445 ` 446 447 const genCreate = ` 448 {{$model := .}} 449 {{$repoName := RepoName .Name}} 450 {{$modelName := .Name}} 451 func (r *{{$repoName}}) CreateWithTxn( 452 txn *rony.StoreTxn, alloc *tools.Allocator, m *{{$modelName}}, 453 ) (err error) { 454 if alloc == nil { 455 alloc = tools.NewAllocator() 456 defer alloc.ReleaseAll() 457 } 458 key := alloc.Gen({{DBKey .Table "m."}}) 459 if store.ExistsByKey(txn, alloc, key) { 460 return errors.ErrAlreadyExists 461 } 462 463 // save table entry 464 val := alloc.Marshal(m) 465 err = store.SetByKey(txn, val, key) 466 if err != nil { 467 return 468 } 469 {{range .Views }} 470 // save view entry 471 err = store.Set(txn, alloc, val, {{(DBKey . "m.")}}) 472 if err != nil { 473 return err 474 } 475 {{- end }} 476 {{ if HasIndex . }} 477 // key := alloc.Gen({{(DBKey .Table "m.")}}) 478 {{- range .Fields }} 479 {{- if .HasIndex }} 480 // update field index by saving new value: {{.Name}} 481 {{- if eq .Cardinality "repeated" }} 482 for idx := range m.{{.Name}} { 483 err = store.Set(txn, alloc, key, {{IndexDBKey $model . "m." "[idx]"}}) 484 if err != nil { 485 return 486 } 487 } 488 {{- else }} 489 err = store.Set(txn, alloc, key, {{IndexDBKey $model . "m." ""}}) 490 if err != nil { 491 return 492 } 493 {{- end }} 494 {{- end }} 495 {{- end }} 496 {{- end }} 497 498 return 499 } 500 501 func (r *{{$repoName}}) Create(m *{{$modelName}}) error { 502 alloc := tools.NewAllocator() 503 defer alloc.ReleaseAll() 504 return r.s.Update(func(txn *rony.StoreTxn) error { 505 return r.CreateWithTxn (txn, alloc, m) 506 }) 507 } 508 ` 509 510 const genUpdate = ` 511 {{$model := .}} 512 {{$repoName := RepoName .Name}} 513 {{$modelName := .Name}} 514 func (r *{{$repoName}}) UpdateWithTxn ( 515 txn *rony.StoreTxn, alloc *tools.Allocator, m *{{$modelName}}, 516 ) error { 517 if alloc == nil { 518 alloc = tools.NewAllocator() 519 defer alloc.ReleaseAll() 520 } 521 522 err := r.DeleteWithTxn(txn, alloc, {{String .Table "m." "," false}}) 523 if err != nil { 524 return err 525 } 526 527 return r.CreateWithTxn(txn, alloc, m) 528 } 529 530 func (r *{{$repoName}}) Update ({{FuncArgs .Table ""}}, m *{{$modelName}}) error { 531 alloc := tools.NewAllocator() 532 defer alloc.ReleaseAll() 533 534 if m == nil { 535 return errors.ErrEmptyObject 536 } 537 538 err := r.s.Update(func(txn *rony.StoreTxn) (err error) { 539 return r.UpdateWithTxn(txn, alloc, m) 540 }) 541 542 return err 543 } 544 ` 545 546 const genSave = ` 547 {{$model := .}} 548 {{$repoName := RepoName .Name}} 549 {{$modelName := .Name}} 550 func (r *{{$repoName}}) SaveWithTxn ( 551 txn *rony.StoreTxn, alloc *tools.Allocator, m *{{$modelName}}, 552 ) (err error) { 553 if store.Exists(txn, alloc, {{DBKey .Table "m."}}) { 554 return r.UpdateWithTxn(txn, alloc, m) 555 } else { 556 return r.CreateWithTxn(txn, alloc, m) 557 } 558 } 559 560 func (r *{{$repoName}}) Save (m *{{$modelName}}) error { 561 alloc := tools.NewAllocator() 562 defer alloc.ReleaseAll() 563 564 return r.s.Update(func(txn *rony.StoreTxn) error { 565 return r.SaveWithTxn(txn, alloc, m) 566 }) 567 } 568 ` 569 570 const genRead = ` 571 {{$model := .}} 572 {{$repoName := RepoName .Name}} 573 {{$modelName := .Name}} 574 func (r *{{$repoName}}) ReadWithTxn( 575 txn *rony.StoreTxn, alloc *tools.Allocator, 576 {{FuncArgs .Table ""}}, m *{{$modelName}}, 577 ) (*{{$modelName}}, error) { 578 if alloc == nil { 579 alloc = tools.NewAllocator() 580 defer alloc.ReleaseAll() 581 } 582 583 err := store.Unmarshal(txn, alloc, m, {{DBKey .Table ""}}) 584 if err != nil { 585 return nil, err 586 } 587 return m, nil 588 } 589 590 func (r *{{$repoName}}) Read ({{FuncArgs .Table ""}}, m *{{$modelName}}) (*{{$modelName}}, error) { 591 alloc := tools.NewAllocator() 592 defer alloc.ReleaseAll() 593 594 if m == nil { 595 m = &{{$modelName}}{} 596 } 597 598 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 599 m, err = r.ReadWithTxn(txn, alloc, {{String .Table "" "," true}}, m) 600 return err 601 }) 602 return m, err 603 } 604 {{ range .Views }} 605 func (r *{{$repoName}}) ReadBy{{MVAlias . ""}}WithTxn ( 606 txn *rony.StoreTxn, alloc *tools.Allocator, 607 {{FuncArgs . ""}}, m *{{$modelName}}, 608 ) (*{{$modelName}}, error) { 609 if alloc == nil { 610 alloc = tools.NewAllocator() 611 defer alloc.ReleaseAll() 612 } 613 614 err := store.Unmarshal(txn, alloc, m, {{DBKey . ""}}) 615 if err != nil { 616 return nil, err 617 } 618 return m, err 619 } 620 621 func (r *{{$repoName}}) ReadBy{{MVAlias . ""}}({{FuncArgs . ""}}, m *{{$modelName}}) (*{{$modelName}}, error) { 622 alloc := tools.NewAllocator() 623 defer alloc.ReleaseAll() 624 625 if m == nil { 626 m = &{{$modelName}}{} 627 } 628 629 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 630 m, err = r.ReadBy{{MVAlias . ""}}WithTxn (txn, alloc, {{String . "" "," true}}, m) 631 return err 632 }) 633 return m, err 634 } 635 {{ end }} 636 ` 637 638 const genDelete = ` 639 {{$model := .}} 640 {{$repoName := RepoName .Name}} 641 {{$modelName := .Name}} 642 func (r *{{$repoName}}) DeleteWithTxn( 643 txn *rony.StoreTxn, alloc *tools.Allocator, 644 {{FuncArgs .Table ""}}, 645 ) error { 646 if alloc == nil { 647 alloc = tools.NewAllocator() 648 defer alloc.ReleaseAll() 649 } 650 {{ if or (gt (len .Views) 0) (HasIndex .) }} 651 m := &{{$modelName}}{} 652 err := store.Unmarshal(txn, alloc, m, {{DBKey .Table ""}}) 653 if err != nil { 654 return err 655 } 656 err = store.Delete(txn, alloc, {{DBKey .Table "m."}}) 657 {{- else }} 658 err := store.Delete(txn, alloc, {{DBKey .Table ""}}) 659 {{- end }} 660 if err != nil { 661 return err 662 } 663 {{- range .Fields }} 664 {{ if .HasIndex }} 665 // delete field index 666 {{- if eq .Cardinality "repeated" }} 667 for idx := range m.{{.Name}} { 668 err = store.Delete(txn, alloc, {{IndexDBKey $model . "m." "[idx]"}}) 669 if err != nil { 670 return err 671 } 672 } 673 {{- else }} 674 err = store.Delete(txn, alloc, {{IndexDBKey $model . "m." ""}}) 675 if err != nil { 676 return err 677 } 678 {{- end }} 679 {{- end }} 680 {{- end }} 681 {{- range .Views }} 682 err = store.Delete(txn, alloc, {{DBKey . "m."}}) 683 if err != nil { 684 return err 685 } 686 687 {{- end }} 688 689 return nil 690 } 691 692 func (r *{{$repoName}}) Delete({{FuncArgs .Table ""}}) error { 693 alloc := tools.NewAllocator() 694 defer alloc.ReleaseAll() 695 696 return r.s.Update(func(txn *rony.StoreTxn) error { 697 return r.DeleteWithTxn(txn, alloc, {{String .Table "" "," true}}) 698 }) 699 } 700 ` 701 702 const genPrimaryKey = ` 703 {{$modelName := .Name}} 704 type {{$modelName}}PrimaryKey interface { 705 make{{$modelName}}Private() 706 } 707 708 type {{$modelName}}PK struct { 709 {{- range .Table.Keys }} 710 {{.Name}} {{.GoType}} 711 {{- end }} 712 } 713 714 func ({{$modelName}}PK) make{{$modelName}}Private() {} 715 716 {{- range .Views }} 717 718 type {{MVName .}}PK struct { 719 {{- range .Keys }} 720 {{.Name}} {{.GoType}} 721 {{- end }} 722 } 723 724 func ({{MVName .}}PK) make{{$modelName}}Private() {} 725 {{ end }} 726 ` 727 728 const genIter = ` 729 {{$model := .}} 730 {{$repoName := RepoName .Name}} 731 {{$modelName := .Name}} 732 func (r *{{$repoName}}) IterWithTxn( 733 txn *rony.StoreTxn, alloc *tools.Allocator, offset {{$modelName}}PrimaryKey, 734 ito *store.IterOption, cb func(m *{{$modelName}}) bool, 735 ) error { 736 if alloc == nil { 737 alloc = tools.NewAllocator() 738 defer alloc.ReleaseAll() 739 } 740 741 var seekKey []byte 742 opt := store.DefaultIteratorOptions 743 opt.Reverse = ito.Backward() 744 745 switch offset := offset.(type) { 746 case {{$modelName}}PK: 747 opt.Prefix = alloc.Gen({{DBKeyPKs .Table "offset."}}) 748 seekKey = alloc.Gen({{DBKey .Table "offset."}}) 749 {{ range .Views }} 750 case {{MVName .}}PK: 751 opt.Prefix = alloc.Gen({{DBKeyPKs . "offset."}}) 752 seekKey = alloc.Gen({{DBKey . "offset."}}) 753 {{ end }} 754 default: 755 opt.Prefix = alloc.Gen({{DBPrefix .Table}}) 756 seekKey = opt.Prefix 757 } 758 759 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 760 iter := txn.NewIterator(opt) 761 if ito.OffsetKey() == nil { 762 iter.Seek(seekKey) 763 } else { 764 iter.Seek(ito.OffsetKey()) 765 } 766 exitLoop := false 767 for ; iter.ValidForPrefix(opt.Prefix); iter.Next() { 768 err = iter.Item().Value(func(val []byte) error { 769 m := &{{$modelName}}{} 770 err := m.Unmarshal(val) 771 if err != nil { 772 return err 773 } 774 if !cb(m) { 775 exitLoop = true 776 } 777 return nil 778 }) 779 if err != nil || exitLoop { 780 break 781 } 782 } 783 iter.Close() 784 785 return 786 }) 787 788 return err 789 } 790 791 func (r *{{$repoName}}) Iter( 792 pk {{$modelName}}PrimaryKey, ito *store.IterOption, cb func(m *{{$modelName}}) bool, 793 ) error { 794 alloc := tools.NewAllocator() 795 defer alloc.ReleaseAll() 796 797 798 return r.s.View(func(txn *rony.StoreTxn) error { 799 return r.IterWithTxn(txn, alloc, pk, ito, cb) 800 }) 801 } 802 ` 803 804 const genList = ` 805 {{$model := .}} 806 {{$repoName := RepoName .Name}} 807 {{$modelName := .Name}} 808 func (r *{{$repoName}}) ListWithTxn( 809 txn *rony.StoreTxn, alloc *tools.Allocator, 810 offset {{$modelName}}PrimaryKey, lo *store.ListOption, cond func(m *{{$modelName}}) bool, 811 ) ([]*{{$modelName}}, error) { 812 if alloc == nil { 813 alloc = tools.NewAllocator() 814 defer alloc.ReleaseAll() 815 } 816 817 var seekKey []byte 818 opt := store.DefaultIteratorOptions 819 opt.Reverse = lo.Backward() 820 res := make([]*{{$modelName}}, 0, lo.Limit()) 821 822 switch offset := offset.(type) { 823 case {{$modelName}}PK: 824 opt.Prefix = alloc.Gen({{DBKeyPKs .Table "offset."}}) 825 seekKey = alloc.Gen({{DBKey .Table "offset."}}) 826 {{ range .Views }} 827 case {{MVName .}}PK: 828 opt.Prefix = alloc.Gen({{DBKeyPKs . "offset."}}) 829 seekKey = alloc.Gen({{DBKey . "offset."}}) 830 {{ end }} 831 default: 832 opt.Prefix = alloc.Gen({{DBPrefix .Table}}) 833 seekKey = opt.Prefix 834 } 835 836 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 837 iter := txn.NewIterator(opt) 838 offset := lo.Skip() 839 limit := lo.Limit() 840 for iter.Seek(seekKey); iter.ValidForPrefix(opt.Prefix); iter.Next() { 841 if offset--; offset >= 0 { 842 continue 843 } 844 if limit--; limit < 0 { 845 break 846 } 847 err = iter.Item().Value(func(val []byte) error { 848 m := &{{$modelName}}{} 849 err := m.Unmarshal(val) 850 if err != nil { 851 return err 852 } 853 if cond == nil || cond(m) { 854 res = append(res, m) 855 } else { 856 limit++ 857 } 858 return nil 859 }) 860 if err != nil { 861 return err 862 } 863 } 864 iter.Close() 865 return 866 }) 867 868 return res, err 869 } 870 871 func (r *{{$repoName}}) List( 872 pk {{$modelName}}PrimaryKey, lo *store.ListOption, cond func(m *{{$modelName}}) bool, 873 ) ([]*{{$modelName}}, error) { 874 alloc := tools.NewAllocator() 875 defer alloc.ReleaseAll() 876 877 var ( 878 res []*{{$modelName}} 879 err error 880 ) 881 err = r.s.View(func(txn *rony.StoreTxn) error { 882 res, err = r.ListWithTxn(txn, alloc, pk, lo, cond) 883 return err 884 }) 885 if err != nil { 886 return nil, err 887 } 888 889 return res, nil 890 } 891 ` 892 893 const genListByIndex = ` 894 {{$model := .}} 895 {{$repoName := RepoName .Name}} 896 {{$modelName := .Name}} 897 {{ range .Fields }} 898 {{ if .HasIndex }} 899 func (r *{{$repoName}}) ListBy{{Singular .Name}} ( 900 {{Singular .NameCC}} {{.GoKind}}, lo *store.ListOption, cond func(*{{$modelName}}) bool, 901 ) ([]*{{$modelName}}, error) { 902 alloc := tools.NewAllocator() 903 defer alloc.ReleaseAll() 904 905 opt := store.DefaultIteratorOptions 906 opt.Reverse = lo.Backward() 907 opt.Prefix = alloc.Gen({{IndexDBPrefix $model . "" ""}}) 908 res := make([]*{{$modelName}}, 0, lo.Limit()) 909 err := r.s.View(func(txn *rony.StoreTxn) (err error) { 910 iter := txn.NewIterator(opt) 911 offset := lo.Skip() 912 limit := lo.Limit() 913 for iter.Seek(opt.Prefix); iter.ValidForPrefix(opt.Prefix); iter.Next() { 914 if offset--; offset >= 0 { 915 continue 916 } 917 if limit--; limit < 0 { 918 break 919 } 920 err = iter.Item().Value(func(val []byte) error { 921 b, err := store.GetByKey(txn, alloc, val) 922 if err != nil { 923 return err 924 } 925 m := &{{$modelName}}{} 926 err = m.Unmarshal(b) 927 if err != nil { 928 return err 929 } 930 if cond == nil || cond(m) { 931 res = append(res, m) 932 } else { 933 limit++ 934 } 935 return nil 936 }) 937 if err != nil { 938 break 939 } 940 } 941 iter.Close() 942 return err 943 }) 944 if err != nil { 945 return nil, err 946 } 947 948 return res, nil 949 } 950 {{ end }} 951 {{ end }} 952 953 `