search

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2022 License: MIT Imports: 7 Imported by: 0

README

Search model generator

Basic model required, which can be generated with one of the model generators

Use search sub-command to execute generator:

bungen search -h

First create your database and tables in it

create table "projects"
(
    "projectId" serial not null,
    "name"      text   not null,

    primary key ("projectId")
);

create table "users"
(
    "userId"    serial      not null,
    "email"     varchar(64) not null,
    "activated" bool        not null default false,
    "name"      varchar(128),
    "countryId" integer,

    primary key ("userId")
);

create schema "geo";
create table geo."countries"
(
    "countryId" serial     not null,
    "code"      varchar(3) not null,
    "coords"    integer[],

    primary key ("countryId")
);

alter table "users"
    add constraint "fk_user_country"
        foreign key ("countryId")
            references geo."countries" ("countryId") on update restrict on delete restrict;

Run generator

bungen search -c postgres://user:password@localhost:5432/yourdb -o ~/output/model.go -t public.* -f

You should get following search structs on model package:

//lint:file-ignore U1000 ignore unused code, it's generated
package model

import (
	"github.com/uptrace/bun"
)

const condition =  "?.? = ?"

// base filters
type applier func(query bun.QueryBuilder) (bun.QueryBuilder, error)

type search struct {
	appliers[] applier
}

func (s *search) apply(query bun.QueryBuilder) {
	for _, applier := range s.appliers {
		applier(query)
	}
}

func (s *search) where(query bun.QueryBuilder, table, field string, value interface{}) {
	
	query.Where(condition, bun.Ident(table), bun.Ident(field), value)
	
}

func (s *search) WithApply(a applier) {
	if s.appliers == nil {
		s.appliers = []applier{}
	}
	s.appliers = append(s.appliers, a)
}

func (s *search) With(condition string, params ...interface{}) {
	s.WithApply(func(query bun.QueryBuilder) (bun.QueryBuilder, error) {
		return query.Where(condition, params...), nil
	})
}

// Searcher is interface for every generated filter
type Searcher interface {
	Apply(query bun.QueryBuilder) bun.QueryBuilder
	Q() applier

	With(condition string, params ...interface{})
	WithApply(a applier)
}


type ProjectSearch struct {
	search 

	
	ID *int
	Name *string
}

func (s *ProjectSearch) Apply(query bun.QueryBuilder) bun.QueryBuilder { 
	if s.ID != nil {  
		s.where(query, Tables.Project.Alias, Columns.Project.ID, s.ID)
	}
	if s.Name != nil {  
		s.where(query, Tables.Project.Alias, Columns.Project.Name, s.Name)
	}

	s.apply(query)
	
	return query
}

func (s *ProjectSearch) Q() applier {
	return func(query bun.QueryBuilder) (bun.QueryBuilder, error) {
		return s.Apply(query), nil
	}
}

type UserSearch struct {
	search 

	
	ID *int
	Email *string
	Activated *bool
	Name *string
	CountryID *int
}

func (s *UserSearch) Apply(query bun.QueryBuilder) bun.QueryBuilder { 
	if s.ID != nil {  
		s.where(query, Tables.User.Alias, Columns.User.ID, s.ID)
	}
	if s.Email != nil {  
		s.where(query, Tables.User.Alias, Columns.User.Email, s.Email)
	}
	if s.Activated != nil {  
		s.where(query, Tables.User.Alias, Columns.User.Activated, s.Activated)
	}
	if s.Name != nil {  
		s.where(query, Tables.User.Alias, Columns.User.Name, s.Name)
	}
	if s.CountryID != nil {  
		s.where(query, Tables.User.Alias, Columns.User.CountryID, s.CountryID)
	}

	s.apply(query)
	
	return query
}

func (s *UserSearch) Q() applier {
	return func(query bun.QueryBuilder) (bun.QueryBuilder, error) {
		return s.Apply(query), nil
	}
}

type GeoCountrySearch struct {
	search 

	
	ID *int
	Code *string
}

func (s *GeoCountrySearch) Apply(query bun.QueryBuilder) bun.QueryBuilder { 
	if s.ID != nil {  
		s.where(query, Tables.GeoCountry.Alias, Columns.GeoCountry.ID, s.ID)
	}
	if s.Code != nil {  
		s.where(query, Tables.GeoCountry.Alias, Columns.GeoCountry.Code, s.Code)
	}

	s.apply(query)
	
	return query
}

func (s *GeoCountrySearch) Q() applier {
	return func(query bun.QueryBuilder) (bun.QueryBuilder, error) {
		return s.Apply(query), nil
	}
}

Try it

package model

import (
	"fmt"
	"testing"

	"github.com/uptrace/bun"
)

func TestModel(t *testing.T) {
	// connecting to db
	pgdb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN("postgres://user:password@localhost:5432/yourdb")))
	db := bun.NewDB(pgdb, pgdialect.New(), bun.WithDiscardUnknownColumns())

	if _, err := db.Exec(`truncate table users; truncate table geo.countries cascade;`); err != nil {
		panic(err)
	}

	// objects to insert
	toInsert := []GeoCountry{
		GeoCountry{
			Code:   "us",
			Coords: []int{1, 2},
		},
		GeoCountry{
			Code:   "uk",
			Coords: nil,
		},
	}

	// inserting
	ctx := context.Background()
	if _, err := db.NewInsert().Model(&toInsert).Column("code", "coords").Exec(ctx); err != nil {
		panic(err)
	}

    code := "us"
    country := GeoCountry{}
    search := GeoCountrySearch{
        Code: &code,
    }
    m := db.NewSelect().Model(&country)
	m = search.Apply(m.QueryBuilder()).Unwrap().(*bun.SelectQuery)

    ctx = context.Background()
	if err := m.Scan(ctx); err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", country)
}

Documentation

Index

Constants

View Source
const Template = `` /* 1914-byte string literal not displayed */

Variables

This section is empty.

Functions

func CreateCommand

func CreateCommand() *cobra.Command

CreateCommand creates generator command

Types

type Options

type Options struct {
	base.Options

	// Package sets package name for model
	// Works only with SchemaPackage = false
	Package string

	// Do not replace primary key name to ID
	KeepPK bool

	// Do not generate alias tag
	NoAlias bool

	// Strict types in filters
	Relaxed bool

	// Add json tag to models
	AddJSONTag bool
}

Options for generator

func (*Options) Def

func (o *Options) Def()

Def fills default values of an options

type Search struct {
	// contains filtered or unexported fields
}

Search represents search generator

func New

func New() *Search

New creates generator

func (*Search) AddFlags

func (g *Search) AddFlags(command *cobra.Command)

AddFlags adds flags to command

func (*Search) Generate

func (g *Search) Generate() error

Generate runs whole generation process

func (*Search) Options

func (g *Search) Options() *Options

Options gets options

func (*Search) Packer

func (g *Search) Packer() base.Packer

Packer returns packer function for compile entities into package

func (*Search) ReadFlags

func (g *Search) ReadFlags(command *cobra.Command) error

ReadFlags read flags from command

func (*Search) Repack

func (g *Search) Repack(packer base.Packer) error

Repack runs generator with custom packer

func (*Search) SetOptions

func (g *Search) SetOptions(options Options)

SetOptions sets options

type TemplateColumn

type TemplateColumn struct {
	model.Column

	Relaxed bool

	HasTags bool
	Tag     template.HTML

	UseCustomRender bool
	CustomRender    template.HTML
}

TemplateColumn stores column info

func NewTemplateColumn

func NewTemplateColumn(_ model.Entity, column model.Column, options Options) TemplateColumn

NewTemplateColumn creates a column for template

type TemplateEntity

type TemplateEntity struct {
	model.Entity

	NoAlias bool
	Alias   string

	Columns []TemplateColumn

	Imports []string
}

TemplateEntity stores struct info

func NewTemplateEntity

func NewTemplateEntity(entity model.Entity, options Options) TemplateEntity

NewTemplateEntity creates an entity for template

type TemplatePackage

type TemplatePackage struct {
	Package string

	HasImports bool
	Imports    []string

	Entities []TemplateEntity
}

TemplatePackage stores package info

func NewTemplatePackage

func NewTemplatePackage(entities []model.Entity, options Options) TemplatePackage

NewTemplatePackage creates a package for template

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL