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  `