Speed Up your coding process with Smart Code Generator.
Axara CLI is code generator that used to build repeatable code depend on the Model and Template. For example, If you work using architecture layer this tool will useful to help build your CRUD(create update delete) on repository, delivery, or usecase layer, even mocking an service or swagger documentation. So you can just focus to the business logic on the project.
go install github.com/wirnat/axara@latest
Let's practices with a simple case, assume we want to create a CRUD for modules company and customer, but only in repository layer.
First, prepare the models in model directory:
package model type Company struct { BaseModel Name string `json:"name"` //@meta validate:true } //@Register Company
package model import "time" type Customer struct { BaseModel Name string `json:"name"` //@meta validate:true BirthDate *time.Time `json:"birth_date"` Email string `json:"email"` //@meta validate:true Phone string `json:"phone"` //@meta validate:true } //@Register Customer
package model import ( "time" ) type BaseModel struct { ID int64 `json:"id"` UUID string `json:"uuid"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` //~ignore DeletedAt *time.Time `json:"deleted_at"` //~ignore }
Model work as backbone in this generator, if @Register comment is found in model, it will execute the model to the generator.
Then, create a config yaml file simple_crud.yaml
You can use other name of config file if you want.
key: ᬅᬓ᭄ᬱᬭ model_path: model module_name: gox models: Customer: module: customer Company: module: company meta: result_path: modules repository_dir: ~result_path~/~module~/repository repository_gorm_dir: ~result_path~/~module~/repository/gorm_repository template: templates import_model: ~module_name~/~model_path~ import_repository: ~module_name~/repository module_traits: - name: "~model_snake~ repository" dir: ~repository_dir~ template: ~template~/repository.text file_name: "~model_snake~.g.go" active: true - name: "~model_snake~ repository gorm" dir: ~repository_gorm_dir~ template: ~template~/repository_gorm.text file_name: "~model_snake~_gorm.g.go" active: true
Module Trait will executed when the generator read the model that has @Register [Model]
Axara CLI has default meta and can called in generator config file or in template file, but you can also add meta in config file or you can add meta in models (dynamic meta)
In config file you can use ~meta name~ to make decode value to your config for more dynamic and readable.
Now let's create the template, at module_traits in config file we have declared 2 generate file, so we need create 2 template too.
Template for interface repository file, templates/repository.text :
package repository import ( "context" "{{.Meta.import_model}}" "time" ) type {{.Model}} interface { Fetch(ctx context.Context, param Param) (res []model.{{.Model}}, err error) Show(ctx context.Context, param Param) (res model.{{.Model}}, err error) Update(ctx context.Context, param Param, update model.{{.Model}}) (err error) Store(ctx context.Context, store model.{{.Model}}) (err error) Delete(ctx context.Context, id int64) (err error) } type Param struct { {{- range $m:=.ModelFields }} {{$m.Name }} *{{$m.Type }} `json:"{{$m.Json -}}" form:"{{$m.Json }}" query:"{{$m.Json }}" {{if eq $m.Meta.validate "true"}}validate:"required"{{end}}` {{- end}} }
Template for repository implementation file, templates/repository_gorm.text:
package gorm_repository import ( "context" "gorm.io/gorm" "{{.Meta.import_model}}" "{{.Meta.import_repository}}" ) type {{.ModelCamel}}Gorm struct { gorm.DB } func New{{.Model}}Gorm(DB gorm.DB) *{{.ModelCamel}}Gorm { return &{{.ModelCamel}}Gorm{DB: DB} } func filter(db *gorm.DB, param repository.Param) { {{- range $m:=.ModelFields }} if param.{{$m.Name}} != nil { *db = *db.Where("{{$m.Json}}=?", *param.{{$m.Name -}}) } {{- end}} } func (r {{.ModelCamel}}Gorm) Fetch(ctx context.Context, param repository.Param) (res []model.{{.Model}}, err error) { filter(&r.DB, param) err = r.DB.Find(&res).Error return } func (r {{.ModelCamel}}Gorm) Show(ctx context.Context, param repository.Param) (res model.{{.Model}}, err error) { filter(&r.DB, param) err = r.DB.First(&res).Error return } func (r {{.ModelCamel}}Gorm) Update(ctx context.Context, param repository.Param, update model.{{.Model}}) (err error) { filter(&r.DB, param) err = r.DB.Updates(&update).Error return } func (r {{.ModelCamel}}Gorm) Store(ctx context.Context, store model.{{.Model}}) (err error) { err = r.DB.Create(&store).Error return } func (r {{.ModelCamel}}Gorm) Delete(ctx context.Context, id int64) (err error) { err = r.DB.Where("id=?", id).Delete(&model.{{.Model}}{}).Error return }
axara generate [your config file] --models [execute models]
axara generate simple_crud.yaml --models Customer,Company
Axara-cli works depend on template, model, and config file. 1. On start process generator will read config file. 2. Scan the model directory to find model that has @Register [model] in model file 3. Then module_traits in config file will execute template and, meta variable base on scanned model will decoded on this process.
Meta is a variable that used for config and template file. Meta can be set from model file or config file.
To add meta base on model, you can declare model and add key value of meta
models: Customer: module: customer anything: hello world! Company: module: company
By default, every fields of model has stored to model_fields meta and can be used in template file, but you also can add meta to every field when template is getting complicated.
type Branch struct { BaseModel CompanyID int64 `json:"company_id"` //@meta validate:true Name string `json:"name"` //@meta validate:true Description *string `json:"description"` }
You also can add meta from config file, by adding in meta, but keep in your mind meta must be unique
meta: result_path: modules repository_dir: ~result_path~/~module~/repository repository_gorm_dir: ~result_path~/~module~/repository/gorm_repository template: templates import_model: ~module_name~/~model_path~ import_repository: ~module_name~/repository
In config file you can call meta using ~[meta-name]~, in template you can call meta using {{.[meta-name]}}
~[meta-name]~
{{.[meta-name]}}
Model
ModelFields
Json
Name
Type
IsPtr
Meta
ModuleName
ResultPath
ModelPath
Main former of this generator is The Template, if config file serve as directory and architecture builder, template is the code builder. Template is compiled when all meta, variable, and config in json and model file has been compiled.
Template will be compiled using default template from Template Go, so you can use directive, variable call, and all feature of The Golang Template.
Here some template examples:
package {{.Meta.service}}_gorm import ( "{{.ModuleName}}/{{.ResultPath}}/{{.Meta.service}}/{{.Meta.service}}_request" "gorm.io/gorm" ) func filter(db *gorm.DB, param {{.Meta.service}}_request.{{.Model}}Param) { {{- range $m:=.ModelFields }} if param.{{$m.Name}} != nil { db = db.Where("{{$m.Name}}", *param.{{$m.Name -}}) } {{- end}} }