diff --git a/Makefile b/Makefile index e2c4b63..b448f6c 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ test: fi; \ done; \ go install ./generator/...; \ + rm ./tests/kallax.go ; \ go generate ./tests/...; \ git diff --no-prefix -U1000; \ if [ `git status | grep 'Changes not staged for commit' | wc -l` != '0' ]; then \ diff --git a/README.md b/README.md index 3d20bf6..08bb1eb 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ Imagine you have the following file in the package where your models are. package models type User struct { - kallax.Model `table:"users"` - ID kallax.ULID `pk:""` + kallax.Model `table:"users" pk:"id"` + ID kallax.ULID Username string Email string Password string @@ -90,7 +90,7 @@ Sometimes you might want to use the generated code in the same package it is def A model is just a Go struct that embeds the `kallax.Model` type. All the fields of this struct will be columns in the database table. -A model also needs to have one (and just one) primary key. That is whatever field of the struct with the struct tag `pk`, which can be `pk:""` for a non auto-incrementable primary key or `pk:"autoincr"` for one that is auto-incrementable. +A model also needs to have one (and just one) primary key. The primary key is defined using the `pk` struct tag on the `kallax.Model` embedding. You can also set the primary key in a field of the struct with the struct tag `pk`, which can be `pk:""` for a non auto-incrementable primary key or `pk:"autoincr"` for one that is auto-incrementable. More about primary keys is discussed at the [primary keys](#primary-keys) section. First, let's review the rules and conventions for model fields: @@ -112,9 +112,9 @@ Let's see an example of models with all these cases: ```go type User struct { - kallax.Model `table:"users"` + kallax.Model `table:"users" pk:"id,autoincr"` kallax.Timestamps - ID int64 `pk:"autoincr"` + ID int64 Username string Password string Emails []string @@ -146,6 +146,8 @@ type Metadata struct { | Tag | Description | Can be used in | | --- | --- | --- | | `table:"table_name"` | Specifies the name of the table for a model. If not provided, the name of the table will be the name of the struct in lower snake case (e.g. `UserPreference` => `user_preference`) | embedded `kallax.Model` | +| `pk:"primary_key_column_name"` | Specifies the column name of the primary key. | embedded `kallax.Model` | +| `pk:"primary_key_column_name,autoincr"` | Specifies the column name of the autoincrementable primary key. | embedded `kallax.Model` | | `pk:""` | Specifies the field is a primary key | any field with a valid identifier type | | `pk:"autoincr"` | Specifies the field is an auto-incrementable primary key | any field with a valid identifier type | | `kallax:"column_name"` | Specifies the name of the column | Any model field that is not a relationship | @@ -680,7 +682,7 @@ These are the flags available for `up` and `down`: **Example:** ``` -kallax migrate up --dir ./my-migrations --dns 'user:pass@localhost:5432/dbname?sslmode=disable' --version 1493991142 +kallax migrate up --dir ./my-migrations --dsn 'user:pass@localhost:5432/dbname?sslmode=disable' --version 1493991142 ``` ### Type mappings diff --git a/appveyor.yml b/appveyor.yml index 4c213e3..200c37e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,12 @@ version: build-{build}.{branch} platform: x64 +image: + - Visual Studio 2015 + clone_folder: c:\gopath\src\gopkg.in\src-d\go-kallax.v1 -shallow_clone: true +shallow_clone: false environment: GOPATH: c:\gopath @@ -16,7 +19,7 @@ services: - postgresql96 install: - - set PATH=C:\Program Files\PostgreSQL\9.6\bin\;%GOPATH%\bin;c:\go\bin;%PATH% + - set PATH=C:\Program Files\PostgreSQL\9.6\bin\;C:\MinGW\bin;%GOPATH%\bin;c:\go\bin;%PATH% - go version - go get -v -t .\... @@ -24,4 +27,4 @@ build: off test_script: - createdb testing - - go test -v .\... + - mingw32-make test diff --git a/batcher.go b/batcher.go index 4262ca1..a65a9e3 100644 --- a/batcher.go +++ b/batcher.go @@ -14,6 +14,7 @@ type batchQueryRunner struct { q Query oneToOneRels []Relationship oneToManyRels []Relationship + throughRels []Relationship db squirrel.DBProxy builder squirrel.SelectBuilder total int @@ -29,6 +30,7 @@ func newBatchQueryRunner(schema Schema, db squirrel.DBProxy, q Query) *batchQuer var ( oneToOneRels []Relationship oneToManyRels []Relationship + throughRels []Relationship ) for _, rel := range q.getRelationships() { @@ -37,6 +39,8 @@ func newBatchQueryRunner(schema Schema, db squirrel.DBProxy, q Query) *batchQuer oneToOneRels = append(oneToOneRels, rel) case OneToMany: oneToManyRels = append(oneToManyRels, rel) + case Through: + throughRels = append(throughRels, rel) } } @@ -46,6 +50,7 @@ func newBatchQueryRunner(schema Schema, db squirrel.DBProxy, q Query) *batchQuer q: q, oneToOneRels: oneToOneRels, oneToManyRels: oneToManyRels, + throughRels: throughRels, db: db, builder: builder, } @@ -125,8 +130,14 @@ func (r *batchQueryRunner) processBatch(rows *sql.Rows) ([]Record, error) { return nil, err } + if len(records) == 0 { + return nil, nil + } + var ids = make([]interface{}, len(records)) + var identType Identifier for i, r := range records { + identType = r.GetID() ids[i] = r.GetID().Raw() } @@ -136,63 +147,140 @@ func (r *batchQueryRunner) processBatch(rows *sql.Rows) ([]Record, error) { return nil, err } - for _, r := range records { - err := r.SetRelationship(rel.Field, indexedResults[r.GetID().Raw()]) - if err != nil { - return nil, err - } + err = setIndexedResults(records, rel, indexedResults) + if err != nil { + return nil, err + } + } - // If the relationship is partial, we can not ensure the results - // in the field reflect the truth of the database. - // In this case, the parent is marked as non-writable. - if rel.Filter != nil { - r.setWritable(false) - } + for _, rel := range r.throughRels { + indexedResults, err := r.getRecordThroughRelationships(ids, rel, identType) + if err != nil { + return nil, err + } + + err = setIndexedResults(records, rel, indexedResults) + if err != nil { + return nil, err } } return records, nil } +func setIndexedResults(records []Record, rel Relationship, indexedResults indexedRecords) error { + for _, r := range records { + err := r.SetRelationship(rel.Field, indexedResults[r.GetID().Raw()]) + if err != nil { + return err + } + + // If the relationship is partial, we can not ensure the results + // in the field reflect the truth of the database. + // In this case, the parent is marked as non-writable. + if rel.Filter != nil { + r.setWritable(false) + } + } + + return nil +} + type indexedRecords map[interface{}][]Record func (r *batchQueryRunner) getRecordRelationships(ids []interface{}, rel Relationship) (indexedRecords, error) { fk, ok := r.schema.ForeignKey(rel.Field) if !ok { - return nil, fmt.Errorf("kallax: cannot find foreign key on field %s for table %s", rel.Field, r.schema.Table()) + return nil, fmt.Errorf("kallax: cannot find foreign key on field %s of table %s", rel.Field, r.schema.Table()) } filter := In(fk, ids...) if rel.Filter != nil { - And(rel.Filter, filter) - } else { - rel.Filter = filter + filter = And(rel.Filter, filter) + } + + q := NewBaseQuery(rel.Schema) + q.Where(filter) + cols, builder := q.compile() + rows, err := builder.RunWith(r.db).Query() + if err != nil { + return nil, err + } + + return indexedResultsFromRows(rows, cols, rel.Schema, fk, nil) +} + +func (r *batchQueryRunner) getRecordThroughRelationships(ids []interface{}, rel Relationship, identType Identifier) (indexedRecords, error) { + lfk, rfk, ok := r.schema.ForeignKeys(rel.Field) + if !ok { + return nil, fmt.Errorf("kallax: cannot find foreign keys for through relationship on field %s of table %s", rel.Field, r.schema.Table()) } q := NewBaseQuery(rel.Schema) - q.Where(rel.Filter) + lschema := r.schema.WithAlias(rel.Schema.Alias()) + intSchema := rel.IntermediateSchema.WithAlias(rel.Schema.Alias()) + q.joinThrough(lschema, intSchema, rel.Schema, lfk, rfk) + q.where(In(lschema.ID(), ids...), lschema) + if rel.Filter != nil { + q.Where(rel.Filter) + } + + if rel.IntermediateFilter != nil { + q.where(rel.IntermediateFilter, intSchema) + } cols, builder := q.compile() + // manually add the extra column to also select the parent id + builder = builder.Column(lschema.ID().QualifiedName(lschema)) rows, err := builder.RunWith(r.db).Query() if err != nil { return nil, err } + // we need to pass a new pointer of the parent identifier type so the + // resultset can fill it and we can know to which record it belongs when + // indexing by parent id. + return indexedResultsFromRows(rows, cols, rel.Schema, rfk, identType.newPtr()) +} + +// indexedResultsFromRows returns the results in the given rows indexed by the +// parent id. In the case of many to many relationships, the record odes not +// have a specific field with the ID of the parent to index by it, +// that's why parentIDPtr is passed for these cases. parentIDPtr is a pointer +// to an ID of the type required by the parent to be filled by the result set. +func indexedResultsFromRows(rows *sql.Rows, cols []string, schema Schema, fk SchemaField, parentIDPtr interface{}) (indexedRecords, error) { relRs := NewResultSet(rows, false, nil, cols...) var indexedResults = make(indexedRecords) for relRs.Next() { - rec, err := relRs.Get(rel.Schema) - if err != nil { - return nil, err + var ( + rec Record + err error + ) + + if parentIDPtr != nil { + rec, err = relRs.customGet(schema, parentIDPtr) + } else { + rec, err = relRs.Get(schema) } - val, err := rec.Value(fk.String()) if err != nil { return nil, err } rec.setPersisted() rec.setWritable(true) - id := val.(Identifier).Raw() + + var id interface{} + if parentIDPtr != nil { + id = parentIDPtr.(Identifier).Raw() + } else { + val, err := rec.Value(fk.String()) + if err != nil { + return nil, err + } + + id = val.(Identifier).Raw() + } + indexedResults[id] = append(indexedResults[id], rec) } diff --git a/benchmarks/kallax.go b/benchmarks/kallax.go index adc58b0..0e7e586 100644 --- a/benchmarks/kallax.go +++ b/benchmarks/kallax.go @@ -122,12 +122,12 @@ func (s *PersonStore) DebugWith(logger kallax.LoggerFunc) *PersonStore { func (s *PersonStore) relationshipRecords(record *Person) []kallax.RecordWithSchema { var records []kallax.RecordWithSchema - for _, rec := range record.Pets { - rec.ClearVirtualColumns() - rec.AddVirtualColumn("person_id", record.GetID()) + for i := range record.Pets { + record.Pets[i].ClearVirtualColumns() + record.Pets[i].AddVirtualColumn("person_id", record.GetID()) records = append(records, kallax.RecordWithSchema{ Schema: Schema.Pet.BaseSchema, - Record: rec, + Record: record.Pets[i], }) } @@ -137,12 +137,10 @@ func (s *PersonStore) relationshipRecords(record *Person) []kallax.RecordWithSch // Insert inserts a Person in the database. A non-persisted object is // required for this operation. func (s *PersonStore) Insert(record *Person) error { - records := s.relationshipRecords(record) if len(records) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - if err := s.Insert(Schema.Person.BaseSchema, record); err != nil { return err } @@ -167,7 +165,6 @@ func (s *PersonStore) Insert(record *Person) error { } return s.Store.Insert(Schema.Person.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -177,12 +174,10 @@ func (s *PersonStore) Insert(record *Person) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *PersonStore) Update(record *Person, cols ...kallax.SchemaField) (updated int64, err error) { - records := s.relationshipRecords(record) if len(records) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - updated, err = s.Update(Schema.Person.BaseSchema, record, cols...) if err != nil { return err @@ -213,7 +208,6 @@ func (s *PersonStore) Update(record *Person, cols ...kallax.SchemaField) (update } return s.Store.Update(Schema.Person.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -233,9 +227,7 @@ func (s *PersonStore) Save(record *Person) (updated bool, err error) { // Delete removes the given record from the database. func (s *PersonStore) Delete(record *Person) error { - return s.Store.Delete(Schema.Person.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -641,6 +633,8 @@ func (r *Pet) ColumnAddress(col string) (interface{}, error) { return &r.Name, nil case "kind": return (*string)(&r.Kind), nil + case "person_id": + return types.Nullable(kallax.VirtualColumn("person_id", r, new(kallax.NumericID))), nil default: return nil, fmt.Errorf("kallax: invalid column in Pet: %s", col) @@ -656,6 +650,8 @@ func (r *Pet) Value(col string) (interface{}, error) { return r.Name, nil case "kind": return (string)(r.Kind), nil + case "person_id": + return r.Model.VirtualColumn(col), nil default: return nil, fmt.Errorf("kallax: invalid column in Pet: %s", col) @@ -710,9 +706,7 @@ func (s *PetStore) DebugWith(logger kallax.LoggerFunc) *PetStore { // Insert inserts a Pet in the database. A non-persisted object is // required for this operation. func (s *PetStore) Insert(record *Pet) error { - return s.Store.Insert(Schema.Pet.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -722,9 +716,7 @@ func (s *PetStore) Insert(record *Pet) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *PetStore) Update(record *Pet, cols ...kallax.SchemaField) (updated int64, err error) { - return s.Store.Update(Schema.Pet.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -744,9 +736,7 @@ func (s *PetStore) Save(record *Pet) (updated bool, err error) { // Delete removes the given record from the database. func (s *PetStore) Delete(record *Pet) error { - return s.Store.Delete(Schema.Pet.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -1070,7 +1060,9 @@ var Schema = &schema{ "__person", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Pets": kallax.NewForeignKey("person_id", false), + "Pets": []*kallax.ForeignKey{ + kallax.NewForeignKey("person_id", false), + }, }, func() kallax.Record { return new(Person) @@ -1095,6 +1087,7 @@ var Schema = &schema{ kallax.NewSchemaField("id"), kallax.NewSchemaField("name"), kallax.NewSchemaField("kind"), + kallax.NewSchemaField("person_id"), ), ID: kallax.NewSchemaField("id"), Name: kallax.NewSchemaField("name"), diff --git a/benchmarks/models_kallax.go b/benchmarks/models_kallax.go index 62f89c3..a9eebe7 100644 --- a/benchmarks/models_kallax.go +++ b/benchmarks/models_kallax.go @@ -2,6 +2,8 @@ package benchmark import kallax "gopkg.in/src-d/go-kallax.v1" +//go:generate kallax gen + type Person struct { kallax.Model `table:"people"` ID int64 `pk:"autoincr"` diff --git a/common_test.go b/common_test.go index 828f169..5d42fe9 100644 --- a/common_test.go +++ b/common_test.go @@ -26,28 +26,49 @@ func openTestDB() (*sql.DB, error) { )) } -func setupTables(t *testing.T, db *sql.DB) { - _, err := db.Exec(`CREATE TABLE IF NOT EXISTS model ( +var tableSchemas = []string{ + `CREATE TABLE IF NOT EXISTS model ( id serial PRIMARY KEY, name varchar(255) not null, email varchar(255) not null, age int not null - )`) - require.NoError(t, err) - - _, err = db.Exec(`CREATE TABLE IF NOT EXISTS rel ( + )`, + `CREATE TABLE IF NOT EXISTS rel ( id serial PRIMARY KEY, model_id integer, foo text - )`) - require.NoError(t, err) + )`, + `CREATE TABLE IF NOT EXISTS through_left ( + id serial PRIMARY KEY, + name text not null + )`, + `CREATE TABLE IF NOT EXISTS through_right ( + id serial PRIMARY KEY, + name text not null + )`, + `CREATE TABLE IF NOT EXISTS through_middle ( + id serial PRIMARY KEY, + left_id bigint references through_left(id), + right_id bigint references through_right(id) + )`, +} + +func setupTables(t *testing.T, db *sql.DB) { + for _, ts := range tableSchemas { + _, err := db.Exec(ts) + require.NoError(t, err) + } +} + +var tableNames = []string{ + "rel", "model", "through_middle", "through_left", "through_right", } func teardownTables(t *testing.T, db *sql.DB) { - _, err := db.Exec("DROP TABLE model") - require.NoError(t, err) - _, err = db.Exec("DROP TABLE rel") - require.NoError(t, err) + for _, tn := range tableNames { + _, err := db.Exec(fmt.Sprintf("DROP TABLE %s", tn)) + require.NoError(t, err) + } } type model struct { @@ -225,9 +246,9 @@ var ModelSchema = NewBaseSchema( "__model", f("id"), ForeignKeys{ - "rel": NewForeignKey("model_id", false), - "rels": NewForeignKey("model_id", false), - "rel_inv": NewForeignKey("model_id", true), + "rel": []*ForeignKey{NewForeignKey("model_id", false)}, + "rels": []*ForeignKey{NewForeignKey("model_id", false)}, + "rel_inv": []*ForeignKey{NewForeignKey("model_id", true)}, }, func() Record { return new(model) @@ -265,6 +286,253 @@ var onlyPkModelSchema = NewBaseSchema( f("id"), ) +type throughLeft struct { + Model + ID int64 + Name string + Rights []*throughRight +} + +func newThroughLeft(name string) *throughLeft { + m := &throughLeft{Model: NewModel(), Name: name} + return m +} + +func (m *throughLeft) Value(col string) (interface{}, error) { + switch col { + case "id": + return m.ID, nil + case "name": + return m.Name, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughLeft) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return &m.ID, nil + case "name": + return &m.Name, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughLeft) NewRelationshipRecord(field string) (Record, error) { + switch field { + case "Rights": + return new(throughRight), nil + } + return nil, fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughLeft) SetRelationship(field string, record interface{}) error { + switch field { + case "Rights": + rels, ok := record.([]Record) + if !ok { + return fmt.Errorf("kallax: can't set relationship %s with value of type %T", field, record) + } + m.Rights = make([]*throughRight, len(rels)) + for i, r := range rels { + rel, ok := r.(*throughRight) + if !ok { + return fmt.Errorf("kallax: can't set element of relationship %s with element of type %T", field, r) + } + m.Rights[i] = rel + } + return nil + } + return fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughLeft) GetID() Identifier { + return (*NumericID)(&m.ID) +} + +type throughMiddle struct { + Model + ID int64 + Left *throughLeft + Right *throughRight +} + +func newThroughMiddle(left *throughLeft, right *throughRight) *throughMiddle { + m := &throughMiddle{Model: NewModel(), Left: left, Right: right} + return m +} + +func (m *throughMiddle) Value(col string) (interface{}, error) { + switch col { + case "id": + return m.ID, nil + case "left_id": + return m.Left.ID, nil + case "right_id": + return m.Right.ID, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughMiddle) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return &m.ID, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughMiddle) NewRelationshipRecord(field string) (Record, error) { + switch field { + case "Left": + return new(throughLeft), nil + case "Right": + return new(throughRight), nil + } + return nil, fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughMiddle) SetRelationship(field string, record interface{}) error { + switch field { + case "Left": + rel, ok := record.(*throughLeft) + if !ok { + return fmt.Errorf("kallax: can't set relationship %s with a record of type %t", field, record) + } + m.Left = rel + return nil + case "Right": + rel, ok := record.(*throughRight) + if !ok { + return fmt.Errorf("kallax: can't set relationship %s with a record of type %t", field, record) + } + m.Right = rel + return nil + } + return fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughMiddle) GetID() Identifier { + return (*NumericID)(&m.ID) +} + +type throughRight struct { + Model + ID int64 + Name string + Lefts []*throughLeft +} + +func newThroughRight(name string) *throughRight { + m := &throughRight{Model: NewModel(), Name: name} + return m +} + +func (m *throughRight) Value(col string) (interface{}, error) { + switch col { + case "id": + return m.ID, nil + case "name": + return m.Name, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughRight) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return &m.ID, nil + case "name": + return &m.Name, nil + } + return nil, fmt.Errorf("kallax: column does not exist: %s", col) +} + +func (m *throughRight) NewRelationshipRecord(field string) (Record, error) { + switch field { + case "Lefts": + return new(throughLeft), nil + } + return nil, fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughRight) SetRelationship(field string, record interface{}) error { + switch field { + case "Lefts": + rels, ok := record.([]Record) + if !ok { + return fmt.Errorf("kallax: can't set relationship %s with value of type %T", field, record) + } + m.Lefts = make([]*throughLeft, len(rels)) + for i, r := range rels { + rel, ok := r.(*throughLeft) + if !ok { + return fmt.Errorf("kallax: can't set element of relationship %s with element of type %T", field, r) + } + m.Lefts[i] = rel + } + return nil + } + return fmt.Errorf("kallax: no relationship found for field %s", field) +} + +func (m *throughRight) GetID() Identifier { + return (*NumericID)(&m.ID) +} + +var ThroughLeftSchema = NewBaseSchema( + "through_left", + "__thleft", + f("id"), + ForeignKeys{ + "Rights": []*ForeignKey{ + NewForeignKey("left_id", false), + NewForeignKey("right_id", false), + }, + }, + func() Record { + return new(throughLeft) + }, + true, + f("id"), + f("name"), +) + +var ThroughMiddleSchema = NewBaseSchema( + "through_middle", + "__thmiddle", + f("id"), + ForeignKeys{ + "Left": []*ForeignKey{NewForeignKey("left_id", false)}, + "Right": []*ForeignKey{NewForeignKey("right_id", false)}, + }, + func() Record { + return new(throughMiddle) + }, + true, + f("id"), + f("left_id"), + f("right_id"), +) + +var ThroughRightSchema = NewBaseSchema( + "through_right", + "__thright", + f("id"), + ForeignKeys{ + "Lefts": []*ForeignKey{ + NewForeignKey("right_id", false), + NewForeignKey("left_id", false), + }, + }, + func() Record { + return new(throughRight) + }, + true, + f("id"), + f("name"), +) + func f(name string) SchemaField { return NewSchemaField(name) } diff --git a/generator/cli/kallax/cmd.go b/generator/cli/kallax/cmd.go index 8ff9549..6b40dbd 100644 --- a/generator/cli/kallax/cmd.go +++ b/generator/cli/kallax/cmd.go @@ -8,7 +8,7 @@ import ( "gopkg.in/urfave/cli.v1" ) -const version = "1.2.11" +const version = "1.2.13" func main() { newApp().Run(os.Args) diff --git a/generator/common_test.go b/generator/common_test.go index e71d9ec..1bb2998 100644 --- a/generator/common_test.go +++ b/generator/common_test.go @@ -10,8 +10,8 @@ import ( parseutil "gopkg.in/src-d/go-parse-utils.v1" ) -func mkField(name, typ string, fields ...*Field) *Field { - f := NewField(name, typ, reflect.StructTag("")) +func mkField(name, typ, tag string, fields ...*Field) *Field { + f := NewField(name, typ, reflect.StructTag(tag)) f.SetFields(fields) return f } @@ -46,13 +46,9 @@ func withNode(f *Field, name string, typ types.Type) *Field { return f } -func withTag(f *Field, tag string) *Field { - f.Tag = reflect.StructTag(tag) - return f -} - func inline(f *Field) *Field { - return withTag(f, `kallax:",inline"`) + f.Tag = reflect.StructTag(`kallax:",inline"`) + return f } func processorFixture(source string) (*Processor, error) { diff --git a/generator/processor.go b/generator/processor.go index d3f3b67..ee58f83 100644 --- a/generator/processor.go +++ b/generator/processor.go @@ -161,6 +161,11 @@ func (p *Processor) processPackage() (*Package, error) { if err := pkg.addMissingRelationships(); err != nil { return nil, err } + + if err := pkg.addThroughModels(); err != nil { + return nil, err + } + for _, ctor := range ctors { p.tryMatchConstructor(pkg, ctor) } @@ -201,11 +206,11 @@ func (p *Processor) processModel(name string, s *types.Struct, t *types.Named) ( return nil, nil } + p.processBaseField(m, fields[base]) if err := m.SetFields(fields); err != nil { return nil, err } - p.processBaseField(m, fields[base]) return m, nil } diff --git a/generator/processor_test.go b/generator/processor_test.go index 579f059..1931ed9 100644 --- a/generator/processor_test.go +++ b/generator/processor_test.go @@ -384,11 +384,15 @@ func (s *ProcessorSuite) TestIsEmbedded() { type Bar struct { kallax.Model ID int64 ` + "`pk:\"autoincr\"`" + ` - Bar string + Baz string } type Struct struct { - Bar Bar + Qux Bar + } + + type Struct2 struct { + Mux string } type Foo struct { @@ -396,7 +400,7 @@ func (s *ProcessorSuite) TestIsEmbedded() { ID int64 ` + "`pk:\"autoincr\"`" + ` A Bar B *Bar - Bar + Struct2 *Struct C struct { D int @@ -405,21 +409,16 @@ func (s *ProcessorSuite) TestIsEmbedded() { ` pkg := s.processFixture(src) m := findModel(pkg, "Foo") - cases := []struct { - field string - embedded bool - }{ - {"Model", true}, - {"A", false}, - {"B", false}, - {"Bar", true}, - {"Struct", true}, - {"C", false}, + expected := []string{ + "ID", "Model", "A", "B", "Mux", "Qux", "C", } - for _, c := range cases { - s.Equal(c.embedded, findField(m, c.field).IsEmbedded, c.field) + var names []string + for _, f := range m.Fields { + names = append(names, f.Name) } + + s.Equal(expected, names) } func TestProcessor(t *testing.T) { diff --git a/generator/template.go b/generator/template.go index bc4f3a1..13953f0 100644 --- a/generator/template.go +++ b/generator/template.go @@ -233,6 +233,27 @@ func (td *TemplateData) findJSONSchemas(parent string, f *Field) { } } +const fkTpl = `kallax.NewForeignKey("%s", %s)` + +func (td *TemplateData) GenForeignKeys(f *Field) string { + var fks []string + if f.IsManyToManyRelationship() { + fks = append( + fks, + fmt.Sprintf(fkTpl, f.LeftForeignKey(), "true"), + fmt.Sprintf(fkTpl, f.RightForeignKey(), "true"), + ) + } else { + fks = append(fks, fmt.Sprintf( + fkTpl, + f.ForeignKey(), + fmt.Sprint(f.IsInverse()), + )) + } + + return strings.Join(fks, ", ") +} + // GenTypeName generates the name of the type in the field. func (td *TemplateData) GenTypeName(f *Field) string { if name, ok := findNamed(f.Node.Type(), td.pkg); ok { @@ -464,7 +485,10 @@ func prettyfy(input []byte, wr io.Writer) error { return err } - _, err = wr.Write(output) + out := strings.Replace(string(output), "{\n\n", "{\n", -1) + out = strings.Replace(out, "\n\n}", "\n}", -1) + + _, err = wr.Write([]byte(out)) return err } @@ -509,14 +533,16 @@ func addTemplate(base *template.Template, name string, filename string) *templat return template.Must(base.New(name).Parse(text)) } -var base *template.Template = makeTemplate("base", "templates/base.tgo") -var schema *template.Template = addTemplate(base, "schema", "templates/schema.tgo") -var model *template.Template = addTemplate(base, "model", "templates/model.tgo") -var query *template.Template = addTemplate(model, "query", "templates/query.tgo") -var resultset *template.Template = addTemplate(model, "resultset", "templates/resultset.tgo") +var ( + base = makeTemplate("base", "templates/base.tgo") + schema = addTemplate(base, "schema", "templates/schema.tgo") + model = addTemplate(base, "model", "templates/model.tgo") + query = addTemplate(model, "query", "templates/query.tgo") + resultset = addTemplate(model, "resultset", "templates/resultset.tgo") +) // Base is the default Template instance with all templates preloaded. -var Base *Template = &Template{template: base} +var Base = &Template{template: base} const ( // tplFindByCollection is the template of the FindBy autogenerated for @@ -524,7 +550,7 @@ const ( // The passed values to the FindBy will be used in an kallax.ArrayContains tplFindByCollection = ` // FindBy%[1]s adds a new filter to the query that will require that - // the %[1]s property contains all the passed values; if no passed values, + // the %[1]s property contains all the passed values; if no passed values, // it will do nothing. func (q *%[2]s) FindBy%[1]s(v ...%[3]s) *%[2]s { if len(v) == 0 {return q} @@ -552,7 +578,7 @@ const ( // The passed values to the FindBy will be used in an kallax.In condition. tplFindByID = ` // FindBy%[1]s adds a new filter to the query that will require that - // the %[1]s property is equal to one of the passed values; if no passed values, + // the %[1]s property is equal to one of the passed values; if no passed values, // it will do nothing. func (q *%[2]s) FindBy%[1]s(v ...%[3]s) *%[2]s { if len(v) == 0 {return q} @@ -598,6 +624,10 @@ func (td *TemplateData) genFindBy(buf *bytes.Buffer, parent *Model, fields []*Fi } } +func (td *TemplateData) IsMany(f *Field) bool { + return isSliceOrArray(f) +} + func writeFindByTpl(buf *bytes.Buffer, parent *Model, name string, f *Field, tpl string) { findableTypeName, ok := f.typeName() if !ok { @@ -706,10 +736,9 @@ func shortName(pkg *types.Package, typ types.Type) string { if specialName, ok := specialTypeShortName(typ); ok { return prefix + specialName - } else { - shortName := typeString(typ, pkg) - return prefix + strings.Replace(shortName, "*", "", -1) } + shortName := typeString(typ, pkg) + return prefix + strings.Replace(shortName, "*", "", -1) } // isEqualizable returns true if the autogenerated FindBy will use an equal query diff --git a/generator/template_test.go b/generator/template_test.go index 5910ab2..bd0aca8 100644 --- a/generator/template_test.go +++ b/generator/template_test.go @@ -437,6 +437,61 @@ func (s *TemplateSuite) TestGenTimeTruncations() { s.Equal(expectedTimeTruncations, s.td.GenTimeTruncations(m)) } +func (s *TemplateSuite) TestGenForeignKeys() { + s.processSource(` + package foo + + import "gopkg.in/src-d/go-kallax.v1" + + type Foo struct { + kallax.Model + ID int64 ` + "`pk:\"autoincr\"`" + ` + Multiple *Bar ` + "`through:\"baz\"`" + ` + Rel *Qux + RelInverse *Mux ` + "`fk:\",inverse\"`" + ` + } + + type Baz struct { + kallax.Model + ID int64 ` + "`pk:\"autoincr\"`" + ` + Foo *Foo ` + "`fk:\",inverse\"`" + ` + Bar *Bar ` + "`fk:\",inverse\"`" + ` + } + + type Bar struct { + kallax.Model + ID int64 ` + "`pk:\"autoincr\"`" + ` + } + + type Qux struct { + kallax.Model + ID int64 ` + "`pk:\"autoincr\"`" + ` + } + + type Mux struct { + kallax.Model + ID int64 ` + "`pk:\"autoincr\"`" + ` + Foo *Foo + } + `) + + m := findModel(s.td.Package, "Foo") + f := findField(m, "Multiple") + s.Equal(expectedMultipleFKs, s.td.GenForeignKeys(f)) + + f = findField(m, "Rel") + s.Equal(expectedSingleFKNoInverse, s.td.GenForeignKeys(f)) + + f = findField(m, "RelInverse") + s.Equal(expectedSingleFKInverse, s.td.GenForeignKeys(f)) +} + +const ( + expectedMultipleFKs = `kallax.NewForeignKey("foo_id", true), kallax.NewForeignKey("bar_id", true)` + expectedSingleFKNoInverse = `kallax.NewForeignKey("foo_id", false)` + expectedSingleFKInverse = `kallax.NewForeignKey("mux_id", true)` +) + func (s *TemplateSuite) TestExecute() { s.processSource(baseTpl) var buf bytes.Buffer diff --git a/generator/templates/model.tgo b/generator/templates/model.tgo index ff60d0e..3195029 100644 --- a/generator/templates/model.tgo +++ b/generator/templates/model.tgo @@ -51,32 +51,54 @@ func (r *{{.Name}}) NewRelationshipRecord(field string) (kallax.Record, error) { func (r *{{.Name}}) SetRelationship(field string, rel interface{}) error { {{if .Relationships -}} switch field { - {{range .Relationships}}{{if not .IsOneToManyRelationship}}case "{{.Name}}": - val, ok := rel.(*{{$.GenTypeName .}}) - if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship {{.Name}}", rel) - } - {{if .IsPtr}}if !val.GetID().IsEmpty() { - r.{{.Name}} = val - } - {{else}}r.{{.Name}} = *val{{end}} - return nil - {{else}}case "{{.Name}}": - records, ok := rel.([]kallax.Record) - if !ok { - return fmt.Errorf("kallax: relationship field %s needs a collection of records, not %T", field, rel) - } + {{range .Relationships}} + case "{{.Name}}": + {{if and (.IsManyToManyRelationship) (not ($.IsMany .)) -}} + recs, ok := rel.([]kallax.Record) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship {{.Name}}", recs) + } - r.{{.Name}} = make([]{{if $.IsPtrSlice .}}*{{end}}{{$.GenTypeName .}}, len(records)) - for i, record := range records { - rel, ok := record.(*{{$.GenTypeName . }}) + if len(recs) > 1 { + return fmt.Errorf("kallax: can't assign %d records to the relationship {{.Name}}. Only one record was expected", len(recs)) + } + + if len(recs) > 0 { + val, ok := recs[0].(*{{$.GenTypeName .}}) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship {{.Name}}", recs[0]) + } + r.{{.Name}} = {{if not .IsPtr}}*{{end}}val + } + + return nil + {{else if not .IsOneToManyRelationship -}} + val, ok := rel.(*{{$.GenTypeName .}}) if !ok { - return fmt.Errorf("kallax: element of type %T cannot be added to relationship %s", record, field) + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship {{.Name}}", rel) } - r.{{.Name}}[i] = {{if not ($.IsPtrSlice .)}}*{{end}}rel - } - return nil - {{end}}{{end}} + {{if .IsPtr}}if !val.GetID().IsEmpty() { + r.{{.Name}} = val + } + {{else}}r.{{.Name}} = *val{{end}} + return nil + {{else -}} + records, ok := rel.([]kallax.Record) + if !ok { + return fmt.Errorf("kallax: relationship field %s needs a collection of records, not %T", field, rel) + } + + r.{{.Name}} = make([]{{if $.IsPtrSlice .}}*{{end}}{{$.GenTypeName .}}, len(records)) + for i, record := range records { + rel, ok := record.(*{{$.GenTypeName . }}) + if !ok { + return fmt.Errorf("kallax: element of type %T cannot be added to relationship %s", record, field) + } + r.{{.Name}}[i] = {{if not ($.IsPtrSlice .)}}*{{end}}rel + } + return nil + {{end}} + {{end}} } return fmt.Errorf("kallax: model {{.Name}} has no relationship %s", field) {{- else -}} diff --git a/generator/templates/query.tgo b/generator/templates/query.tgo index e11b4e9..310dd82 100644 --- a/generator/templates/query.tgo +++ b/generator/templates/query.tgo @@ -1,5 +1,5 @@ -// {{.QueryName}} is the object used to create queries for the {{.Name}} +// {{.QueryName}} is the object used to create queries for the {{.Name}} // entity. type {{.QueryName}} struct { *kallax.BaseQuery @@ -68,15 +68,37 @@ func (q *{{.QueryName}}) Where(cond kallax.Condition) *{{.QueryName}} { } {{range .Relationships}} -{{if not .IsOneToManyRelationship}} -func (q *{{$.QueryName}}) With{{.Name}}() *{{$.QueryName}} { - q.AddRelation(Schema.{{.TypeSchemaName}}.BaseSchema, "{{.Name}}", kallax.OneToOne, nil) +{{if .IsManyToManyRelationship}} +// With{{.Name}} retrieves all the {{.Name}} records associated with each +// record. Two conditions can be passed, the first to filter the table used +// to join {{.Name}} and {{.Model.Name}} and the second one to filter +// {{.Name}} directly. +func (q *{{$.QueryName}}) With{{.Name}}( + filter{{.ThroughSchemaName}} kallax.Condition, + filter{{.TypeSchemaName}} kallax.Condition, +) *{{$.QueryName}} { + q.AddRelationThrough( + Schema.{{.TypeSchemaName}}.BaseSchema, + Schema.{{.ThroughSchemaName}}.BaseSchema, + "{{.Name}}", + filter{{.ThroughSchemaName}}, + filter{{.TypeSchemaName}}, + ) return q } -{{else}} +{{else if .IsOneToManyRelationship}} +// With{{.Name}} retrieves all the {{.Name}} records associated with each +// record. A condition can be passed to filter the associated records. func (q *{{$.QueryName}}) With{{.Name}}(cond kallax.Condition) *{{$.QueryName}} { q.AddRelation(Schema.{{.TypeSchemaName}}.BaseSchema, "{{.Name}}", kallax.OneToMany, cond) return q } +{{else}} +// With{{.Name}} retrieves the {{.Name}} record associated with each +// record. +func (q *{{$.QueryName}}) With{{.Name}}() *{{$.QueryName}} { + q.AddRelation(Schema.{{.TypeSchemaName}}.BaseSchema, "{{.Name}}", kallax.OneToOne, nil) + return q +} {{end}} {{end}} diff --git a/generator/templates/schema.tgo b/generator/templates/schema.tgo index d7a040f..94c6695 100644 --- a/generator/templates/schema.tgo +++ b/generator/templates/schema.tgo @@ -20,7 +20,10 @@ var Schema = &schema{ "{{.Alias}}", kallax.NewSchemaField("{{.ID.ColumnName}}"), kallax.ForeignKeys{ - {{range .Relationships}}"{{.Name}}": kallax.NewForeignKey("{{.ForeignKey}}", {{if .IsInverse}}true{{else}}false{{end}}), + {{range .Relationships}} + "{{.Name}}": []*kallax.ForeignKey{ + {{$.GenForeignKeys .}}, + }, {{end}} }, func() kallax.Record { diff --git a/generator/types.go b/generator/types.go index 2270785..66f421a 100644 --- a/generator/types.go +++ b/generator/types.go @@ -129,6 +129,7 @@ type Package struct { // Models are all the models found in the package. Models []*Model indexedModels map[string]*Model + modelsByTable map[string]*Model } // NewPackage creates a new package. @@ -137,6 +138,7 @@ func NewPackage(pkg *types.Package) *Package { Name: pkg.Name(), pkg: pkg, indexedModels: make(map[string]*Model), + modelsByTable: make(map[string]*Model), } } @@ -144,6 +146,7 @@ func NewPackage(pkg *types.Package) *Package { func (p *Package) SetModels(models []*Model) { for _, m := range models { p.indexedModels[m.Name] = m + p.modelsByTable[m.Table] = m } p.Models = models } @@ -153,20 +156,41 @@ func (p *Package) FindModel(name string) *Model { return p.indexedModels[name] } -func (p *Package) addMissingRelationships() error { +func (p *Package) forEachModelField(fn func(m *Model, f *Field) error) error { for _, m := range p.Models { for _, f := range m.Fields { - if f.Kind == Relationship && !f.IsInverse() { - if err := p.trySetFK(f.TypeSchemaName(), f); err != nil { - return err - } + if err := fn(m, f); err != nil { + return err } } } - return nil } +func (p *Package) addThroughModels() error { + return p.forEachModelField(func(m *Model, f *Field) error { + if f.IsManyToManyRelationship() { + model, ok := p.modelsByTable[f.ThroughTable()] + if !ok { + return fmt.Errorf("kallax: cannot find a model with table name %s to access field %s of model %s", f.ThroughTable(), f.Name, m.Name) + } + f.ThroughModel = model + } + return nil + }) +} + +func (p *Package) addMissingRelationships() error { + return p.forEachModelField(func(m *Model, f *Field) error { + if f.Kind == Relationship && !f.IsInverse() && !f.IsManyToManyRelationship() { + if err := p.trySetFK(f.TypeSchemaName(), f); err != nil { + return err + } + } + return nil + }) +} + func (p *Package) trySetFK(model string, fk *Field) error { m := p.FindModel(model) if m == nil { @@ -470,15 +494,20 @@ func (m *Model) CtorRetVars() string { return strings.Join(ret, ", ") } -// SetFields sets all the children fields and their model to the current model. +// SetFields sets all the children fields and their model to the current +// model. // It also finds the primary key and sets it in the model. // It will return an error if more than one primary key is found. +// SetFields always sets the primary key as the first field of the model. +// So, all models can expect to have the primary key in the position 0 of +// their field slice. This is because the Store will expect the ID in that +// position. func (m *Model) SetFields(fields []*Field) error { var fs []*Field var id *Field - for _, f := range fields { + for _, f := range flattenFields(fields) { f.Model = m - if f.IsPrimaryKey() { + if f.IsPrimaryKey() && f.Type != BaseModel { if id != nil { return fmt.Errorf( "kallax: found more than one primary key in model %s: %s and %s", @@ -489,14 +518,56 @@ func (m *Model) SetFields(fields []*Field) error { } id = f - m.ID = f + } else if f.IsPrimaryKey() { + if f.primaryKey == "" { + return fmt.Errorf( + "kallax: primary key defined in %s has no field name, but it must be specified", + f.Name, + ) + } + + // the pk is defined in the model, we need to collect the model + // and we'll look for the field afterwards, when we have collected + // all fields. The model is appended to the field set, though, + // because it will not act as a primary key. + id = f + fs = append(fs, f) } else { fs = append(fs, f) } } + // if the id is a Model we need to look for the specified field + if id != nil && id.Type == BaseModel { + for i, f := range fs { + if f.columnName == id.primaryKey { + f.isPrimaryKey = true + f.isAutoincrement = id.isAutoincrement + id = f + + if len(fs)-1 == i { + fs = append(fs[:i]) + } else { + fs = append(fs[:i], fs[i+1:]...) + } + break + } + } + + // If the ID is still a base model, means we did not find the pk + // field. + if id.Type == BaseModel { + return fmt.Errorf( + "kallax: the primary key was supposed to be %s according to the pk definition in %s, but the field could not be found", + id.primaryKey, + id.Name, + ) + } + } + if id != nil { m.Fields = []*Field{id} + m.ID = id } m.Fields = append(m.Fields, fs...) return nil @@ -556,12 +627,16 @@ func relationshipsOnFields(fields []*Field) []*Field { return result } +// ImplicitFK is a foreign key that is defined on just one side of the +// relationship and needs to be added on the other side. type ImplicitFK struct { Name string Type string } // Field is the representation of a model field. +// TODO(erizocosmico): please, refactor all this structure to use precomputed +// data instead of calculating it upon each call. type Field struct { // Name is the field name. Name string @@ -580,6 +655,9 @@ type Field struct { Parent *Field // Model is the reference to the model containing this field. Model *Model + // ThroughModel is the reference to the model through which the field is + // accessed in a relationship. + ThroughModel *Model // IsPtr reports whether the field is a pointer type or not. IsPtr bool // IsJSON reports whether the field has to be converted to JSON. @@ -590,6 +668,11 @@ type Field struct { // A struct is considered embedded if and only if the struct was embedded // as defined in Go. IsEmbedded bool + + primaryKey string + isPrimaryKey bool + isAutoincrement bool + columnName string } // FieldKind is the kind of a field. @@ -645,11 +728,47 @@ func (t FieldKind) String() string { // NewField creates a new field with its name, type and struct tag. func NewField(n, t string, tag reflect.StructTag) *Field { + pkName, autoincr, isPrimaryKey := pkProperties(tag) + return &Field{ Name: n, Type: t, Tag: tag, + + primaryKey: pkName, + columnName: columnName(n, tag), + isPrimaryKey: isPrimaryKey, + isAutoincrement: autoincr, + } +} + +// pkProperties returns the primary key properties from a struct tag. +// Valid primary key definitions are the following: +// - pk:"" -> non-autoincr primary key without a field name. +// - pk:"autoincr" -> autoincr primary key without a field name. +// - pk:"foobar" -> non-autoincr primary key with a field name. +// - pk:"foobar,autoincr" -> autoincr primary key with a field name. +func pkProperties(tag reflect.StructTag) (name string, autoincr, isPrimaryKey bool) { + val, ok := tag.Lookup("pk") + if !ok { + return + } + + isPrimaryKey = true + if val == "autoincr" || val == "" { + if val == "autoincr" { + autoincr = true + } + return + } + + parts := strings.Split(val, ",") + name = parts[0] + if len(parts) > 1 && parts[1] == "autoincr" { + autoincr = true } + + return } // SetFields sets all the children fields and the current field as a parent of @@ -667,16 +786,20 @@ func (f *Field) SetFields(sf []*Field) { // is the field name converted to lower snake case. // If the resultant name is a reserved keyword a _ will be prepended to the name. func (f *Field) ColumnName() string { - name := strings.TrimSpace(strings.Split(f.Tag.Get("kallax"), ",")[0]) - if name == "" { - name = toLowerSnakeCase(f.Name) + return f.columnName +} + +func columnName(name string, tag reflect.StructTag) string { + n := strings.TrimSpace(strings.Split(tag.Get("kallax"), ",")[0]) + if n == "" { + n = toLowerSnakeCase(name) } - if _, ok := reservedKeywords[strings.ToLower(name)]; ok { - name = "_" + name + if _, ok := reservedKeywords[strings.ToLower(n)]; ok { + n = "_" + n } - return name + return n } // ForeignKey returns the name of the foreign keys as specified in the struct @@ -699,13 +822,12 @@ func (f *Field) ForeignKey() string { // IsPrimaryKey reports whether the field is the primary key. func (f *Field) IsPrimaryKey() bool { - _, ok := f.Tag.Lookup("pk") - return ok + return f.isPrimaryKey } // IsAutoIncrement reports whether the field is an autoincrementable primary key. func (f *Field) IsAutoIncrement() bool { - return f.Tag.Get("pk") == "autoincr" + return f.isAutoincrement } // IsInverse returns whether the field is an inverse relationship. @@ -714,8 +836,12 @@ func (f *Field) IsInverse() bool { return false } - for _, part := range strings.Split(f.Tag.Get("fk"), ",") { - if part == "inverse" { + if f.IsManyToManyRelationship() { + return f.isInverseThrough() + } + + for i, part := range strings.Split(f.Tag.Get("fk"), ",") { + if i > 0 && part == "inverse" { return true } } @@ -729,6 +855,58 @@ func (f *Field) IsOneToManyRelationship() bool { return f.Kind == Relationship && strings.HasPrefix(f.Type, "[]") } +// IsManyToManyRelationship reports whether the field is a many to many +// relationship. +func (f *Field) IsManyToManyRelationship() bool { + return f.Kind == Relationship && f.Tag.Get("through") != "" +} + +// ThroughTable returns the name of the intermediate table used to access the +// current field. +func (f *Field) ThroughTable() string { + return f.getThroughTablePart(0) +} + +// LeftForeignKey is the name of the column used to join the current model with +// the intermediate table. +func (f *Field) LeftForeignKey() string { + fk := f.getThroughTablePart(1) + if fk == "" { + fk = foreignKeyForModel(f.Model.Name) + } + return fk +} + +// RightForeignKey is the name of the column used to join the relationship +// model with the intermediate table. +func (f *Field) RightForeignKey() string { + fk := f.getThroughTablePart(2) + if fk == "" { + fk = foreignKeyForModel(f.TypeSchemaName()) + } + return fk +} + +func (f *Field) isInverseThrough() bool { + return f.getThroughPart(1) == "inverse" +} + +func (f *Field) getThroughPart(idx int) string { + parts := strings.Split(f.Tag.Get("through"), ",") + if len(parts) > idx { + return strings.TrimSpace(parts[idx]) + } + return "" +} + +func (f *Field) getThroughTablePart(idx int) string { + parts := strings.Split(f.getThroughPart(0), ":") + if len(parts) > idx { + return strings.TrimSpace(parts[idx]) + } + return "" +} + func foreignKeyForModel(model string) string { return toLowerSnakeCase(model) + "_id" } @@ -867,6 +1045,11 @@ func (f *Field) TypeSchemaName() string { return parts[len(parts)-1] } +// ThroughSchemaName returns the name of the Schema for the through model type. +func (f *Field) ThroughSchemaName() string { + return f.ThroughModel.Name +} + func (f *Field) SQLType() string { return f.Tag.Get("sqltype") } @@ -1003,6 +1186,22 @@ func toLowerSnakeCase(s string) string { return buf.String() } +// flattenFields will recursively flatten all fields removing the embedded ones +// from the field set. +func flattenFields(fields []*Field) []*Field { + var result = make([]*Field, 0, len(fields)) + + for _, f := range fields { + if f.IsEmbedded && f.Type != BaseModel { + result = append(result, flattenFields(f.Fields)...) + } else { + result = append(result, f) + } + } + + return result +} + // Event is the name of an event. type Event string diff --git a/generator/types_test.go b/generator/types_test.go index 3a0bf03..8049607 100644 --- a/generator/types_test.go +++ b/generator/types_test.go @@ -37,7 +37,7 @@ func (s *FieldSuite) TestInline() { } for _, c := range cases { - s.Equal(c.inline, withTag(mkField("", c.typ), c.tag).Inline(), "field with tag: %s", c.tag) + s.Equal(c.inline, mkField("", c.typ, c.tag).Inline(), "field with tag: %s", c.tag) } } @@ -55,7 +55,7 @@ func (s *FieldSuite) TestIsPrimaryKey() { } for _, c := range cases { - s.Equal(c.ok, withTag(mkField("", ""), c.tag).IsPrimaryKey(), "field with tag: %s", c.tag) + s.Equal(c.ok, mkField("", "", c.tag).IsPrimaryKey(), "field with tag: %s", c.tag) } } @@ -71,7 +71,7 @@ func (s *FieldSuite) TestIsAutoIncrement() { } for _, c := range cases { - s.Equal(c.ok, withTag(mkField("", ""), c.tag).IsAutoIncrement(), "field with tag: %s", c.tag) + s.Equal(c.ok, mkField("", "", c.tag).IsAutoIncrement(), "field with tag: %s", c.tag) } } @@ -91,7 +91,7 @@ func (s *FieldSuite) TestColumnName() { } for _, c := range cases { - name := withTag(mkField(c.name, ""), c.tag).ColumnName() + name := mkField(c.name, "", c.tag).ColumnName() s.Equal(c.expected, name, "field with name: %q and tag: %s", c.name, c.tag) } } @@ -135,13 +135,13 @@ func (s *FieldSuite) TestAddress() { "types.Nullable(r.Foo)", }, { - Basic, false, true, "Foo", "", withParent(mkField("Bar", ""), mkField("Baz", "")), + Basic, false, true, "Foo", "", withParent(mkField("Bar", "", ""), mkField("Baz", "", "")), "types.Nullable(&r.Baz.Bar.Foo)", }, } for i, c := range cases { - f := withKind(withParent(mkField(c.name, c.typeStr), c.parent), c.kind) + f := withKind(withParent(mkField(c.name, c.typeStr, ""), c.parent), c.kind) if c.isJSON { f = withJSON(f) } @@ -160,31 +160,31 @@ func (s *FieldSuite) TestValue() { expected string }{ { - mkField("Foo", "string"), + mkField("Foo", "string", ""), "r.Foo, nil", }, { - withAlias(mkField("Foo", "string")), + withAlias(mkField("Foo", "string", "")), "(string)(r.Foo), nil", }, { - withPtr(withAlias(mkField("Foo", "string"))), + withPtr(withAlias(mkField("Foo", "string", ""))), "(*string)(r.Foo), nil", }, { - withKind(mkField("Foo", ""), Slice), + withKind(mkField("Foo", "", ""), Slice), "types.Slice(r.Foo), nil", }, { - withKind(mkField("Foo", "[5]string"), Array), + withKind(mkField("Foo", "[5]string", ""), Array), `types.Array(&r.Foo, 5), nil`, }, { - withJSON(withKind(mkField("Foo", ""), Map)), + withJSON(withKind(mkField("Foo", "", ""), Map)), "types.JSON(r.Foo), nil", }, { - withKind(mkField("Foo", ""), Struct), + withKind(mkField("Foo", "", ""), Struct), "r.Foo, nil", }, } @@ -194,6 +194,79 @@ func (s *FieldSuite) TestValue() { } } +func (s *FieldSuite) TestIsInverse() { + cases := []struct { + tag string + expected bool + }{ + {"", false}, + {`inverse:"true"`, false}, + {`fk:"inverse"`, false}, + {`through:"inverse"`, false}, + {`fk:"foo,inverse"`, true}, + {`fk:",inverse"`, true}, + {`through:"foo,inverse"`, true}, + {`through:"foo:a:b,inverse"`, true}, + } + + for _, tt := range cases { + f := mkField("", "", tt.tag) + f.Kind = Relationship + s.Equal(tt.expected, f.IsInverse(), tt.tag) + } +} + +func (s *FieldSuite) TestThroughTable() { + cases := []struct { + tag, expected string + }{ + {``, ""}, + {`through:"foo"`, "foo"}, + {`through:"foo,inverse"`, "foo"}, + {`through:"foo:a:b,inverse"`, "foo"}, + } + + for _, tt := range cases { + s.Equal(tt.expected, mkField("", "", tt.tag).ThroughTable(), tt.tag) + } +} + +func (s *FieldSuite) TestLeftForeignKey() { + cases := []struct { + tag, expected string + }{ + {``, "bar_id"}, + {`through:"foo"`, "bar_id"}, + {`through:"foo,inverse"`, "bar_id"}, + {`through:"foo:a,inverse"`, "a"}, + {`through:"foo:a:b,inverse"`, "a"}, + } + + for _, tt := range cases { + f := mkField("", "", tt.tag) + f.Model = &Model{Name: "Bar"} + s.Equal(tt.expected, f.LeftForeignKey(), tt.tag) + } +} + +func (s *FieldSuite) TestRightForeignKey() { + cases := []struct { + tag, expected string + }{ + {``, "foo_id"}, + {`through:"foo"`, "foo_id"}, + {`through:"foo,inverse"`, "foo_id"}, + {`through:"foo:a,inverse"`, "foo_id"}, + {`through:"foo:a:b,inverse"`, "b"}, + } + + for _, tt := range cases { + f := mkField("", "", tt.tag) + f.Type = "Foo" + s.Equal(tt.expected, f.RightForeignKey(), tt.tag) + } +} + type ModelSuite struct { suite.Suite model *Model @@ -211,8 +284,8 @@ import ( ) type User struct { - kallax.Model ` + "`table:\"users\"`" + ` - ID kallax.ULID ` + "`pk:\"\"`" + ` + kallax.Model ` + "`table:\"users\" pk:\"id\"`" + ` + ID kallax.ULID Username string Email string Password Password @@ -321,16 +394,16 @@ func (s *ModelSuite) TestModelValidate() { id := s.model.ID m := &Model{Name: "Foo", Table: "foo", ID: id} m.Fields = []*Field{ - mkField("ID", ""), - inline(mkField("Nested", "", inline( - mkField("Deep", "", mkField("ID", "")), + mkField("ID", "", ""), + inline(mkField("Nested", "", "", inline( + mkField("Deep", "", "", mkField("ID", "", "")), ))), } require.Error(m.Validate(), "should return error") m.Fields = []*Field{ - mkField("ID", ""), - inline(mkField("Nested", "", mkField("Foo", ""))), + mkField("ID", "", ""), + inline(mkField("Nested", "", "", mkField("Foo", "", ""))), } require.NoError(m.Validate(), "should not return error") @@ -379,22 +452,53 @@ func TestModelSetFields(t *testing.T) { name string fields []*Field err bool + id string }{ { "only one primary key", []*Field{ - mkField("Foo", ""), - withTag(mkField("ID", ""), `pk:""`), + mkField("Foo", "", ""), + mkField("ID", "", `pk:""`), }, false, + "ID", }, { "multiple primary keys", []*Field{ - withTag(mkField("ID", ""), `pk:""`), - withTag(mkField("FooID", ""), `pk:""`), + mkField("ID", "", `pk:""`), + mkField("FooID", "", `pk:""`), + }, + true, + "", + }, + { + "primary key defined in model but empty", + []*Field{ + mkField("Model", BaseModel, `pk:""`), + }, + true, + "", + }, + { + "primary key defined in model and non existent", + []*Field{ + mkField("Model", BaseModel, `pk:"foo"`), + mkField("Bar", "", ""), }, true, + "", + }, + { + "primary key defined in model", + []*Field{ + mkField("Model", BaseModel, `pk:"foo"`), + mkField("Baz", "", ""), + mkField("Foo", "", ""), + mkField("Bar", "", ""), + }, + false, + "Foo", }, } @@ -405,6 +509,7 @@ func TestModelSetFields(t *testing.T) { r.Error(err, c.name) } else { r.NoError(err, c.name) + r.Equal(c.id, m.ID.Name) } } } @@ -412,3 +517,27 @@ func TestModelSetFields(t *testing.T) { func TestModel(t *testing.T) { suite.Run(t, new(ModelSuite)) } + +func TestPkProperties(t *testing.T) { + cases := []struct { + tag string + name string + autoincr bool + isPrimaryKey bool + }{ + {`pk:"bar"`, "bar", false, true}, + {`pk:""`, "", false, true}, + {`pk:"autoincr"`, "", true, true}, + {`pk:",autoincr"`, "", true, true}, + {`bar:"baz" pk:"foo"`, "foo", false, true}, + {`pk:"foo,autoincr"`, "foo", true, true}, + } + + require := require.New(t) + for _, tt := range cases { + name, autoincr, isPrimaryKey := pkProperties(reflect.StructTag(tt.tag)) + require.Equal(tt.name, name, tt.tag) + require.Equal(tt.autoincr, autoincr, tt.tag) + require.Equal(tt.isPrimaryKey, isPrimaryKey, tt.tag) + } +} diff --git a/model.go b/model.go index 95abde4..1a16947 100644 --- a/model.go +++ b/model.go @@ -113,6 +113,7 @@ type Identifier interface { IsEmpty() bool // Raw returns the internal value of the identifier. Raw() interface{} + newPtr() interface{} } // Identifiable must be implemented by those values that can be identified by an ID. @@ -225,6 +226,10 @@ func NewULIDFromText(text string) (ULID, error) { return id, err } +func (id ULID) newPtr() interface{} { + return new(ULID) +} + // Scan implements the Scanner interface. func (id *ULID) Scan(src interface{}) error { switch src := src.(type) { @@ -371,6 +376,10 @@ func (id NumericID) IsEmpty() bool { return int64(id) == 0 } +func (id NumericID) newPtr() interface{} { + return new(NumericID) +} + // String returns the string representation of the ID. func (id NumericID) String() string { return fmt.Sprint(int64(id)) @@ -407,6 +416,10 @@ func (id UUID) Value() (driver.Value, error) { return uuid.UUID(id).Value() } +func (id UUID) newPtr() interface{} { + return new(UUID) +} + // IsEmpty returns whether the ID is empty or not. An empty ID means it has not // been set yet. func (id UUID) IsEmpty() bool { diff --git a/query.go b/query.go index 2b93459..507751d 100644 --- a/query.go +++ b/query.go @@ -7,11 +7,7 @@ import ( "github.com/Masterminds/squirrel" ) -var ( - // ErrManyToManyNotSupported is returned when a many to many relationship - // is added to a query. - ErrManyToManyNotSupported = errors.New("kallax: many to many relationships are not supported") -) +var ErrThroughNotSupported = errors.New("kallax: a relationship of type Through cannot be added using AddRelation, you need to use AddRelationThrough") // Query is the common interface all queries must satisfy. The basic abilities // of a query are compiling themselves to something executable and return @@ -164,8 +160,8 @@ func (q *BaseQuery) selectedColumns() []SchemaField { // in the given field of the query base schema. A condition to filter can also // be passed in the case of one to many relationships. func (q *BaseQuery) AddRelation(schema Schema, field string, typ RelationshipType, filter Condition) error { - if typ == ManyToMany { - return ErrManyToManyNotSupported + if typ == Through { + return ErrThroughNotSupported } fk, ok := q.schema.ForeignKey(field) @@ -181,10 +177,19 @@ func (q *BaseQuery) AddRelation(schema Schema, field string, typ RelationshipTyp q.join(schema, fk) } - q.relationships = append(q.relationships, Relationship{typ, field, schema, filter}) + q.relationships = append(q.relationships, Relationship{typ, field, schema, nil, filter, nil}) return nil } +// AddRelationThrough adds a relationship through an intermediate table +// if given to the query, which is present in the given field of the query +// base schema. Conditions to filter in the intermediate table and the end +// table can also be passed. +func (q *BaseQuery) AddRelationThrough(schema, intermediateSchema Schema, field string, intermediateFilter, endFilter Condition) { + schema = schema.WithAlias(field) + q.relationships = append(q.relationships, Relationship{Through, field, schema, intermediateSchema, endFilter, intermediateFilter}) +} + func (q *BaseQuery) join(schema Schema, fk *ForeignKey) { fkCol := fk.QualifiedName(schema) idCol := q.schema.ID().QualifiedName(q.schema) @@ -209,6 +214,27 @@ func (q *BaseQuery) join(schema Schema, fk *ForeignKey) { } } +func (q *BaseQuery) joinThrough(lschema, intSchema, rschema Schema, lfk, rfk *ForeignKey) { + lfkCol := lfk.QualifiedName(intSchema) + rfkCol := rfk.QualifiedName(intSchema) + lidCol := lschema.ID().QualifiedName(lschema) + ridCol := rschema.ID().QualifiedName(rschema) + + q.builder = q.builder.Join(fmt.Sprintf( + "%s %s ON (%s = %s)", + intSchema.Table(), + intSchema.Alias(), + rfkCol, + ridCol, + )).Join(fmt.Sprintf( + "%s %s ON (%s = %s)", + lschema.Table(), + lschema.Alias(), + lfkCol, + lidCol, + )) +} + // Order adds the given order clauses to the list of columns to order the // results by. func (q *BaseQuery) Order(cols ...ColumnOrder) { @@ -256,7 +282,11 @@ func (q *BaseQuery) GetOffset() uint64 { // q.Where(Gt(AgeColumn, 18)) // // ... WHERE name = "foo" AND age > 18 func (q *BaseQuery) Where(cond Condition) { - q.builder = q.builder.Where(cond(q.schema)) + q.where(cond, q.schema) +} + +func (q *BaseQuery) where(cond Condition, schema Schema) { + q.builder = q.builder.Where(cond(schema)) } // compile returns the selected column names and the select builder. diff --git a/query_test.go b/query_test.go index 4fd7191..55cb959 100644 --- a/query_test.go +++ b/query_test.go @@ -92,9 +92,9 @@ func (s *QuerySuite) TestAddRelation_Inverse() { s.Equal("SELECT __model.id, __model.name, __model.email, __model.age, __rel_rel_inv.id, __rel_rel_inv.model_id, __rel_rel_inv.foo FROM model __model LEFT JOIN rel __rel_rel_inv ON (__rel_rel_inv.id = __model.model_id)", s.q.String()) } -func (s *QuerySuite) TestAddRelation_ManyToMany() { - err := s.q.AddRelation(RelSchema, "rel", ManyToMany, nil) - s.Equal(ErrManyToManyNotSupported, err) +func (s *QuerySuite) TestAddRelation_Through() { + err := s.q.AddRelation(RelSchema, "rel", Through, nil) + s.Equal(ErrThroughNotSupported, err) } func (s *QuerySuite) TestAddRelation_FKNotFound() { diff --git a/resultset.go b/resultset.go index 5f02ac5..ae3527c 100644 --- a/resultset.go +++ b/resultset.go @@ -51,15 +51,19 @@ func NewResultSet(rows *sql.Rows, readOnly bool, relationships []Relationship, c // Get returns the next record in the schema. func (rs *BaseResultSet) Get(schema Schema) (Record, error) { + return rs.customGet(schema) +} + +func (rs *BaseResultSet) customGet(schema Schema, extra ...interface{}) (Record, error) { record := schema.New() - if err := rs.Scan(record); err != nil { + if err := rs.Scan(record, extra...); err != nil { return nil, err } return record, nil } // Scan fills the column fields of the given value with the current row. -func (rs *BaseResultSet) Scan(record Record) error { +func (rs *BaseResultSet) Scan(record Record, extra ...interface{}) error { if len(rs.columns) == 0 { return ErrRawScan } @@ -95,6 +99,7 @@ func (rs *BaseResultSet) Scan(record Record) error { relationships[i] = rec } + pointers = append(pointers, extra...) if err := rs.Rows.Scan(pointers...); err != nil { return err } diff --git a/schema.go b/schema.go index 5e62379..d0a4f5e 100644 --- a/schema.go +++ b/schema.go @@ -18,6 +18,9 @@ type Schema interface { Columns() []SchemaField // ForeignKey returns the name of the foreign key of the given model field. ForeignKey(string) (*ForeignKey, bool) + // ForeignKeys returns the name of both of the foreign keys involved in a + // relationship through an intermediate table. + ForeignKeys(string) (left *ForeignKey, right *ForeignKey, ok bool) // WithAlias returns a new schema with the given string added to the // default alias. // Calling WithAlias on a schema returned by WithAlias not return a @@ -61,8 +64,18 @@ func (s *BaseSchema) Table() string { return s.table } func (s *BaseSchema) ID() SchemaField { return s.id } func (s *BaseSchema) Columns() []SchemaField { return s.columns } func (s *BaseSchema) ForeignKey(field string) (*ForeignKey, bool) { - k, ok := s.foreignKeys[field] - return k, ok + k := s.foreignKeys[field] + if len(k) > 0 { + return k[0], true + } + return nil, false +} +func (s *BaseSchema) ForeignKeys(field string) (*ForeignKey, *ForeignKey, bool) { + k := s.foreignKeys[field] + if len(k) == 2 { + return k[0], k[1], true + } + return nil, nil, false } func (s *BaseSchema) WithAlias(field string) Schema { return &aliasSchema{s, field} @@ -82,7 +95,7 @@ func (s *aliasSchema) Alias() string { } // ForeignKeys is a mapping between relationships and their foreign key field. -type ForeignKeys map[string]*ForeignKey +type ForeignKeys map[string][]*ForeignKey // SchemaField is a named field in the table schema. type SchemaField interface { @@ -215,7 +228,7 @@ func AtJSONPath(field SchemaField, typ JSONKeyType, path ...string) SchemaField return NewJSONSchemaKey(typ, field.String(), path...) } -// Relationship is a relationship with its schema and the field of te relation +// Relationship is a relationship with its schema and the field of the relation // in the record. type Relationship struct { // Type is the kind of relationship this is. @@ -224,9 +237,15 @@ type Relationship struct { Field string // Schema is the schema of the relationship. Schema Schema + // IntermediateSchema is the schema of the intermediate table used for + // matching models in the relationship. Only used in Through relationships. + IntermediateSchema Schema // Filter establishes the filter to be applied when retrieving rows of the // relationships. Filter Condition + // IntermediateFilter is a filter to be applied on the intermediate table when + // retrieving rows of the relationship. Only used in Through relationships. + IntermediateFilter Condition } // RelationshipType describes the type of the relationship. @@ -239,10 +258,10 @@ const ( // OneToMany is a relationship between one record in a table and multiple // in another table. OneToMany - // ManyToMany is a relationship between many records on both sides of the - // relationship. - // NOTE: It is not supported yet. - ManyToMany + // Through is a relationship that needs an intermediate table to relate + // both sides of the relationship. + // Typically a many to many. + Through ) func containsRelationshipOfType(rels []Relationship, typ RelationshipType) bool { diff --git a/store.go b/store.go index 5eab953..2e6c96c 100644 --- a/store.go +++ b/store.go @@ -306,7 +306,8 @@ func (s *Store) RawExec(sql string, params ...interface{}) (int64, error) { // Find performs a query and returns a result set with the results. func (s *Store) Find(q Query) (ResultSet, error) { rels := q.getRelationships() - if containsRelationshipOfType(rels, OneToMany) { + if containsRelationshipOfType(rels, OneToMany) || + containsRelationshipOfType(rels, Through) { return NewBatchingResultSet(newBatchQueryRunner(q.Schema(), s.proxy, q)), nil } diff --git a/store_test.go b/store_test.go index 378bf50..41119b2 100644 --- a/store_test.go +++ b/store_test.go @@ -544,6 +544,111 @@ func (s *StoreSuite) TestFind_1toNMultiple() { s.Equal(100, i) } +func (s *StoreSuite) Fixtures_NtoM() { + require := s.Require() + + lefts := []*throughLeft{ + newThroughLeft("a"), + newThroughLeft("b"), + newThroughLeft("c"), + } + + for _, l := range lefts { + require.NoError(s.store.Insert(ThroughLeftSchema, l)) + } + + rights := []*throughRight{ + newThroughRight("d"), + newThroughRight("e"), + newThroughRight("f"), + } + + for _, r := range rights { + require.NoError(s.store.Insert(ThroughRightSchema, r)) + } + + middles := []*throughMiddle{ + newThroughMiddle(lefts[0], rights[0]), + newThroughMiddle(lefts[0], rights[1]), + newThroughMiddle(lefts[1], rights[0]), + newThroughMiddle(lefts[1], rights[1]), + newThroughMiddle(lefts[2], rights[1]), + newThroughMiddle(lefts[2], rights[2]), + } + + for _, m := range middles { + require.NoError(s.store.Insert(ThroughMiddleSchema, m)) + } +} + +func (s *StoreSuite) TestFind_NtoM() { + require := s.Require() + s.Fixtures_NtoM() + + q := NewBaseQuery(ThroughLeftSchema) + q.AddRelationThrough(ThroughRightSchema, ThroughMiddleSchema, "Rights", nil, nil) + rs, err := s.store.Debug().Find(q) + require.NoError(err) + + var results []*throughLeft + for rs.Next() { + r, err := rs.Get(ThroughLeftSchema) + require.NoError(err) + results = append(results, r.(*throughLeft)) + } + + require.Equal(3, len(results)) + + var result = make(map[string][]string) + for _, l := range results { + var rights []string + for _, r := range l.Rights { + rights = append(rights, r.Name) + } + result[l.Name] = rights + } + + require.Equal(map[string][]string{ + "a": {"d", "e"}, + "b": {"d", "e"}, + "c": {"e", "f"}, + }, result) +} + +func (s *StoreSuite) TestFind_NtoM_Inverse() { + require := s.Require() + s.Fixtures_NtoM() + + q := NewBaseQuery(ThroughRightSchema) + q.AddRelationThrough(ThroughLeftSchema, ThroughMiddleSchema, "Lefts", nil, nil) + rs, err := s.store.Debug().Find(q) + require.NoError(err) + + var results []*throughRight + for rs.Next() { + r, err := rs.Get(ThroughRightSchema) + require.NoError(err) + results = append(results, r.(*throughRight)) + } + + require.Equal(3, len(results)) + + var result = make(map[string][]string) + for _, r := range results { + var lefts []string + for _, r := range r.Lefts { + lefts = append(lefts, r.Name) + } + result[r.Name] = lefts + } + + require.Equal(map[string][]string{ + "d": {"a", "b"}, + "e": {"a", "b", "c"}, + "f": {"c"}, + }, result) +} + func (s *StoreSuite) assertModel(m *model) { var result model err := s.db.QueryRow("SELECT id, name, email, age FROM model WHERE id = $1", m.GetID()). diff --git a/tests/kallax.go b/tests/kallax.go index 3982146..21c72a1 100644 --- a/tests/kallax.go +++ b/tests/kallax.go @@ -139,7 +139,6 @@ func (s *CarStore) inverseRecords(record *Car) []kallax.RecordWithSchema { // Insert inserts a Car in the database. A non-persisted object is // required for this operation. func (s *CarStore) Insert(record *Car) error { - if err := record.BeforeSave(); err != nil { return err } @@ -148,7 +147,6 @@ func (s *CarStore) Insert(record *Car) error { if len(inverseRecords) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -187,7 +185,6 @@ func (s *CarStore) Insert(record *Car) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -197,7 +194,6 @@ func (s *CarStore) Insert(record *Car) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *CarStore) Update(record *Car, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeSave(); err != nil { return 0, err } @@ -206,7 +202,6 @@ func (s *CarStore) Update(record *Car, cols ...kallax.SchemaField) (updated int6 if len(inverseRecords) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -257,7 +252,6 @@ func (s *CarStore) Update(record *Car, cols ...kallax.SchemaField) (updated int6 return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -277,7 +271,6 @@ func (s *CarStore) Save(record *Car) (updated bool, err error) { // Delete removes the given record from the database. func (s *CarStore) Delete(record *Car) error { - if err := record.BeforeDelete(); err != nil { return err } @@ -290,7 +283,6 @@ func (s *CarStore) Delete(record *Car) error { return record.AfterDelete() }) - } // Find returns the set of results for the given query. @@ -455,6 +447,8 @@ func (q *CarQuery) Where(cond kallax.Condition) *CarQuery { return q } +// WithOwner retrieves the Owner record associated with each +// record. func (q *CarQuery) WithOwner() *CarQuery { q.AddRelation(Schema.Person.BaseSchema, "Owner", kallax.OneToOne, nil) return q @@ -682,9 +676,7 @@ func (s *ChildStore) DebugWith(logger kallax.LoggerFunc) *ChildStore { // Insert inserts a Child in the database. A non-persisted object is // required for this operation. func (s *ChildStore) Insert(record *Child) error { - return s.Store.Insert(Schema.Child.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -694,9 +686,7 @@ func (s *ChildStore) Insert(record *Child) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *ChildStore) Update(record *Child, cols ...kallax.SchemaField) (updated int64, err error) { - return s.Store.Update(Schema.Child.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -716,9 +706,7 @@ func (s *ChildStore) Save(record *Child) (updated bool, err error) { // Delete removes the given record from the database. func (s *ChildStore) Delete(record *Child) error { - return s.Store.Delete(Schema.Child.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -1103,7 +1091,6 @@ func (s *EventsAllFixtureStore) DebugWith(logger kallax.LoggerFunc) *EventsAllFi // Insert inserts a EventsAllFixture in the database. A non-persisted object is // required for this operation. func (s *EventsAllFixtureStore) Insert(record *EventsAllFixture) error { - if err := record.BeforeSave(); err != nil { return err } @@ -1127,7 +1114,6 @@ func (s *EventsAllFixtureStore) Insert(record *EventsAllFixture) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -1137,7 +1123,6 @@ func (s *EventsAllFixtureStore) Insert(record *EventsAllFixture) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *EventsAllFixtureStore) Update(record *EventsAllFixture, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeSave(); err != nil { return 0, err } @@ -1167,7 +1152,6 @@ func (s *EventsAllFixtureStore) Update(record *EventsAllFixture, cols ...kallax. return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -1187,9 +1171,7 @@ func (s *EventsAllFixtureStore) Save(record *EventsAllFixture) (updated bool, er // Delete removes the given record from the database. func (s *EventsAllFixtureStore) Delete(record *EventsAllFixture) error { - return s.Store.Delete(Schema.EventsAllFixture.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -1568,7 +1550,6 @@ func (s *EventsFixtureStore) DebugWith(logger kallax.LoggerFunc) *EventsFixtureS // Insert inserts a EventsFixture in the database. A non-persisted object is // required for this operation. func (s *EventsFixtureStore) Insert(record *EventsFixture) error { - if err := record.BeforeInsert(); err != nil { return err } @@ -1584,7 +1565,6 @@ func (s *EventsFixtureStore) Insert(record *EventsFixture) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -1594,7 +1574,6 @@ func (s *EventsFixtureStore) Insert(record *EventsFixture) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *EventsFixtureStore) Update(record *EventsFixture, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeUpdate(); err != nil { return 0, err } @@ -1616,7 +1595,6 @@ func (s *EventsFixtureStore) Update(record *EventsFixture, cols ...kallax.Schema return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -1636,9 +1614,7 @@ func (s *EventsFixtureStore) Save(record *EventsFixture) (updated bool, err erro // Delete removes the given record from the database. func (s *EventsFixtureStore) Delete(record *EventsFixture) error { - return s.Store.Delete(Schema.EventsFixture.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -2017,7 +1993,6 @@ func (s *EventsSaveFixtureStore) DebugWith(logger kallax.LoggerFunc) *EventsSave // Insert inserts a EventsSaveFixture in the database. A non-persisted object is // required for this operation. func (s *EventsSaveFixtureStore) Insert(record *EventsSaveFixture) error { - if err := record.BeforeSave(); err != nil { return err } @@ -2033,7 +2008,6 @@ func (s *EventsSaveFixtureStore) Insert(record *EventsSaveFixture) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -2043,7 +2017,6 @@ func (s *EventsSaveFixtureStore) Insert(record *EventsSaveFixture) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *EventsSaveFixtureStore) Update(record *EventsSaveFixture, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeSave(); err != nil { return 0, err } @@ -2065,7 +2038,6 @@ func (s *EventsSaveFixtureStore) Update(record *EventsSaveFixture, cols ...kalla return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -2085,9 +2057,7 @@ func (s *EventsSaveFixtureStore) Save(record *EventsSaveFixture) (updated bool, // Delete removes the given record from the database. func (s *EventsSaveFixtureStore) Delete(record *EventsSaveFixture) error { - return s.Store.Delete(Schema.EventsSaveFixture.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -2476,9 +2446,7 @@ func (s *JSONModelStore) DebugWith(logger kallax.LoggerFunc) *JSONModelStore { // Insert inserts a JSONModel in the database. A non-persisted object is // required for this operation. func (s *JSONModelStore) Insert(record *JSONModel) error { - return s.Store.Insert(Schema.JSONModel.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -2488,9 +2456,7 @@ func (s *JSONModelStore) Insert(record *JSONModel) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *JSONModelStore) Update(record *JSONModel, cols ...kallax.SchemaField) (updated int64, err error) { - return s.Store.Update(Schema.JSONModel.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -2510,9 +2476,7 @@ func (s *JSONModelStore) Save(record *JSONModel) (updated bool, err error) { // Delete removes the given record from the database. func (s *JSONModelStore) Delete(record *JSONModel) error { - return s.Store.Delete(Schema.JSONModel.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -2901,7 +2865,6 @@ func (s *MultiKeySortFixtureStore) Insert(record *MultiKeySortFixture) error { record.End = record.End.Truncate(time.Microsecond) return s.Store.Insert(Schema.MultiKeySortFixture.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -2915,7 +2878,6 @@ func (s *MultiKeySortFixtureStore) Update(record *MultiKeySortFixture, cols ...k record.End = record.End.Truncate(time.Microsecond) return s.Store.Update(Schema.MultiKeySortFixture.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -2935,9 +2897,7 @@ func (s *MultiKeySortFixtureStore) Save(record *MultiKeySortFixture) (updated bo // Delete removes the given record from the database. func (s *MultiKeySortFixtureStore) Delete(record *MultiKeySortFixture) error { - return s.Store.Delete(Schema.MultiKeySortFixture.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -3354,7 +3314,6 @@ func (s *NullableStore) Insert(record *Nullable) error { } return s.Store.Insert(Schema.Nullable.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -3369,7 +3328,6 @@ func (s *NullableStore) Update(record *Nullable, cols ...kallax.SchemaField) (up } return s.Store.Update(Schema.Nullable.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -3389,9 +3347,7 @@ func (s *NullableStore) Save(record *Nullable) (updated bool, err error) { // Delete removes the given record from the database. func (s *NullableStore) Delete(record *Nullable) error { - return s.Store.Delete(Schema.Nullable.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -3812,12 +3768,10 @@ func (s *ParentStore) relationshipRecords(record *Parent) []kallax.RecordWithSch // Insert inserts a Parent in the database. A non-persisted object is // required for this operation. func (s *ParentStore) Insert(record *Parent) error { - records := s.relationshipRecords(record) if len(records) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - if err := s.Insert(Schema.Parent.BaseSchema, record); err != nil { return err } @@ -3842,7 +3796,6 @@ func (s *ParentStore) Insert(record *Parent) error { } return s.Store.Insert(Schema.Parent.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -3852,12 +3805,10 @@ func (s *ParentStore) Insert(record *Parent) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *ParentStore) Update(record *Parent, cols ...kallax.SchemaField) (updated int64, err error) { - records := s.relationshipRecords(record) if len(records) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - updated, err = s.Update(Schema.Parent.BaseSchema, record, cols...) if err != nil { return err @@ -3888,7 +3839,6 @@ func (s *ParentStore) Update(record *Parent, cols ...kallax.SchemaField) (update } return s.Store.Update(Schema.Parent.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -3908,9 +3858,7 @@ func (s *ParentStore) Save(record *Parent) (updated bool, err error) { // Delete removes the given record from the database. func (s *ParentStore) Delete(record *Parent) error { - return s.Store.Delete(Schema.Parent.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -4164,6 +4112,8 @@ func (q *ParentQuery) Where(cond kallax.Condition) *ParentQuery { return q } +// WithChildren retrieves all the Children records associated with each +// record. A condition can be passed to filter the associated records. func (q *ParentQuery) WithChildren(cond kallax.Condition) *ParentQuery { q.AddRelation(Schema.Child.BaseSchema, "Children", kallax.OneToMany, cond) return q @@ -4419,12 +4369,10 @@ func (s *ParentNoPtrStore) relationshipRecords(record *ParentNoPtr) []kallax.Rec // Insert inserts a ParentNoPtr in the database. A non-persisted object is // required for this operation. func (s *ParentNoPtrStore) Insert(record *ParentNoPtr) error { - records := s.relationshipRecords(record) if len(records) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - if err := s.Insert(Schema.ParentNoPtr.BaseSchema, record); err != nil { return err } @@ -4449,7 +4397,6 @@ func (s *ParentNoPtrStore) Insert(record *ParentNoPtr) error { } return s.Store.Insert(Schema.ParentNoPtr.BaseSchema, record) - } // Update updates the given record on the database. If the columns are given, @@ -4459,12 +4406,10 @@ func (s *ParentNoPtrStore) Insert(record *ParentNoPtr) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *ParentNoPtrStore) Update(record *ParentNoPtr, cols ...kallax.SchemaField) (updated int64, err error) { - records := s.relationshipRecords(record) if len(records) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - updated, err = s.Update(Schema.ParentNoPtr.BaseSchema, record, cols...) if err != nil { return err @@ -4495,7 +4440,6 @@ func (s *ParentNoPtrStore) Update(record *ParentNoPtr, cols ...kallax.SchemaFiel } return s.Store.Update(Schema.ParentNoPtr.BaseSchema, record, cols...) - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -4515,9 +4459,7 @@ func (s *ParentNoPtrStore) Save(record *ParentNoPtr) (updated bool, err error) { // Delete removes the given record from the database. func (s *ParentNoPtrStore) Delete(record *ParentNoPtr) error { - return s.Store.Delete(Schema.ParentNoPtr.BaseSchema, record) - } // Find returns the set of results for the given query. @@ -4771,6 +4713,8 @@ func (q *ParentNoPtrQuery) Where(cond kallax.Condition) *ParentNoPtrQuery { return q } +// WithChildren retrieves all the Children records associated with each +// record. A condition can be passed to filter the associated records. func (q *ParentNoPtrQuery) WithChildren(cond kallax.Condition) *ParentNoPtrQuery { q.AddRelation(Schema.Child.BaseSchema, "Children", kallax.OneToMany, cond) return q @@ -4971,6 +4915,7 @@ func (r *Person) SetRelationship(field string, rel interface{}) error { r.Pets[i] = rel } return nil + case "Car": val, ok := rel.(*Car) if !ok { @@ -5047,7 +4992,6 @@ func (s *PersonStore) relationshipRecords(record *Person) []kallax.RecordWithSch // Insert inserts a Person in the database. A non-persisted object is // required for this operation. func (s *PersonStore) Insert(record *Person) error { - if err := record.BeforeSave(); err != nil { return err } @@ -5056,7 +5000,6 @@ func (s *PersonStore) Insert(record *Person) error { if len(records) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - if err := s.Insert(Schema.Person.BaseSchema, record); err != nil { return err } @@ -5095,7 +5038,6 @@ func (s *PersonStore) Insert(record *Person) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -5105,7 +5047,6 @@ func (s *PersonStore) Insert(record *Person) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *PersonStore) Update(record *Person, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeSave(); err != nil { return 0, err } @@ -5114,7 +5055,6 @@ func (s *PersonStore) Update(record *Person, cols ...kallax.SchemaField) (update if len(records) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - updated, err = s.Update(Schema.Person.BaseSchema, record, cols...) if err != nil { return err @@ -5165,7 +5105,6 @@ func (s *PersonStore) Update(record *Person, cols ...kallax.SchemaField) (update return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -5185,7 +5124,6 @@ func (s *PersonStore) Save(record *Person) (updated bool, err error) { // Delete removes the given record from the database. func (s *PersonStore) Delete(record *Person) error { - if err := record.BeforeDelete(); err != nil { return err } @@ -5198,7 +5136,6 @@ func (s *PersonStore) Delete(record *Person) error { return record.AfterDelete() }) - } // Find returns the set of results for the given query. @@ -5483,11 +5420,15 @@ func (q *PersonQuery) Where(cond kallax.Condition) *PersonQuery { return q } +// WithPets retrieves all the Pets records associated with each +// record. A condition can be passed to filter the associated records. func (q *PersonQuery) WithPets(cond kallax.Condition) *PersonQuery { q.AddRelation(Schema.Pet.BaseSchema, "Pets", kallax.OneToMany, cond) return q } +// WithCar retrieves the Car record associated with each +// record. func (q *PersonQuery) WithCar() *PersonQuery { q.AddRelation(Schema.Car.BaseSchema, "Car", kallax.OneToOne, nil) return q @@ -5746,7 +5687,6 @@ func (s *PetStore) inverseRecords(record *Pet) []kallax.RecordWithSchema { // Insert inserts a Pet in the database. A non-persisted object is // required for this operation. func (s *PetStore) Insert(record *Pet) error { - if err := record.BeforeSave(); err != nil { return err } @@ -5755,7 +5695,6 @@ func (s *PetStore) Insert(record *Pet) error { if len(inverseRecords) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -5794,7 +5733,6 @@ func (s *PetStore) Insert(record *Pet) error { return nil }) - } // Update updates the given record on the database. If the columns are given, @@ -5804,7 +5742,6 @@ func (s *PetStore) Insert(record *Pet) error { // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. func (s *PetStore) Update(record *Pet, cols ...kallax.SchemaField) (updated int64, err error) { - if err := record.BeforeSave(); err != nil { return 0, err } @@ -5813,7 +5750,6 @@ func (s *PetStore) Update(record *Pet, cols ...kallax.SchemaField) (updated int6 if len(inverseRecords) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -5864,7 +5800,6 @@ func (s *PetStore) Update(record *Pet, cols ...kallax.SchemaField) (updated int6 return 0, err } return updated, nil - } // Save inserts the object if the record is not persisted, otherwise it updates @@ -5884,7 +5819,6 @@ func (s *PetStore) Save(record *Pet) (updated bool, err error) { // Delete removes the given record from the database. func (s *PetStore) Delete(record *Pet) error { - if err := record.BeforeDelete(); err != nil { return err } @@ -5897,7 +5831,6 @@ func (s *PetStore) Delete(record *Pet) error { return record.AfterDelete() }) - } // Find returns the set of results for the given query. @@ -6062,6 +5995,8 @@ func (q *PetQuery) Where(cond kallax.Condition) *PetQuery { return q } +// WithOwner retrieves the Owner record associated with each +// record. func (q *PetQuery) WithOwner() *PetQuery { q.AddRelation(Schema.Person.BaseSchema, "Owner", kallax.OneToOne, nil) return q @@ -6207,313 +6142,137 @@ func (rs *PetResultSet) Close() error { return rs.ResultSet.Close() } -// NewQueryFixture returns a new instance of QueryFixture. -func NewQueryFixture(f string) (record *QueryFixture) { - return newQueryFixture(f) +// NewPost returns a new instance of Post. +func NewPost(text string) (record *Post) { + return newPost(text) } // GetID returns the primary key of the model. -func (r *QueryFixture) GetID() kallax.Identifier { - return (*kallax.ULID)(&r.ID) +func (r *Post) GetID() kallax.Identifier { + return (*kallax.NumericID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *QueryFixture) ColumnAddress(col string) (interface{}, error) { +func (r *Post) ColumnAddress(col string) (interface{}, error) { switch col { case "id": - return (*kallax.ULID)(&r.ID), nil - case "inverse_id": - return types.Nullable(kallax.VirtualColumn("inverse_id", r, new(kallax.ULID))), nil - case "embedded": - return types.JSON(&r.Embedded), nil - case "inline": - return &r.Inline.Inline, nil - case "map_of_string": - return types.JSON(&r.MapOfString), nil - case "map_of_interface": - return types.JSON(&r.MapOfInterface), nil - case "map_of_some_type": - return types.JSON(&r.MapOfSomeType), nil - case "foo": - return &r.Foo, nil - case "string_property": - return &r.StringProperty, nil - case "integer": - return &r.Integer, nil - case "integer64": - return &r.Integer64, nil - case "float32": - return &r.Float32, nil - case "boolean": - return &r.Boolean, nil - case "array_param": - return types.Array(&r.ArrayParam, 3), nil - case "slice_param": - return types.Slice(&r.SliceParam), nil - case "alias_array_param": - return types.Array(&r.AliasArrayParam, 3), nil - case "alias_slice_param": - return types.Slice((*[]string)(&r.AliasSliceParam)), nil - case "alias_string_param": - return (*string)(&r.AliasStringParam), nil - case "alias_int_param": - return (*int)(&r.AliasIntParam), nil - case "dummy_param": - return types.JSON(&r.DummyParam), nil - case "alias_dummy_param": - return types.JSON(&r.AliasDummyParam), nil - case "slice_dummy_param": - return types.JSON(&r.SliceDummyParam), nil - case "idproperty_param": - return &r.IDPropertyParam, nil - case "interface_prop_param": - return &r.InterfacePropParam, nil - case "urlparam": - return (*types.URL)(&r.URLParam), nil - case "time_param": - return &r.TimeParam, nil - case "alias_arr_alias_string_param": - return types.Slice(&r.AliasArrAliasStringParam), nil - case "alias_here_array_param": - return types.Array(&r.AliasHereArrayParam, 3), nil - case "array_alias_here_string_param": - return types.Slice(&r.ArrayAliasHereStringParam), nil - case "scanner_valuer_param": - return &r.ScannerValuerParam, nil + return (*kallax.NumericID)(&r.ID), nil + case "text": + return &r.Text, nil default: - return nil, fmt.Errorf("kallax: invalid column in QueryFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in Post: %s", col) } } // Value returns the value of the given column. -func (r *QueryFixture) Value(col string) (interface{}, error) { +func (r *Post) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil - case "inverse_id": - return r.Model.VirtualColumn(col), nil - case "embedded": - return types.JSON(r.Embedded), nil - case "inline": - return r.Inline.Inline, nil - case "map_of_string": - return types.JSON(r.MapOfString), nil - case "map_of_interface": - return types.JSON(r.MapOfInterface), nil - case "map_of_some_type": - return types.JSON(r.MapOfSomeType), nil - case "foo": - return r.Foo, nil - case "string_property": - return r.StringProperty, nil - case "integer": - return r.Integer, nil - case "integer64": - return r.Integer64, nil - case "float32": - return r.Float32, nil - case "boolean": - return r.Boolean, nil - case "array_param": - return types.Array(&r.ArrayParam, 3), nil - case "slice_param": - return types.Slice(r.SliceParam), nil - case "alias_array_param": - return types.Array(&r.AliasArrayParam, 3), nil - case "alias_slice_param": - return types.Slice(r.AliasSliceParam), nil - case "alias_string_param": - return (string)(r.AliasStringParam), nil - case "alias_int_param": - return (int)(r.AliasIntParam), nil - case "dummy_param": - return types.JSON(r.DummyParam), nil - case "alias_dummy_param": - return types.JSON(r.AliasDummyParam), nil - case "slice_dummy_param": - return types.JSON(r.SliceDummyParam), nil - case "idproperty_param": - return r.IDPropertyParam, nil - case "interface_prop_param": - return r.InterfacePropParam, nil - case "urlparam": - return (*types.URL)(&r.URLParam), nil - case "time_param": - return r.TimeParam, nil - case "alias_arr_alias_string_param": - return types.Slice(r.AliasArrAliasStringParam), nil - case "alias_here_array_param": - return types.Array(&r.AliasHereArrayParam, 3), nil - case "array_alias_here_string_param": - return types.Slice(r.ArrayAliasHereStringParam), nil - case "scanner_valuer_param": - return r.ScannerValuerParam, nil + case "text": + return r.Text, nil default: - return nil, fmt.Errorf("kallax: invalid column in QueryFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in Post: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *QueryFixture) NewRelationshipRecord(field string) (kallax.Record, error) { +func (r *Post) NewRelationshipRecord(field string) (kallax.Record, error) { switch field { - case "Relation": - return new(QueryRelationFixture), nil - case "Inverse": - return new(QueryRelationFixture), nil - case "NRelation": - return new(QueryRelationFixture), nil + case "User": + return new(User), nil } - return nil, fmt.Errorf("kallax: model QueryFixture has no relationship %s", field) + return nil, fmt.Errorf("kallax: model Post has no relationship %s", field) } // SetRelationship sets the given relationship in the given field. -func (r *QueryFixture) SetRelationship(field string, rel interface{}) error { +func (r *Post) SetRelationship(field string, rel interface{}) error { switch field { - case "Relation": - val, ok := rel.(*QueryRelationFixture) - if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Relation", rel) - } - if !val.GetID().IsEmpty() { - r.Relation = val - } - - return nil - case "Inverse": - val, ok := rel.(*QueryRelationFixture) + case "User": + recs, ok := rel.([]kallax.Record) if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Inverse", rel) - } - if !val.GetID().IsEmpty() { - r.Inverse = val + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship User", recs) } - return nil - case "NRelation": - records, ok := rel.([]kallax.Record) - if !ok { - return fmt.Errorf("kallax: relationship field %s needs a collection of records, not %T", field, rel) + if len(recs) > 1 { + return fmt.Errorf("kallax: can't assign %d records to the relationship User. Only one record was expected", len(recs)) } - r.NRelation = make([]*QueryRelationFixture, len(records)) - for i, record := range records { - rel, ok := record.(*QueryRelationFixture) + if len(recs) > 0 { + val, ok := recs[0].(*User) if !ok { - return fmt.Errorf("kallax: element of type %T cannot be added to relationship %s", record, field) + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship User", recs[0]) } - r.NRelation[i] = rel + r.User = val } + return nil } - return fmt.Errorf("kallax: model QueryFixture has no relationship %s", field) + return fmt.Errorf("kallax: model Post has no relationship %s", field) } -// QueryFixtureStore is the entity to access the records of the type QueryFixture +// PostStore is the entity to access the records of the type Post // in the database. -type QueryFixtureStore struct { +type PostStore struct { *kallax.Store } -// NewQueryFixtureStore creates a new instance of QueryFixtureStore +// NewPostStore creates a new instance of PostStore // using a SQL database. -func NewQueryFixtureStore(db *sql.DB) *QueryFixtureStore { - return &QueryFixtureStore{kallax.NewStore(db)} +func NewPostStore(db *sql.DB) *PostStore { + return &PostStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *QueryFixtureStore) GenericStore() *kallax.Store { +func (s *PostStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *QueryFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *PostStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *QueryFixtureStore) Debug() *QueryFixtureStore { - return &QueryFixtureStore{s.Store.Debug()} +func (s *PostStore) Debug() *PostStore { + return &PostStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *QueryFixtureStore) DebugWith(logger kallax.LoggerFunc) *QueryFixtureStore { - return &QueryFixtureStore{s.Store.DebugWith(logger)} +func (s *PostStore) DebugWith(logger kallax.LoggerFunc) *PostStore { + return &PostStore{s.Store.DebugWith(logger)} } -func (s *QueryFixtureStore) relationshipRecords(record *QueryFixture) []kallax.RecordWithSchema { +func (s *PostStore) relationshipRecords(record *Post) []kallax.RecordWithSchema { var records []kallax.RecordWithSchema - if record.Relation != nil { - record.Relation.ClearVirtualColumns() - record.Relation.AddVirtualColumn("owner_id", record.GetID()) - records = append(records, kallax.RecordWithSchema{ - Schema: Schema.QueryRelationFixture.BaseSchema, - Record: record.Relation, - }) - } - - for i := range record.NRelation { - record.NRelation[i].ClearVirtualColumns() - record.NRelation[i].AddVirtualColumn("owner_id", record.GetID()) - records = append(records, kallax.RecordWithSchema{ - Schema: Schema.QueryRelationFixture.BaseSchema, - Record: record.NRelation[i], - }) - } - - return records -} - -func (s *QueryFixtureStore) inverseRecords(record *QueryFixture) []kallax.RecordWithSchema { - record.ClearVirtualColumns() - var records []kallax.RecordWithSchema - - if record.Inverse != nil { - record.AddVirtualColumn("inverse_id", record.Inverse.GetID()) + if record.User != nil { + record.User.ClearVirtualColumns() + record.User.AddVirtualColumn("post_id", record.GetID()) records = append(records, kallax.RecordWithSchema{ - Schema: Schema.QueryRelationFixture.BaseSchema, - Record: record.Inverse, + Schema: Schema.User.BaseSchema, + Record: record.User, }) } return records } -// Insert inserts a QueryFixture in the database. A non-persisted object is +// Insert inserts a Post in the database. A non-persisted object is // required for this operation. -func (s *QueryFixtureStore) Insert(record *QueryFixture) error { - record.TimeParam = record.TimeParam.Truncate(time.Microsecond) - +func (s *PostStore) Insert(record *Post) error { records := s.relationshipRecords(record) - inverseRecords := s.inverseRecords(record) - - if len(records) > 0 && len(inverseRecords) > 0 { + if len(records) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - - for _, r := range inverseRecords { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - if err := s.Insert(Schema.QueryFixture.BaseSchema, record); err != nil { + if err := s.Insert(Schema.Post.BaseSchema, record); err != nil { return err } @@ -6536,8 +6295,7 @@ func (s *QueryFixtureStore) Insert(record *QueryFixture) error { }) } - return s.Store.Insert(Schema.QueryFixture.BaseSchema, record) - + return s.Store.Insert(Schema.Post.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -6546,32 +6304,12 @@ func (s *QueryFixtureStore) Insert(record *QueryFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *QueryFixtureStore) Update(record *QueryFixture, cols ...kallax.SchemaField) (updated int64, err error) { - record.TimeParam = record.TimeParam.Truncate(time.Microsecond) - +func (s *PostStore) Update(record *Post, cols ...kallax.SchemaField) (updated int64, err error) { records := s.relationshipRecords(record) - inverseRecords := s.inverseRecords(record) - - if len(records) > 0 && len(inverseRecords) > 0 { + if len(records) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - - for _, r := range inverseRecords { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - updated, err = s.Update(Schema.QueryFixture.BaseSchema, record, cols...) + updated, err = s.Update(Schema.Post.BaseSchema, record, cols...) if err != nil { return err } @@ -6600,13 +6338,12 @@ func (s *QueryFixtureStore) Update(record *QueryFixture, cols ...kallax.SchemaFi return updated, nil } - return s.Store.Update(Schema.QueryFixture.BaseSchema, record, cols...) - + return s.Store.Update(Schema.Post.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *QueryFixtureStore) Save(record *QueryFixture) (updated bool, err error) { +func (s *PostStore) Save(record *Post) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -6620,43 +6357,41 @@ func (s *QueryFixtureStore) Save(record *QueryFixture) (updated bool, err error) } // Delete removes the given record from the database. -func (s *QueryFixtureStore) Delete(record *QueryFixture) error { - - return s.Store.Delete(Schema.QueryFixture.BaseSchema, record) - +func (s *PostStore) Delete(record *Post) error { + return s.Store.Delete(Schema.Post.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *QueryFixtureStore) Find(q *QueryFixtureQuery) (*QueryFixtureResultSet, error) { +func (s *PostStore) Find(q *PostQuery) (*PostResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewQueryFixtureResultSet(rs), nil + return NewPostResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *QueryFixtureStore) MustFind(q *QueryFixtureQuery) *QueryFixtureResultSet { - return NewQueryFixtureResultSet(s.Store.MustFind(q)) +func (s *PostStore) MustFind(q *PostQuery) *PostResultSet { + return NewPostResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *QueryFixtureStore) Count(q *QueryFixtureQuery) (int64, error) { +func (s *PostStore) Count(q *PostQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *QueryFixtureStore) MustCount(q *QueryFixtureQuery) int64 { +func (s *PostStore) MustCount(q *PostQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *QueryFixtureStore) FindOne(q *QueryFixtureQuery) (*QueryFixture, error) { +func (s *PostStore) FindOne(q *PostQuery) (*Post, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -6681,7 +6416,7 @@ func (s *QueryFixtureStore) FindOne(q *QueryFixtureQuery) (*QueryFixture, error) } // FindAll returns a list of all the rows returned by the given query. -func (s *QueryFixtureStore) FindAll(q *QueryFixtureQuery) ([]*QueryFixture, error) { +func (s *PostStore) FindAll(q *PostQuery) ([]*Post, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -6692,7 +6427,7 @@ func (s *QueryFixtureStore) FindAll(q *QueryFixtureQuery) ([]*QueryFixture, erro // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *QueryFixtureStore) MustFindOne(q *QueryFixtureQuery) *QueryFixture { +func (s *PostStore) MustFindOne(q *PostQuery) *Post { record, err := s.FindOne(q) if err != nil { panic(err) @@ -6700,30 +6435,30 @@ func (s *QueryFixtureStore) MustFindOne(q *QueryFixtureQuery) *QueryFixture { return record } -// Reload refreshes the QueryFixture with the data in the database and +// Reload refreshes the Post with the data in the database and // makes it writable. -func (s *QueryFixtureStore) Reload(record *QueryFixture) error { - return s.Store.Reload(Schema.QueryFixture.BaseSchema, record) +func (s *PostStore) Reload(record *Post) error { + return s.Store.Reload(Schema.Post.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *QueryFixtureStore) Transaction(callback func(*QueryFixtureStore) error) error { +func (s *PostStore) Transaction(callback func(*PostStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&QueryFixtureStore{store}) + return callback(&PostStore{store}) }) } -// RemoveRelation removes from the database the given relationship of the -// model. It also resets the field Relation of the model. -func (s *QueryFixtureStore) RemoveRelation(record *QueryFixture) error { - var r kallax.Record = record.Relation +// RemoveUser removes from the database the given relationship of the +// model. It also resets the field User of the model. +func (s *PostStore) RemoveUser(record *Post) error { + var r kallax.Record = record.User if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { if err := beforeDeleter.BeforeDelete(); err != nil { return err @@ -6733,7 +6468,7 @@ func (s *QueryFixtureStore) RemoveRelation(record *QueryFixture) error { var err error if afterDeleter, ok := r.(kallax.AfterDeleter); ok { err = s.Store.Transaction(func(s *kallax.Store) error { - err := s.Delete(Schema.QueryRelationFixture.BaseSchema, r) + err := s.Delete(Schema.User.BaseSchema, r) if err != nil { return err } @@ -6741,120 +6476,31 @@ func (s *QueryFixtureStore) RemoveRelation(record *QueryFixture) error { return afterDeleter.AfterDelete() }) } else { - err = s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, r) + err = s.Store.Delete(Schema.User.BaseSchema, r) } if err != nil { return err } - record.Relation = nil - return nil -} - -// RemoveNRelation removes the given items of the NRelation field of the -// model. If no items are given, it removes all of them. -// The items will also be removed from the passed record inside this method. -func (s *QueryFixtureStore) RemoveNRelation(record *QueryFixture, deleted ...*QueryRelationFixture) error { - var updated []*QueryRelationFixture - var clear bool - if len(deleted) == 0 { - clear = true - deleted = record.NRelation - if len(deleted) == 0 { - return nil - } - } - - if len(deleted) > 1 { - err := s.Store.Transaction(func(s *kallax.Store) error { - for _, d := range deleted { - var r kallax.Record = d - - if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { - if err := beforeDeleter.BeforeDelete(); err != nil { - return err - } - } - - if err := s.Delete(Schema.QueryRelationFixture.BaseSchema, d); err != nil { - return err - } - - if afterDeleter, ok := r.(kallax.AfterDeleter); ok { - if err := afterDeleter.AfterDelete(); err != nil { - return err - } - } - } - return nil - }) - - if err != nil { - return err - } - - if clear { - record.NRelation = nil - return nil - } - } else { - var r kallax.Record = deleted[0] - if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { - if err := beforeDeleter.BeforeDelete(); err != nil { - return err - } - } - - var err error - if afterDeleter, ok := r.(kallax.AfterDeleter); ok { - err = s.Store.Transaction(func(s *kallax.Store) error { - err := s.Delete(Schema.QueryRelationFixture.BaseSchema, r) - if err != nil { - return err - } - - return afterDeleter.AfterDelete() - }) - } else { - err = s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, deleted[0]) - } - - if err != nil { - return err - } - } - - for _, r := range record.NRelation { - var found bool - for _, d := range deleted { - if d.GetID().Equals(r.GetID()) { - found = true - break - } - } - if !found { - updated = append(updated, r) - } - } - record.NRelation = updated + record.User = nil return nil } -// QueryFixtureQuery is the object used to create queries for the QueryFixture +// PostQuery is the object used to create queries for the Post // entity. -type QueryFixtureQuery struct { +type PostQuery struct { *kallax.BaseQuery } -// NewQueryFixtureQuery returns a new instance of QueryFixtureQuery. -func NewQueryFixtureQuery() *QueryFixtureQuery { - return &QueryFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.QueryFixture.BaseSchema), +// NewPostQuery returns a new instance of PostQuery. +func NewPostQuery() *PostQuery { + return &PostQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.Post.BaseSchema), } } // Select adds columns to select in the query. -func (q *QueryFixtureQuery) Select(columns ...kallax.SchemaField) *QueryFixtureQuery { +func (q *PostQuery) Select(columns ...kallax.SchemaField) *PostQuery { if len(columns) == 0 { return q } @@ -6863,70 +6509,73 @@ func (q *QueryFixtureQuery) Select(columns ...kallax.SchemaField) *QueryFixtureQ } // SelectNot excludes columns from being selected in the query. -func (q *QueryFixtureQuery) SelectNot(columns ...kallax.SchemaField) *QueryFixtureQuery { +func (q *PostQuery) SelectNot(columns ...kallax.SchemaField) *PostQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *QueryFixtureQuery) Copy() *QueryFixtureQuery { - return &QueryFixtureQuery{ +func (q *PostQuery) Copy() *PostQuery { + return &PostQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *QueryFixtureQuery) Order(cols ...kallax.ColumnOrder) *QueryFixtureQuery { +func (q *PostQuery) Order(cols ...kallax.ColumnOrder) *PostQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *QueryFixtureQuery) BatchSize(size uint64) *QueryFixtureQuery { +func (q *PostQuery) BatchSize(size uint64) *PostQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *QueryFixtureQuery) Limit(n uint64) *QueryFixtureQuery { +func (q *PostQuery) Limit(n uint64) *PostQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *QueryFixtureQuery) Offset(n uint64) *QueryFixtureQuery { +func (q *PostQuery) Offset(n uint64) *PostQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *QueryFixtureQuery) Where(cond kallax.Condition) *QueryFixtureQuery { +func (q *PostQuery) Where(cond kallax.Condition) *PostQuery { q.BaseQuery.Where(cond) return q } -func (q *QueryFixtureQuery) WithRelation() *QueryFixtureQuery { - q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "Relation", kallax.OneToOne, nil) - return q -} - -func (q *QueryFixtureQuery) WithInverse() *QueryFixtureQuery { - q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "Inverse", kallax.OneToOne, nil) - return q -} - -func (q *QueryFixtureQuery) WithNRelation(cond kallax.Condition) *QueryFixtureQuery { - q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "NRelation", kallax.OneToMany, cond) +// WithUser retrieves all the User records associated with each +// record. Two conditions can be passed, the first to filter the table used +// to join User and Post and the second one to filter +// User directly. +func (q *PostQuery) WithUser( + filterUserPost kallax.Condition, + filterUser kallax.Condition, +) *PostQuery { + q.AddRelationThrough( + Schema.User.BaseSchema, + Schema.UserPost.BaseSchema, + "User", + filterUserPost, + filterUser, + ) return q } // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *QueryFixtureQuery) FindByID(v ...kallax.ULID) *QueryFixtureQuery { +func (q *PostQuery) FindByID(v ...int64) *PostQuery { if len(v) == 0 { return q } @@ -6934,181 +6583,1951 @@ func (q *QueryFixtureQuery) FindByID(v ...kallax.ULID) *QueryFixtureQuery { for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.QueryFixture.ID, values...)) + return q.Where(kallax.In(Schema.Post.ID, values...)) } -// FindByInverse adds a new filter to the query that will require that -// the foreign key of Inverse is equal to the passed value. -func (q *QueryFixtureQuery) FindByInverse(v kallax.ULID) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.InverseFK, v)) +// FindByText adds a new filter to the query that will require that +// the Text property is equal to the passed value. +func (q *PostQuery) FindByText(v string) *PostQuery { + return q.Where(kallax.Eq(Schema.Post.Text, v)) } -// FindByInline adds a new filter to the query that will require that -// the Inline property is equal to the passed value. -func (q *QueryFixtureQuery) FindByInline(v string) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.Inline, v)) +// PostResultSet is the set of results returned by a query to the +// database. +type PostResultSet struct { + ResultSet kallax.ResultSet + last *Post + lastErr error } -// FindByFoo adds a new filter to the query that will require that -// the Foo property is equal to the passed value. -func (q *QueryFixtureQuery) FindByFoo(v string) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.Foo, v)) +// NewPostResultSet creates a new result set for rows of the type +// Post. +func NewPostResultSet(rs kallax.ResultSet) *PostResultSet { + return &PostResultSet{ResultSet: rs} } -// FindByStringProperty adds a new filter to the query that will require that -// the StringProperty property is equal to the passed value. -func (q *QueryFixtureQuery) FindByStringProperty(v string) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.StringProperty, v)) -} +// Next fetches the next item in the result set and returns true if there is +// a next item. +// The result set is closed automatically when there are no more items. +func (rs *PostResultSet) Next() bool { + if !rs.ResultSet.Next() { + rs.lastErr = rs.ResultSet.Close() + rs.last = nil + return false + } -// FindByInteger adds a new filter to the query that will require that -// the Integer property is equal to the passed value. + var record kallax.Record + record, rs.lastErr = rs.ResultSet.Get(Schema.Post.BaseSchema) + if rs.lastErr != nil { + rs.last = nil + } else { + var ok bool + rs.last, ok = record.(*Post) + if !ok { + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *Post") + rs.last = nil + } + } + + return true +} + +// Get retrieves the last fetched item from the result set and the last error. +func (rs *PostResultSet) Get() (*Post, error) { + return rs.last, rs.lastErr +} + +// ForEach iterates over the complete result set passing every record found to +// the given callback. It is possible to stop the iteration by returning +// `kallax.ErrStop` in the callback. +// Result set is always closed at the end. +func (rs *PostResultSet) ForEach(fn func(*Post) error) error { + for rs.Next() { + record, err := rs.Get() + if err != nil { + return err + } + + if err := fn(record); err != nil { + if err == kallax.ErrStop { + return rs.Close() + } + + return err + } + } + return nil +} + +// All returns all records on the result set and closes the result set. +func (rs *PostResultSet) All() ([]*Post, error) { + var result []*Post + for rs.Next() { + record, err := rs.Get() + if err != nil { + return nil, err + } + result = append(result, record) + } + return result, nil +} + +// One returns the first record on the result set and closes the result set. +func (rs *PostResultSet) One() (*Post, error) { + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil +} + +// Err returns the last error occurred. +func (rs *PostResultSet) Err() error { + return rs.lastErr +} + +// Close closes the result set. +func (rs *PostResultSet) Close() error { + return rs.ResultSet.Close() +} + +// NewQueryFixture returns a new instance of QueryFixture. +func NewQueryFixture(f string) (record *QueryFixture) { + return newQueryFixture(f) +} + +// GetID returns the primary key of the model. +func (r *QueryFixture) GetID() kallax.Identifier { + return (*kallax.ULID)(&r.ID) +} + +// ColumnAddress returns the pointer to the value of the given column. +func (r *QueryFixture) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return (*kallax.ULID)(&r.ID), nil + case "inverse_id": + return types.Nullable(kallax.VirtualColumn("inverse_id", r, new(kallax.ULID))), nil + case "embedded": + return types.JSON(&r.Embedded), nil + case "inline": + return &r.Inline.Inline, nil + case "map_of_string": + return types.JSON(&r.MapOfString), nil + case "map_of_interface": + return types.JSON(&r.MapOfInterface), nil + case "map_of_some_type": + return types.JSON(&r.MapOfSomeType), nil + case "foo": + return &r.Foo, nil + case "string_property": + return &r.StringProperty, nil + case "integer": + return &r.Integer, nil + case "integer64": + return &r.Integer64, nil + case "float32": + return &r.Float32, nil + case "boolean": + return &r.Boolean, nil + case "array_param": + return types.Array(&r.ArrayParam, 3), nil + case "slice_param": + return types.Slice(&r.SliceParam), nil + case "alias_array_param": + return types.Array(&r.AliasArrayParam, 3), nil + case "alias_slice_param": + return types.Slice((*[]string)(&r.AliasSliceParam)), nil + case "alias_string_param": + return (*string)(&r.AliasStringParam), nil + case "alias_int_param": + return (*int)(&r.AliasIntParam), nil + case "dummy_param": + return types.JSON(&r.DummyParam), nil + case "alias_dummy_param": + return types.JSON(&r.AliasDummyParam), nil + case "slice_dummy_param": + return types.JSON(&r.SliceDummyParam), nil + case "idproperty_param": + return &r.IDPropertyParam, nil + case "interface_prop_param": + return &r.InterfacePropParam, nil + case "urlparam": + return (*types.URL)(&r.URLParam), nil + case "time_param": + return &r.TimeParam, nil + case "alias_arr_alias_string_param": + return types.Slice(&r.AliasArrAliasStringParam), nil + case "alias_here_array_param": + return types.Array(&r.AliasHereArrayParam, 3), nil + case "array_alias_here_string_param": + return types.Slice(&r.ArrayAliasHereStringParam), nil + case "scanner_valuer_param": + return &r.ScannerValuerParam, nil + + default: + return nil, fmt.Errorf("kallax: invalid column in QueryFixture: %s", col) + } +} + +// Value returns the value of the given column. +func (r *QueryFixture) Value(col string) (interface{}, error) { + switch col { + case "id": + return r.ID, nil + case "inverse_id": + return r.Model.VirtualColumn(col), nil + case "embedded": + return types.JSON(r.Embedded), nil + case "inline": + return r.Inline.Inline, nil + case "map_of_string": + return types.JSON(r.MapOfString), nil + case "map_of_interface": + return types.JSON(r.MapOfInterface), nil + case "map_of_some_type": + return types.JSON(r.MapOfSomeType), nil + case "foo": + return r.Foo, nil + case "string_property": + return r.StringProperty, nil + case "integer": + return r.Integer, nil + case "integer64": + return r.Integer64, nil + case "float32": + return r.Float32, nil + case "boolean": + return r.Boolean, nil + case "array_param": + return types.Array(&r.ArrayParam, 3), nil + case "slice_param": + return types.Slice(r.SliceParam), nil + case "alias_array_param": + return types.Array(&r.AliasArrayParam, 3), nil + case "alias_slice_param": + return types.Slice(r.AliasSliceParam), nil + case "alias_string_param": + return (string)(r.AliasStringParam), nil + case "alias_int_param": + return (int)(r.AliasIntParam), nil + case "dummy_param": + return types.JSON(r.DummyParam), nil + case "alias_dummy_param": + return types.JSON(r.AliasDummyParam), nil + case "slice_dummy_param": + return types.JSON(r.SliceDummyParam), nil + case "idproperty_param": + return r.IDPropertyParam, nil + case "interface_prop_param": + return r.InterfacePropParam, nil + case "urlparam": + return (*types.URL)(&r.URLParam), nil + case "time_param": + return r.TimeParam, nil + case "alias_arr_alias_string_param": + return types.Slice(r.AliasArrAliasStringParam), nil + case "alias_here_array_param": + return types.Array(&r.AliasHereArrayParam, 3), nil + case "array_alias_here_string_param": + return types.Slice(r.ArrayAliasHereStringParam), nil + case "scanner_valuer_param": + return r.ScannerValuerParam, nil + + default: + return nil, fmt.Errorf("kallax: invalid column in QueryFixture: %s", col) + } +} + +// NewRelationshipRecord returns a new record for the relatiobship in the given +// field. +func (r *QueryFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + switch field { + case "Relation": + return new(QueryRelationFixture), nil + case "Inverse": + return new(QueryRelationFixture), nil + case "NRelation": + return new(QueryRelationFixture), nil + + } + return nil, fmt.Errorf("kallax: model QueryFixture has no relationship %s", field) +} + +// SetRelationship sets the given relationship in the given field. +func (r *QueryFixture) SetRelationship(field string, rel interface{}) error { + switch field { + case "Relation": + val, ok := rel.(*QueryRelationFixture) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Relation", rel) + } + if !val.GetID().IsEmpty() { + r.Relation = val + } + + return nil + + case "Inverse": + val, ok := rel.(*QueryRelationFixture) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Inverse", rel) + } + if !val.GetID().IsEmpty() { + r.Inverse = val + } + + return nil + + case "NRelation": + records, ok := rel.([]kallax.Record) + if !ok { + return fmt.Errorf("kallax: relationship field %s needs a collection of records, not %T", field, rel) + } + + r.NRelation = make([]*QueryRelationFixture, len(records)) + for i, record := range records { + rel, ok := record.(*QueryRelationFixture) + if !ok { + return fmt.Errorf("kallax: element of type %T cannot be added to relationship %s", record, field) + } + r.NRelation[i] = rel + } + return nil + + } + return fmt.Errorf("kallax: model QueryFixture has no relationship %s", field) +} + +// QueryFixtureStore is the entity to access the records of the type QueryFixture +// in the database. +type QueryFixtureStore struct { + *kallax.Store +} + +// NewQueryFixtureStore creates a new instance of QueryFixtureStore +// using a SQL database. +func NewQueryFixtureStore(db *sql.DB) *QueryFixtureStore { + return &QueryFixtureStore{kallax.NewStore(db)} +} + +// GenericStore returns the generic store of this store. +func (s *QueryFixtureStore) GenericStore() *kallax.Store { + return s.Store +} + +// SetGenericStore changes the generic store of this store. +func (s *QueryFixtureStore) SetGenericStore(store *kallax.Store) { + s.Store = store +} + +// Debug returns a new store that will print all SQL statements to stdout using +// the log.Printf function. +func (s *QueryFixtureStore) Debug() *QueryFixtureStore { + return &QueryFixtureStore{s.Store.Debug()} +} + +// DebugWith returns a new store that will print all SQL statements using the +// given logger function. +func (s *QueryFixtureStore) DebugWith(logger kallax.LoggerFunc) *QueryFixtureStore { + return &QueryFixtureStore{s.Store.DebugWith(logger)} +} + +func (s *QueryFixtureStore) relationshipRecords(record *QueryFixture) []kallax.RecordWithSchema { + var records []kallax.RecordWithSchema + + if record.Relation != nil { + record.Relation.ClearVirtualColumns() + record.Relation.AddVirtualColumn("owner_id", record.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.QueryRelationFixture.BaseSchema, + Record: record.Relation, + }) + } + + for i := range record.NRelation { + record.NRelation[i].ClearVirtualColumns() + record.NRelation[i].AddVirtualColumn("owner_id", record.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.QueryRelationFixture.BaseSchema, + Record: record.NRelation[i], + }) + } + + return records +} + +func (s *QueryFixtureStore) inverseRecords(record *QueryFixture) []kallax.RecordWithSchema { + record.ClearVirtualColumns() + var records []kallax.RecordWithSchema + + if record.Inverse != nil { + record.AddVirtualColumn("inverse_id", record.Inverse.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.QueryRelationFixture.BaseSchema, + Record: record.Inverse, + }) + } + + return records +} + +// Insert inserts a QueryFixture in the database. A non-persisted object is +// required for this operation. +func (s *QueryFixtureStore) Insert(record *QueryFixture) error { + record.TimeParam = record.TimeParam.Truncate(time.Microsecond) + + records := s.relationshipRecords(record) + + inverseRecords := s.inverseRecords(record) + + if len(records) > 0 && len(inverseRecords) > 0 { + return s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + if err := s.Insert(Schema.QueryFixture.BaseSchema, record); err != nil { + return err + } + + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + return nil + }) + } + + return s.Store.Insert(Schema.QueryFixture.BaseSchema, record) +} + +// Update updates the given record on the database. If the columns are given, +// only these columns will be updated. Otherwise all of them will be. +// Be very careful with this, as you will have a potentially different object +// in memory but not on the database. +// Only writable records can be updated. Writable objects are those that have +// been just inserted or retrieved using a query with no custom select fields. +func (s *QueryFixtureStore) Update(record *QueryFixture, cols ...kallax.SchemaField) (updated int64, err error) { + record.TimeParam = record.TimeParam.Truncate(time.Microsecond) + + records := s.relationshipRecords(record) + + inverseRecords := s.inverseRecords(record) + + if len(records) > 0 && len(inverseRecords) > 0 { + err = s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + updated, err = s.Update(Schema.QueryFixture.BaseSchema, record, cols...) + if err != nil { + return err + } + + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + return nil + }) + if err != nil { + return 0, err + } + + return updated, nil + } + + return s.Store.Update(Schema.QueryFixture.BaseSchema, record, cols...) +} + +// Save inserts the object if the record is not persisted, otherwise it updates +// it. Same rules of Update and Insert apply depending on the case. +func (s *QueryFixtureStore) Save(record *QueryFixture) (updated bool, err error) { + if !record.IsPersisted() { + return false, s.Insert(record) + } + + rowsUpdated, err := s.Update(record) + if err != nil { + return false, err + } + + return rowsUpdated > 0, nil +} + +// Delete removes the given record from the database. +func (s *QueryFixtureStore) Delete(record *QueryFixture) error { + return s.Store.Delete(Schema.QueryFixture.BaseSchema, record) +} + +// Find returns the set of results for the given query. +func (s *QueryFixtureStore) Find(q *QueryFixtureQuery) (*QueryFixtureResultSet, error) { + rs, err := s.Store.Find(q) + if err != nil { + return nil, err + } + + return NewQueryFixtureResultSet(rs), nil +} + +// MustFind returns the set of results for the given query, but panics if there +// is any error. +func (s *QueryFixtureStore) MustFind(q *QueryFixtureQuery) *QueryFixtureResultSet { + return NewQueryFixtureResultSet(s.Store.MustFind(q)) +} + +// Count returns the number of rows that would be retrieved with the given +// query. +func (s *QueryFixtureStore) Count(q *QueryFixtureQuery) (int64, error) { + return s.Store.Count(q) +} + +// MustCount returns the number of rows that would be retrieved with the given +// query, but panics if there is an error. +func (s *QueryFixtureStore) MustCount(q *QueryFixtureQuery) int64 { + return s.Store.MustCount(q) +} + +// FindOne returns the first row returned by the given query. +// `ErrNotFound` is returned if there are no results. +func (s *QueryFixtureStore) FindOne(q *QueryFixtureQuery) (*QueryFixture, error) { + q.Limit(1) + q.Offset(0) + rs, err := s.Find(q) + if err != nil { + return nil, err + } + + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil +} + +// FindAll returns a list of all the rows returned by the given query. +func (s *QueryFixtureStore) FindAll(q *QueryFixtureQuery) ([]*QueryFixture, error) { + rs, err := s.Find(q) + if err != nil { + return nil, err + } + + return rs.All() +} + +// MustFindOne returns the first row retrieved by the given query. It panics +// if there is an error or if there are no rows. +func (s *QueryFixtureStore) MustFindOne(q *QueryFixtureQuery) *QueryFixture { + record, err := s.FindOne(q) + if err != nil { + panic(err) + } + return record +} + +// Reload refreshes the QueryFixture with the data in the database and +// makes it writable. +func (s *QueryFixtureStore) Reload(record *QueryFixture) error { + return s.Store.Reload(Schema.QueryFixture.BaseSchema, record) +} + +// Transaction executes the given callback in a transaction and rollbacks if +// an error is returned. +// The transaction is only open in the store passed as a parameter to the +// callback. +func (s *QueryFixtureStore) Transaction(callback func(*QueryFixtureStore) error) error { + if callback == nil { + return kallax.ErrInvalidTxCallback + } + + return s.Store.Transaction(func(store *kallax.Store) error { + return callback(&QueryFixtureStore{store}) + }) +} + +// RemoveRelation removes from the database the given relationship of the +// model. It also resets the field Relation of the model. +func (s *QueryFixtureStore) RemoveRelation(record *QueryFixture) error { + var r kallax.Record = record.Relation + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + var err error + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + err = s.Store.Transaction(func(s *kallax.Store) error { + err := s.Delete(Schema.QueryRelationFixture.BaseSchema, r) + if err != nil { + return err + } + + return afterDeleter.AfterDelete() + }) + } else { + err = s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, r) + } + if err != nil { + return err + } + + record.Relation = nil + return nil +} + +// RemoveNRelation removes the given items of the NRelation field of the +// model. If no items are given, it removes all of them. +// The items will also be removed from the passed record inside this method. +func (s *QueryFixtureStore) RemoveNRelation(record *QueryFixture, deleted ...*QueryRelationFixture) error { + var updated []*QueryRelationFixture + var clear bool + if len(deleted) == 0 { + clear = true + deleted = record.NRelation + if len(deleted) == 0 { + return nil + } + } + + if len(deleted) > 1 { + err := s.Store.Transaction(func(s *kallax.Store) error { + for _, d := range deleted { + var r kallax.Record = d + + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + if err := s.Delete(Schema.QueryRelationFixture.BaseSchema, d); err != nil { + return err + } + + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + if err := afterDeleter.AfterDelete(); err != nil { + return err + } + } + } + return nil + }) + + if err != nil { + return err + } + + if clear { + record.NRelation = nil + return nil + } + } else { + var r kallax.Record = deleted[0] + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + var err error + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + err = s.Store.Transaction(func(s *kallax.Store) error { + err := s.Delete(Schema.QueryRelationFixture.BaseSchema, r) + if err != nil { + return err + } + + return afterDeleter.AfterDelete() + }) + } else { + err = s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, deleted[0]) + } + + if err != nil { + return err + } + } + + for _, r := range record.NRelation { + var found bool + for _, d := range deleted { + if d.GetID().Equals(r.GetID()) { + found = true + break + } + } + if !found { + updated = append(updated, r) + } + } + record.NRelation = updated + return nil +} + +// QueryFixtureQuery is the object used to create queries for the QueryFixture +// entity. +type QueryFixtureQuery struct { + *kallax.BaseQuery +} + +// NewQueryFixtureQuery returns a new instance of QueryFixtureQuery. +func NewQueryFixtureQuery() *QueryFixtureQuery { + return &QueryFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.QueryFixture.BaseSchema), + } +} + +// Select adds columns to select in the query. +func (q *QueryFixtureQuery) Select(columns ...kallax.SchemaField) *QueryFixtureQuery { + if len(columns) == 0 { + return q + } + q.BaseQuery.Select(columns...) + return q +} + +// SelectNot excludes columns from being selected in the query. +func (q *QueryFixtureQuery) SelectNot(columns ...kallax.SchemaField) *QueryFixtureQuery { + q.BaseQuery.SelectNot(columns...) + return q +} + +// Copy returns a new identical copy of the query. Remember queries are mutable +// so make a copy any time you need to reuse them. +func (q *QueryFixtureQuery) Copy() *QueryFixtureQuery { + return &QueryFixtureQuery{ + BaseQuery: q.BaseQuery.Copy(), + } +} + +// Order adds order clauses to the query for the given columns. +func (q *QueryFixtureQuery) Order(cols ...kallax.ColumnOrder) *QueryFixtureQuery { + q.BaseQuery.Order(cols...) + return q +} + +// BatchSize sets the number of items to fetch per batch when there are 1:N +// relationships selected in the query. +func (q *QueryFixtureQuery) BatchSize(size uint64) *QueryFixtureQuery { + q.BaseQuery.BatchSize(size) + return q +} + +// Limit sets the max number of items to retrieve. +func (q *QueryFixtureQuery) Limit(n uint64) *QueryFixtureQuery { + q.BaseQuery.Limit(n) + return q +} + +// Offset sets the number of items to skip from the result set of items. +func (q *QueryFixtureQuery) Offset(n uint64) *QueryFixtureQuery { + q.BaseQuery.Offset(n) + return q +} + +// Where adds a condition to the query. All conditions added are concatenated +// using a logical AND. +func (q *QueryFixtureQuery) Where(cond kallax.Condition) *QueryFixtureQuery { + q.BaseQuery.Where(cond) + return q +} + +// WithRelation retrieves the Relation record associated with each +// record. +func (q *QueryFixtureQuery) WithRelation() *QueryFixtureQuery { + q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "Relation", kallax.OneToOne, nil) + return q +} + +// WithInverse retrieves the Inverse record associated with each +// record. +func (q *QueryFixtureQuery) WithInverse() *QueryFixtureQuery { + q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "Inverse", kallax.OneToOne, nil) + return q +} + +// WithNRelation retrieves all the NRelation records associated with each +// record. A condition can be passed to filter the associated records. +func (q *QueryFixtureQuery) WithNRelation(cond kallax.Condition) *QueryFixtureQuery { + q.AddRelation(Schema.QueryRelationFixture.BaseSchema, "NRelation", kallax.OneToMany, cond) + return q +} + +// FindByID adds a new filter to the query that will require that +// the ID property is equal to one of the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByID(v ...kallax.ULID) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.In(Schema.QueryFixture.ID, values...)) +} + +// FindByInverse adds a new filter to the query that will require that +// the foreign key of Inverse is equal to the passed value. +func (q *QueryFixtureQuery) FindByInverse(v kallax.ULID) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.InverseFK, v)) +} + +// FindByInline adds a new filter to the query that will require that +// the Inline property is equal to the passed value. +func (q *QueryFixtureQuery) FindByInline(v string) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.Inline, v)) +} + +// FindByFoo adds a new filter to the query that will require that +// the Foo property is equal to the passed value. +func (q *QueryFixtureQuery) FindByFoo(v string) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.Foo, v)) +} + +// FindByStringProperty adds a new filter to the query that will require that +// the StringProperty property is equal to the passed value. +func (q *QueryFixtureQuery) FindByStringProperty(v string) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.StringProperty, v)) +} + +// FindByInteger adds a new filter to the query that will require that +// the Integer property is equal to the passed value. func (q *QueryFixtureQuery) FindByInteger(cond kallax.ScalarCond, v int) *QueryFixtureQuery { return q.Where(cond(Schema.QueryFixture.Integer, v)) } -// FindByInteger64 adds a new filter to the query that will require that -// the Integer64 property is equal to the passed value. -func (q *QueryFixtureQuery) FindByInteger64(cond kallax.ScalarCond, v int64) *QueryFixtureQuery { - return q.Where(cond(Schema.QueryFixture.Integer64, v)) +// FindByInteger64 adds a new filter to the query that will require that +// the Integer64 property is equal to the passed value. +func (q *QueryFixtureQuery) FindByInteger64(cond kallax.ScalarCond, v int64) *QueryFixtureQuery { + return q.Where(cond(Schema.QueryFixture.Integer64, v)) +} + +// FindByFloat32 adds a new filter to the query that will require that +// the Float32 property is equal to the passed value. +func (q *QueryFixtureQuery) FindByFloat32(cond kallax.ScalarCond, v float32) *QueryFixtureQuery { + return q.Where(cond(Schema.QueryFixture.Float32, v)) +} + +// FindByBoolean adds a new filter to the query that will require that +// the Boolean property is equal to the passed value. +func (q *QueryFixtureQuery) FindByBoolean(v bool) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.Boolean, v)) +} + +// FindByArrayParam adds a new filter to the query that will require that +// the ArrayParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByArrayParam(v ...string) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.ArrayParam, values...)) +} + +// FindBySliceParam adds a new filter to the query that will require that +// the SliceParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindBySliceParam(v ...string) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.SliceParam, values...)) +} + +// FindByAliasArrayParam adds a new filter to the query that will require that +// the AliasArrayParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByAliasArrayParam(v ...string) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasArrayParam, values...)) +} + +// FindByAliasSliceParam adds a new filter to the query that will require that +// the AliasSliceParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByAliasSliceParam(v ...string) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasSliceParam, values...)) +} + +// FindByAliasStringParam adds a new filter to the query that will require that +// the AliasStringParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByAliasStringParam(v fixtures.AliasString) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.AliasStringParam, v)) +} + +// FindByAliasIntParam adds a new filter to the query that will require that +// the AliasIntParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByAliasIntParam(cond kallax.ScalarCond, v fixtures.AliasInt) *QueryFixtureQuery { + return q.Where(cond(Schema.QueryFixture.AliasIntParam, v)) +} + +// FindByIDPropertyParam adds a new filter to the query that will require that +// the IDPropertyParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByIDPropertyParam(v kallax.ULID) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.IDPropertyParam, v)) +} + +// FindByInterfacePropParam adds a new filter to the query that will require that +// the InterfacePropParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByInterfacePropParam(v fixtures.InterfaceImplementation) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.InterfacePropParam, v)) +} + +// FindByURLParam adds a new filter to the query that will require that +// the URLParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByURLParam(v url.URL) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.URLParam, v)) +} + +// FindByTimeParam adds a new filter to the query that will require that +// the TimeParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByTimeParam(cond kallax.ScalarCond, v time.Time) *QueryFixtureQuery { + return q.Where(cond(Schema.QueryFixture.TimeParam, v)) +} + +// FindByAliasArrAliasStringParam adds a new filter to the query that will require that +// the AliasArrAliasStringParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByAliasArrAliasStringParam(v ...fixtures.AliasString) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasArrAliasStringParam, values...)) +} + +// FindByAliasHereArrayParam adds a new filter to the query that will require that +// the AliasHereArrayParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByAliasHereArrayParam(v ...string) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasHereArrayParam, values...)) +} + +// FindByArrayAliasHereStringParam adds a new filter to the query that will require that +// the ArrayAliasHereStringParam property contains all the passed values; if no passed values, +// it will do nothing. +func (q *QueryFixtureQuery) FindByArrayAliasHereStringParam(v ...AliasHereString) *QueryFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.QueryFixture.ArrayAliasHereStringParam, values...)) +} + +// FindByScannerValuerParam adds a new filter to the query that will require that +// the ScannerValuerParam property is equal to the passed value. +func (q *QueryFixtureQuery) FindByScannerValuerParam(v ScannerValuer) *QueryFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryFixture.ScannerValuerParam, v)) +} + +// QueryFixtureResultSet is the set of results returned by a query to the +// database. +type QueryFixtureResultSet struct { + ResultSet kallax.ResultSet + last *QueryFixture + lastErr error +} + +// NewQueryFixtureResultSet creates a new result set for rows of the type +// QueryFixture. +func NewQueryFixtureResultSet(rs kallax.ResultSet) *QueryFixtureResultSet { + return &QueryFixtureResultSet{ResultSet: rs} +} + +// Next fetches the next item in the result set and returns true if there is +// a next item. +// The result set is closed automatically when there are no more items. +func (rs *QueryFixtureResultSet) Next() bool { + if !rs.ResultSet.Next() { + rs.lastErr = rs.ResultSet.Close() + rs.last = nil + return false + } + + var record kallax.Record + record, rs.lastErr = rs.ResultSet.Get(Schema.QueryFixture.BaseSchema) + if rs.lastErr != nil { + rs.last = nil + } else { + var ok bool + rs.last, ok = record.(*QueryFixture) + if !ok { + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *QueryFixture") + rs.last = nil + } + } + + return true +} + +// Get retrieves the last fetched item from the result set and the last error. +func (rs *QueryFixtureResultSet) Get() (*QueryFixture, error) { + return rs.last, rs.lastErr +} + +// ForEach iterates over the complete result set passing every record found to +// the given callback. It is possible to stop the iteration by returning +// `kallax.ErrStop` in the callback. +// Result set is always closed at the end. +func (rs *QueryFixtureResultSet) ForEach(fn func(*QueryFixture) error) error { + for rs.Next() { + record, err := rs.Get() + if err != nil { + return err + } + + if err := fn(record); err != nil { + if err == kallax.ErrStop { + return rs.Close() + } + + return err + } + } + return nil +} + +// All returns all records on the result set and closes the result set. +func (rs *QueryFixtureResultSet) All() ([]*QueryFixture, error) { + var result []*QueryFixture + for rs.Next() { + record, err := rs.Get() + if err != nil { + return nil, err + } + result = append(result, record) + } + return result, nil +} + +// One returns the first record on the result set and closes the result set. +func (rs *QueryFixtureResultSet) One() (*QueryFixture, error) { + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil +} + +// Err returns the last error occurred. +func (rs *QueryFixtureResultSet) Err() error { + return rs.lastErr +} + +// Close closes the result set. +func (rs *QueryFixtureResultSet) Close() error { + return rs.ResultSet.Close() +} + +// NewQueryRelationFixture returns a new instance of QueryRelationFixture. +func NewQueryRelationFixture() (record *QueryRelationFixture) { + return new(QueryRelationFixture) +} + +// GetID returns the primary key of the model. +func (r *QueryRelationFixture) GetID() kallax.Identifier { + return (*kallax.ULID)(&r.ID) +} + +// ColumnAddress returns the pointer to the value of the given column. +func (r *QueryRelationFixture) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return (*kallax.ULID)(&r.ID), nil + case "name": + return &r.Name, nil + case "owner_id": + return types.Nullable(kallax.VirtualColumn("owner_id", r, new(kallax.ULID))), nil + + default: + return nil, fmt.Errorf("kallax: invalid column in QueryRelationFixture: %s", col) + } +} + +// Value returns the value of the given column. +func (r *QueryRelationFixture) Value(col string) (interface{}, error) { + switch col { + case "id": + return r.ID, nil + case "name": + return r.Name, nil + case "owner_id": + return r.Model.VirtualColumn(col), nil + + default: + return nil, fmt.Errorf("kallax: invalid column in QueryRelationFixture: %s", col) + } +} + +// NewRelationshipRecord returns a new record for the relatiobship in the given +// field. +func (r *QueryRelationFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + switch field { + case "Owner": + return new(QueryFixture), nil + + } + return nil, fmt.Errorf("kallax: model QueryRelationFixture has no relationship %s", field) +} + +// SetRelationship sets the given relationship in the given field. +func (r *QueryRelationFixture) SetRelationship(field string, rel interface{}) error { + switch field { + case "Owner": + val, ok := rel.(*QueryFixture) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Owner", rel) + } + if !val.GetID().IsEmpty() { + r.Owner = val + } + + return nil + + } + return fmt.Errorf("kallax: model QueryRelationFixture has no relationship %s", field) +} + +// QueryRelationFixtureStore is the entity to access the records of the type QueryRelationFixture +// in the database. +type QueryRelationFixtureStore struct { + *kallax.Store +} + +// NewQueryRelationFixtureStore creates a new instance of QueryRelationFixtureStore +// using a SQL database. +func NewQueryRelationFixtureStore(db *sql.DB) *QueryRelationFixtureStore { + return &QueryRelationFixtureStore{kallax.NewStore(db)} +} + +// GenericStore returns the generic store of this store. +func (s *QueryRelationFixtureStore) GenericStore() *kallax.Store { + return s.Store +} + +// SetGenericStore changes the generic store of this store. +func (s *QueryRelationFixtureStore) SetGenericStore(store *kallax.Store) { + s.Store = store +} + +// Debug returns a new store that will print all SQL statements to stdout using +// the log.Printf function. +func (s *QueryRelationFixtureStore) Debug() *QueryRelationFixtureStore { + return &QueryRelationFixtureStore{s.Store.Debug()} +} + +// DebugWith returns a new store that will print all SQL statements using the +// given logger function. +func (s *QueryRelationFixtureStore) DebugWith(logger kallax.LoggerFunc) *QueryRelationFixtureStore { + return &QueryRelationFixtureStore{s.Store.DebugWith(logger)} +} + +func (s *QueryRelationFixtureStore) inverseRecords(record *QueryRelationFixture) []kallax.RecordWithSchema { + record.ClearVirtualColumns() + var records []kallax.RecordWithSchema + + if record.Owner != nil { + record.AddVirtualColumn("owner_id", record.Owner.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.QueryFixture.BaseSchema, + Record: record.Owner, + }) + } + + return records +} + +// Insert inserts a QueryRelationFixture in the database. A non-persisted object is +// required for this operation. +func (s *QueryRelationFixtureStore) Insert(record *QueryRelationFixture) error { + inverseRecords := s.inverseRecords(record) + + if len(inverseRecords) > 0 { + return s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + if err := s.Insert(Schema.QueryRelationFixture.BaseSchema, record); err != nil { + return err + } + + return nil + }) + } + + return s.Store.Insert(Schema.QueryRelationFixture.BaseSchema, record) +} + +// Update updates the given record on the database. If the columns are given, +// only these columns will be updated. Otherwise all of them will be. +// Be very careful with this, as you will have a potentially different object +// in memory but not on the database. +// Only writable records can be updated. Writable objects are those that have +// been just inserted or retrieved using a query with no custom select fields. +func (s *QueryRelationFixtureStore) Update(record *QueryRelationFixture, cols ...kallax.SchemaField) (updated int64, err error) { + inverseRecords := s.inverseRecords(record) + + if len(inverseRecords) > 0 { + err = s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + updated, err = s.Update(Schema.QueryRelationFixture.BaseSchema, record, cols...) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return 0, err + } + + return updated, nil + } + + return s.Store.Update(Schema.QueryRelationFixture.BaseSchema, record, cols...) +} + +// Save inserts the object if the record is not persisted, otherwise it updates +// it. Same rules of Update and Insert apply depending on the case. +func (s *QueryRelationFixtureStore) Save(record *QueryRelationFixture) (updated bool, err error) { + if !record.IsPersisted() { + return false, s.Insert(record) + } + + rowsUpdated, err := s.Update(record) + if err != nil { + return false, err + } + + return rowsUpdated > 0, nil +} + +// Delete removes the given record from the database. +func (s *QueryRelationFixtureStore) Delete(record *QueryRelationFixture) error { + return s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, record) +} + +// Find returns the set of results for the given query. +func (s *QueryRelationFixtureStore) Find(q *QueryRelationFixtureQuery) (*QueryRelationFixtureResultSet, error) { + rs, err := s.Store.Find(q) + if err != nil { + return nil, err + } + + return NewQueryRelationFixtureResultSet(rs), nil +} + +// MustFind returns the set of results for the given query, but panics if there +// is any error. +func (s *QueryRelationFixtureStore) MustFind(q *QueryRelationFixtureQuery) *QueryRelationFixtureResultSet { + return NewQueryRelationFixtureResultSet(s.Store.MustFind(q)) +} + +// Count returns the number of rows that would be retrieved with the given +// query. +func (s *QueryRelationFixtureStore) Count(q *QueryRelationFixtureQuery) (int64, error) { + return s.Store.Count(q) +} + +// MustCount returns the number of rows that would be retrieved with the given +// query, but panics if there is an error. +func (s *QueryRelationFixtureStore) MustCount(q *QueryRelationFixtureQuery) int64 { + return s.Store.MustCount(q) +} + +// FindOne returns the first row returned by the given query. +// `ErrNotFound` is returned if there are no results. +func (s *QueryRelationFixtureStore) FindOne(q *QueryRelationFixtureQuery) (*QueryRelationFixture, error) { + q.Limit(1) + q.Offset(0) + rs, err := s.Find(q) + if err != nil { + return nil, err + } + + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil +} + +// FindAll returns a list of all the rows returned by the given query. +func (s *QueryRelationFixtureStore) FindAll(q *QueryRelationFixtureQuery) ([]*QueryRelationFixture, error) { + rs, err := s.Find(q) + if err != nil { + return nil, err + } + + return rs.All() +} + +// MustFindOne returns the first row retrieved by the given query. It panics +// if there is an error or if there are no rows. +func (s *QueryRelationFixtureStore) MustFindOne(q *QueryRelationFixtureQuery) *QueryRelationFixture { + record, err := s.FindOne(q) + if err != nil { + panic(err) + } + return record +} + +// Reload refreshes the QueryRelationFixture with the data in the database and +// makes it writable. +func (s *QueryRelationFixtureStore) Reload(record *QueryRelationFixture) error { + return s.Store.Reload(Schema.QueryRelationFixture.BaseSchema, record) +} + +// Transaction executes the given callback in a transaction and rollbacks if +// an error is returned. +// The transaction is only open in the store passed as a parameter to the +// callback. +func (s *QueryRelationFixtureStore) Transaction(callback func(*QueryRelationFixtureStore) error) error { + if callback == nil { + return kallax.ErrInvalidTxCallback + } + + return s.Store.Transaction(func(store *kallax.Store) error { + return callback(&QueryRelationFixtureStore{store}) + }) +} + +// QueryRelationFixtureQuery is the object used to create queries for the QueryRelationFixture +// entity. +type QueryRelationFixtureQuery struct { + *kallax.BaseQuery +} + +// NewQueryRelationFixtureQuery returns a new instance of QueryRelationFixtureQuery. +func NewQueryRelationFixtureQuery() *QueryRelationFixtureQuery { + return &QueryRelationFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.QueryRelationFixture.BaseSchema), + } +} + +// Select adds columns to select in the query. +func (q *QueryRelationFixtureQuery) Select(columns ...kallax.SchemaField) *QueryRelationFixtureQuery { + if len(columns) == 0 { + return q + } + q.BaseQuery.Select(columns...) + return q +} + +// SelectNot excludes columns from being selected in the query. +func (q *QueryRelationFixtureQuery) SelectNot(columns ...kallax.SchemaField) *QueryRelationFixtureQuery { + q.BaseQuery.SelectNot(columns...) + return q +} + +// Copy returns a new identical copy of the query. Remember queries are mutable +// so make a copy any time you need to reuse them. +func (q *QueryRelationFixtureQuery) Copy() *QueryRelationFixtureQuery { + return &QueryRelationFixtureQuery{ + BaseQuery: q.BaseQuery.Copy(), + } +} + +// Order adds order clauses to the query for the given columns. +func (q *QueryRelationFixtureQuery) Order(cols ...kallax.ColumnOrder) *QueryRelationFixtureQuery { + q.BaseQuery.Order(cols...) + return q +} + +// BatchSize sets the number of items to fetch per batch when there are 1:N +// relationships selected in the query. +func (q *QueryRelationFixtureQuery) BatchSize(size uint64) *QueryRelationFixtureQuery { + q.BaseQuery.BatchSize(size) + return q +} + +// Limit sets the max number of items to retrieve. +func (q *QueryRelationFixtureQuery) Limit(n uint64) *QueryRelationFixtureQuery { + q.BaseQuery.Limit(n) + return q +} + +// Offset sets the number of items to skip from the result set of items. +func (q *QueryRelationFixtureQuery) Offset(n uint64) *QueryRelationFixtureQuery { + q.BaseQuery.Offset(n) + return q +} + +// Where adds a condition to the query. All conditions added are concatenated +// using a logical AND. +func (q *QueryRelationFixtureQuery) Where(cond kallax.Condition) *QueryRelationFixtureQuery { + q.BaseQuery.Where(cond) + return q +} + +// WithOwner retrieves the Owner record associated with each +// record. +func (q *QueryRelationFixtureQuery) WithOwner() *QueryRelationFixtureQuery { + q.AddRelation(Schema.QueryFixture.BaseSchema, "Owner", kallax.OneToOne, nil) + return q +} + +// FindByID adds a new filter to the query that will require that +// the ID property is equal to one of the passed values; if no passed values, +// it will do nothing. +func (q *QueryRelationFixtureQuery) FindByID(v ...kallax.ULID) *QueryRelationFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.In(Schema.QueryRelationFixture.ID, values...)) +} + +// FindByName adds a new filter to the query that will require that +// the Name property is equal to the passed value. +func (q *QueryRelationFixtureQuery) FindByName(v string) *QueryRelationFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryRelationFixture.Name, v)) +} + +// FindByOwner adds a new filter to the query that will require that +// the foreign key of Owner is equal to the passed value. +func (q *QueryRelationFixtureQuery) FindByOwner(v kallax.ULID) *QueryRelationFixtureQuery { + return q.Where(kallax.Eq(Schema.QueryRelationFixture.OwnerFK, v)) +} + +// QueryRelationFixtureResultSet is the set of results returned by a query to the +// database. +type QueryRelationFixtureResultSet struct { + ResultSet kallax.ResultSet + last *QueryRelationFixture + lastErr error +} + +// NewQueryRelationFixtureResultSet creates a new result set for rows of the type +// QueryRelationFixture. +func NewQueryRelationFixtureResultSet(rs kallax.ResultSet) *QueryRelationFixtureResultSet { + return &QueryRelationFixtureResultSet{ResultSet: rs} +} + +// Next fetches the next item in the result set and returns true if there is +// a next item. +// The result set is closed automatically when there are no more items. +func (rs *QueryRelationFixtureResultSet) Next() bool { + if !rs.ResultSet.Next() { + rs.lastErr = rs.ResultSet.Close() + rs.last = nil + return false + } + + var record kallax.Record + record, rs.lastErr = rs.ResultSet.Get(Schema.QueryRelationFixture.BaseSchema) + if rs.lastErr != nil { + rs.last = nil + } else { + var ok bool + rs.last, ok = record.(*QueryRelationFixture) + if !ok { + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *QueryRelationFixture") + rs.last = nil + } + } + + return true +} + +// Get retrieves the last fetched item from the result set and the last error. +func (rs *QueryRelationFixtureResultSet) Get() (*QueryRelationFixture, error) { + return rs.last, rs.lastErr +} + +// ForEach iterates over the complete result set passing every record found to +// the given callback. It is possible to stop the iteration by returning +// `kallax.ErrStop` in the callback. +// Result set is always closed at the end. +func (rs *QueryRelationFixtureResultSet) ForEach(fn func(*QueryRelationFixture) error) error { + for rs.Next() { + record, err := rs.Get() + if err != nil { + return err + } + + if err := fn(record); err != nil { + if err == kallax.ErrStop { + return rs.Close() + } + + return err + } + } + return nil +} + +// All returns all records on the result set and closes the result set. +func (rs *QueryRelationFixtureResultSet) All() ([]*QueryRelationFixture, error) { + var result []*QueryRelationFixture + for rs.Next() { + record, err := rs.Get() + if err != nil { + return nil, err + } + result = append(result, record) + } + return result, nil +} + +// One returns the first record on the result set and closes the result set. +func (rs *QueryRelationFixtureResultSet) One() (*QueryRelationFixture, error) { + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil +} + +// Err returns the last error occurred. +func (rs *QueryRelationFixtureResultSet) Err() error { + return rs.lastErr +} + +// Close closes the result set. +func (rs *QueryRelationFixtureResultSet) Close() error { + return rs.ResultSet.Close() +} + +// NewResultSetFixture returns a new instance of ResultSetFixture. +func NewResultSetFixture(f string) (record *ResultSetFixture) { + return newResultSetFixture(f) +} + +// GetID returns the primary key of the model. +func (r *ResultSetFixture) GetID() kallax.Identifier { + return (*kallax.ULID)(&r.ID) } -// FindByFloat32 adds a new filter to the query that will require that -// the Float32 property is equal to the passed value. -func (q *QueryFixtureQuery) FindByFloat32(cond kallax.ScalarCond, v float32) *QueryFixtureQuery { - return q.Where(cond(Schema.QueryFixture.Float32, v)) +// ColumnAddress returns the pointer to the value of the given column. +func (r *ResultSetFixture) ColumnAddress(col string) (interface{}, error) { + switch col { + case "id": + return (*kallax.ULID)(&r.ID), nil + case "foo": + return &r.Foo, nil + + default: + return nil, fmt.Errorf("kallax: invalid column in ResultSetFixture: %s", col) + } } -// FindByBoolean adds a new filter to the query that will require that -// the Boolean property is equal to the passed value. -func (q *QueryFixtureQuery) FindByBoolean(v bool) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.Boolean, v)) +// Value returns the value of the given column. +func (r *ResultSetFixture) Value(col string) (interface{}, error) { + switch col { + case "id": + return r.ID, nil + case "foo": + return r.Foo, nil + + default: + return nil, fmt.Errorf("kallax: invalid column in ResultSetFixture: %s", col) + } } -// FindByArrayParam adds a new filter to the query that will require that -// the ArrayParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindByArrayParam(v ...string) *QueryFixtureQuery { - if len(v) == 0 { - return q +// NewRelationshipRecord returns a new record for the relatiobship in the given +// field. +func (r *ResultSetFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + return nil, fmt.Errorf("kallax: model ResultSetFixture has no relationships") +} + +// SetRelationship sets the given relationship in the given field. +func (r *ResultSetFixture) SetRelationship(field string, rel interface{}) error { + return fmt.Errorf("kallax: model ResultSetFixture has no relationships") +} + +// ResultSetFixtureStore is the entity to access the records of the type ResultSetFixture +// in the database. +type ResultSetFixtureStore struct { + *kallax.Store +} + +// NewResultSetFixtureStore creates a new instance of ResultSetFixtureStore +// using a SQL database. +func NewResultSetFixtureStore(db *sql.DB) *ResultSetFixtureStore { + return &ResultSetFixtureStore{kallax.NewStore(db)} +} + +// GenericStore returns the generic store of this store. +func (s *ResultSetFixtureStore) GenericStore() *kallax.Store { + return s.Store +} + +// SetGenericStore changes the generic store of this store. +func (s *ResultSetFixtureStore) SetGenericStore(store *kallax.Store) { + s.Store = store +} + +// Debug returns a new store that will print all SQL statements to stdout using +// the log.Printf function. +func (s *ResultSetFixtureStore) Debug() *ResultSetFixtureStore { + return &ResultSetFixtureStore{s.Store.Debug()} +} + +// DebugWith returns a new store that will print all SQL statements using the +// given logger function. +func (s *ResultSetFixtureStore) DebugWith(logger kallax.LoggerFunc) *ResultSetFixtureStore { + return &ResultSetFixtureStore{s.Store.DebugWith(logger)} +} + +// Insert inserts a ResultSetFixture in the database. A non-persisted object is +// required for this operation. +func (s *ResultSetFixtureStore) Insert(record *ResultSetFixture) error { + return s.Store.Insert(Schema.ResultSetFixture.BaseSchema, record) +} + +// Update updates the given record on the database. If the columns are given, +// only these columns will be updated. Otherwise all of them will be. +// Be very careful with this, as you will have a potentially different object +// in memory but not on the database. +// Only writable records can be updated. Writable objects are those that have +// been just inserted or retrieved using a query with no custom select fields. +func (s *ResultSetFixtureStore) Update(record *ResultSetFixture, cols ...kallax.SchemaField) (updated int64, err error) { + return s.Store.Update(Schema.ResultSetFixture.BaseSchema, record, cols...) +} + +// Save inserts the object if the record is not persisted, otherwise it updates +// it. Same rules of Update and Insert apply depending on the case. +func (s *ResultSetFixtureStore) Save(record *ResultSetFixture) (updated bool, err error) { + if !record.IsPersisted() { + return false, s.Insert(record) } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val + + rowsUpdated, err := s.Update(record) + if err != nil { + return false, err } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.ArrayParam, values...)) + + return rowsUpdated > 0, nil } -// FindBySliceParam adds a new filter to the query that will require that -// the SliceParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindBySliceParam(v ...string) *QueryFixtureQuery { - if len(v) == 0 { - return q +// Delete removes the given record from the database. +func (s *ResultSetFixtureStore) Delete(record *ResultSetFixture) error { + return s.Store.Delete(Schema.ResultSetFixture.BaseSchema, record) +} + +// Find returns the set of results for the given query. +func (s *ResultSetFixtureStore) Find(q *ResultSetFixtureQuery) (*ResultSetFixtureResultSet, error) { + rs, err := s.Store.Find(q) + if err != nil { + return nil, err } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val + + return NewResultSetFixtureResultSet(rs), nil +} + +// MustFind returns the set of results for the given query, but panics if there +// is any error. +func (s *ResultSetFixtureStore) MustFind(q *ResultSetFixtureQuery) *ResultSetFixtureResultSet { + return NewResultSetFixtureResultSet(s.Store.MustFind(q)) +} + +// Count returns the number of rows that would be retrieved with the given +// query. +func (s *ResultSetFixtureStore) Count(q *ResultSetFixtureQuery) (int64, error) { + return s.Store.Count(q) +} + +// MustCount returns the number of rows that would be retrieved with the given +// query, but panics if there is an error. +func (s *ResultSetFixtureStore) MustCount(q *ResultSetFixtureQuery) int64 { + return s.Store.MustCount(q) +} + +// FindOne returns the first row returned by the given query. +// `ErrNotFound` is returned if there are no results. +func (s *ResultSetFixtureStore) FindOne(q *ResultSetFixtureQuery) (*ResultSetFixture, error) { + q.Limit(1) + q.Offset(0) + rs, err := s.Find(q) + if err != nil { + return nil, err } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.SliceParam, values...)) + + if !rs.Next() { + return nil, kallax.ErrNotFound + } + + record, err := rs.Get() + if err != nil { + return nil, err + } + + if err := rs.Close(); err != nil { + return nil, err + } + + return record, nil } -// FindByAliasArrayParam adds a new filter to the query that will require that -// the AliasArrayParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindByAliasArrayParam(v ...string) *QueryFixtureQuery { - if len(v) == 0 { - return q +// FindAll returns a list of all the rows returned by the given query. +func (s *ResultSetFixtureStore) FindAll(q *ResultSetFixtureQuery) ([]*ResultSetFixture, error) { + rs, err := s.Find(q) + if err != nil { + return nil, err } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val + + return rs.All() +} + +// MustFindOne returns the first row retrieved by the given query. It panics +// if there is an error or if there are no rows. +func (s *ResultSetFixtureStore) MustFindOne(q *ResultSetFixtureQuery) *ResultSetFixture { + record, err := s.FindOne(q) + if err != nil { + panic(err) } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasArrayParam, values...)) + return record } -// FindByAliasSliceParam adds a new filter to the query that will require that -// the AliasSliceParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindByAliasSliceParam(v ...string) *QueryFixtureQuery { - if len(v) == 0 { - return q +// Reload refreshes the ResultSetFixture with the data in the database and +// makes it writable. +func (s *ResultSetFixtureStore) Reload(record *ResultSetFixture) error { + return s.Store.Reload(Schema.ResultSetFixture.BaseSchema, record) +} + +// Transaction executes the given callback in a transaction and rollbacks if +// an error is returned. +// The transaction is only open in the store passed as a parameter to the +// callback. +func (s *ResultSetFixtureStore) Transaction(callback func(*ResultSetFixtureStore) error) error { + if callback == nil { + return kallax.ErrInvalidTxCallback } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val + + return s.Store.Transaction(func(store *kallax.Store) error { + return callback(&ResultSetFixtureStore{store}) + }) +} + +// ResultSetFixtureQuery is the object used to create queries for the ResultSetFixture +// entity. +type ResultSetFixtureQuery struct { + *kallax.BaseQuery +} + +// NewResultSetFixtureQuery returns a new instance of ResultSetFixtureQuery. +func NewResultSetFixtureQuery() *ResultSetFixtureQuery { + return &ResultSetFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.ResultSetFixture.BaseSchema), + } +} + +// Select adds columns to select in the query. +func (q *ResultSetFixtureQuery) Select(columns ...kallax.SchemaField) *ResultSetFixtureQuery { + if len(columns) == 0 { + return q } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasSliceParam, values...)) -} - -// FindByAliasStringParam adds a new filter to the query that will require that -// the AliasStringParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByAliasStringParam(v fixtures.AliasString) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.AliasStringParam, v)) + q.BaseQuery.Select(columns...) + return q } -// FindByAliasIntParam adds a new filter to the query that will require that -// the AliasIntParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByAliasIntParam(cond kallax.ScalarCond, v fixtures.AliasInt) *QueryFixtureQuery { - return q.Where(cond(Schema.QueryFixture.AliasIntParam, v)) +// SelectNot excludes columns from being selected in the query. +func (q *ResultSetFixtureQuery) SelectNot(columns ...kallax.SchemaField) *ResultSetFixtureQuery { + q.BaseQuery.SelectNot(columns...) + return q } -// FindByIDPropertyParam adds a new filter to the query that will require that -// the IDPropertyParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByIDPropertyParam(v kallax.ULID) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.IDPropertyParam, v)) +// Copy returns a new identical copy of the query. Remember queries are mutable +// so make a copy any time you need to reuse them. +func (q *ResultSetFixtureQuery) Copy() *ResultSetFixtureQuery { + return &ResultSetFixtureQuery{ + BaseQuery: q.BaseQuery.Copy(), + } } -// FindByInterfacePropParam adds a new filter to the query that will require that -// the InterfacePropParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByInterfacePropParam(v fixtures.InterfaceImplementation) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.InterfacePropParam, v)) +// Order adds order clauses to the query for the given columns. +func (q *ResultSetFixtureQuery) Order(cols ...kallax.ColumnOrder) *ResultSetFixtureQuery { + q.BaseQuery.Order(cols...) + return q } -// FindByURLParam adds a new filter to the query that will require that -// the URLParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByURLParam(v url.URL) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.URLParam, v)) +// BatchSize sets the number of items to fetch per batch when there are 1:N +// relationships selected in the query. +func (q *ResultSetFixtureQuery) BatchSize(size uint64) *ResultSetFixtureQuery { + q.BaseQuery.BatchSize(size) + return q } -// FindByTimeParam adds a new filter to the query that will require that -// the TimeParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByTimeParam(cond kallax.ScalarCond, v time.Time) *QueryFixtureQuery { - return q.Where(cond(Schema.QueryFixture.TimeParam, v)) +// Limit sets the max number of items to retrieve. +func (q *ResultSetFixtureQuery) Limit(n uint64) *ResultSetFixtureQuery { + q.BaseQuery.Limit(n) + return q } -// FindByAliasArrAliasStringParam adds a new filter to the query that will require that -// the AliasArrAliasStringParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindByAliasArrAliasStringParam(v ...fixtures.AliasString) *QueryFixtureQuery { - if len(v) == 0 { - return q - } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val - } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasArrAliasStringParam, values...)) +// Offset sets the number of items to skip from the result set of items. +func (q *ResultSetFixtureQuery) Offset(n uint64) *ResultSetFixtureQuery { + q.BaseQuery.Offset(n) + return q } -// FindByAliasHereArrayParam adds a new filter to the query that will require that -// the AliasHereArrayParam property contains all the passed values; if no passed values, -// it will do nothing. -func (q *QueryFixtureQuery) FindByAliasHereArrayParam(v ...string) *QueryFixtureQuery { - if len(v) == 0 { - return q - } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val - } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.AliasHereArrayParam, values...)) +// Where adds a condition to the query. All conditions added are concatenated +// using a logical AND. +func (q *ResultSetFixtureQuery) Where(cond kallax.Condition) *ResultSetFixtureQuery { + q.BaseQuery.Where(cond) + return q } -// FindByArrayAliasHereStringParam adds a new filter to the query that will require that -// the ArrayAliasHereStringParam property contains all the passed values; if no passed values, +// FindByID adds a new filter to the query that will require that +// the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *QueryFixtureQuery) FindByArrayAliasHereStringParam(v ...AliasHereString) *QueryFixtureQuery { +func (q *ResultSetFixtureQuery) FindByID(v ...kallax.ULID) *ResultSetFixtureQuery { if len(v) == 0 { return q } @@ -7116,33 +8535,33 @@ func (q *QueryFixtureQuery) FindByArrayAliasHereStringParam(v ...AliasHereString for i, val := range v { values[i] = val } - return q.Where(kallax.ArrayContains(Schema.QueryFixture.ArrayAliasHereStringParam, values...)) + return q.Where(kallax.In(Schema.ResultSetFixture.ID, values...)) } -// FindByScannerValuerParam adds a new filter to the query that will require that -// the ScannerValuerParam property is equal to the passed value. -func (q *QueryFixtureQuery) FindByScannerValuerParam(v ScannerValuer) *QueryFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryFixture.ScannerValuerParam, v)) +// FindByFoo adds a new filter to the query that will require that +// the Foo property is equal to the passed value. +func (q *ResultSetFixtureQuery) FindByFoo(v string) *ResultSetFixtureQuery { + return q.Where(kallax.Eq(Schema.ResultSetFixture.Foo, v)) } -// QueryFixtureResultSet is the set of results returned by a query to the +// ResultSetFixtureResultSet is the set of results returned by a query to the // database. -type QueryFixtureResultSet struct { +type ResultSetFixtureResultSet struct { ResultSet kallax.ResultSet - last *QueryFixture + last *ResultSetFixture lastErr error } -// NewQueryFixtureResultSet creates a new result set for rows of the type -// QueryFixture. -func NewQueryFixtureResultSet(rs kallax.ResultSet) *QueryFixtureResultSet { - return &QueryFixtureResultSet{ResultSet: rs} +// NewResultSetFixtureResultSet creates a new result set for rows of the type +// ResultSetFixture. +func NewResultSetFixtureResultSet(rs kallax.ResultSet) *ResultSetFixtureResultSet { + return &ResultSetFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *QueryFixtureResultSet) Next() bool { +func (rs *ResultSetFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -7150,14 +8569,14 @@ func (rs *QueryFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.QueryFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.ResultSetFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*QueryFixture) + rs.last, ok = record.(*ResultSetFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *QueryFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *ResultSetFixture") rs.last = nil } } @@ -7166,7 +8585,7 @@ func (rs *QueryFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *QueryFixtureResultSet) Get() (*QueryFixture, error) { +func (rs *ResultSetFixtureResultSet) Get() (*ResultSetFixture, error) { return rs.last, rs.lastErr } @@ -7174,7 +8593,7 @@ func (rs *QueryFixtureResultSet) Get() (*QueryFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *QueryFixtureResultSet) ForEach(fn func(*QueryFixture) error) error { +func (rs *ResultSetFixtureResultSet) ForEach(fn func(*ResultSetFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -7193,8 +8612,8 @@ func (rs *QueryFixtureResultSet) ForEach(fn func(*QueryFixture) error) error { } // All returns all records on the result set and closes the result set. -func (rs *QueryFixtureResultSet) All() ([]*QueryFixture, error) { - var result []*QueryFixture +func (rs *ResultSetFixtureResultSet) All() ([]*ResultSetFixture, error) { + var result []*ResultSetFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -7206,7 +8625,7 @@ func (rs *QueryFixtureResultSet) All() ([]*QueryFixture, error) { } // One returns the first record on the result set and closes the result set. -func (rs *QueryFixtureResultSet) One() (*QueryFixture, error) { +func (rs *ResultSetFixtureResultSet) One() (*ResultSetFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -7224,142 +8643,190 @@ func (rs *QueryFixtureResultSet) One() (*QueryFixture, error) { } // Err returns the last error occurred. -func (rs *QueryFixtureResultSet) Err() error { +func (rs *ResultSetFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *QueryFixtureResultSet) Close() error { +func (rs *ResultSetFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewQueryRelationFixture returns a new instance of QueryRelationFixture. -func NewQueryRelationFixture() (record *QueryRelationFixture) { - return new(QueryRelationFixture) +// NewSchemaFixture returns a new instance of SchemaFixture. +func NewSchemaFixture() (record *SchemaFixture) { + return newSchemaFixture() } // GetID returns the primary key of the model. -func (r *QueryRelationFixture) GetID() kallax.Identifier { +func (r *SchemaFixture) GetID() kallax.Identifier { return (*kallax.ULID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *QueryRelationFixture) ColumnAddress(col string) (interface{}, error) { +func (r *SchemaFixture) ColumnAddress(col string) (interface{}, error) { switch col { case "id": return (*kallax.ULID)(&r.ID), nil - case "name": - return &r.Name, nil - case "owner_id": - return types.Nullable(kallax.VirtualColumn("owner_id", r, new(kallax.ULID))), nil + case "string": + return &r.String, nil + case "int": + return &r.Int, nil + case "inline": + return &r.Inline.Inline, nil + case "map_of_string": + return types.JSON(&r.MapOfString), nil + case "map_of_interface": + return types.JSON(&r.MapOfInterface), nil + case "map_of_some_type": + return types.JSON(&r.MapOfSomeType), nil + case "rel_id": + return types.Nullable(kallax.VirtualColumn("rel_id", r, new(kallax.ULID))), nil default: - return nil, fmt.Errorf("kallax: invalid column in QueryRelationFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in SchemaFixture: %s", col) } } // Value returns the value of the given column. -func (r *QueryRelationFixture) Value(col string) (interface{}, error) { +func (r *SchemaFixture) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil - case "name": - return r.Name, nil - case "owner_id": + case "string": + return r.String, nil + case "int": + return r.Int, nil + case "inline": + return r.Inline.Inline, nil + case "map_of_string": + return types.JSON(r.MapOfString), nil + case "map_of_interface": + return types.JSON(r.MapOfInterface), nil + case "map_of_some_type": + return types.JSON(r.MapOfSomeType), nil + case "rel_id": return r.Model.VirtualColumn(col), nil default: - return nil, fmt.Errorf("kallax: invalid column in QueryRelationFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in SchemaFixture: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *QueryRelationFixture) NewRelationshipRecord(field string) (kallax.Record, error) { +func (r *SchemaFixture) NewRelationshipRecord(field string) (kallax.Record, error) { switch field { - case "Owner": - return new(QueryFixture), nil + case "Nested": + return new(SchemaFixture), nil + case "Inverse": + return new(SchemaRelationshipFixture), nil } - return nil, fmt.Errorf("kallax: model QueryRelationFixture has no relationship %s", field) + return nil, fmt.Errorf("kallax: model SchemaFixture has no relationship %s", field) } // SetRelationship sets the given relationship in the given field. -func (r *QueryRelationFixture) SetRelationship(field string, rel interface{}) error { +func (r *SchemaFixture) SetRelationship(field string, rel interface{}) error { switch field { - case "Owner": - val, ok := rel.(*QueryFixture) + case "Nested": + val, ok := rel.(*SchemaFixture) if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Owner", rel) + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Nested", rel) } if !val.GetID().IsEmpty() { - r.Owner = val + r.Nested = val + } + + return nil + + case "Inverse": + val, ok := rel.(*SchemaRelationshipFixture) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Inverse", rel) + } + if !val.GetID().IsEmpty() { + r.Inverse = val } return nil } - return fmt.Errorf("kallax: model QueryRelationFixture has no relationship %s", field) + return fmt.Errorf("kallax: model SchemaFixture has no relationship %s", field) } -// QueryRelationFixtureStore is the entity to access the records of the type QueryRelationFixture +// SchemaFixtureStore is the entity to access the records of the type SchemaFixture // in the database. -type QueryRelationFixtureStore struct { +type SchemaFixtureStore struct { *kallax.Store } -// NewQueryRelationFixtureStore creates a new instance of QueryRelationFixtureStore +// NewSchemaFixtureStore creates a new instance of SchemaFixtureStore // using a SQL database. -func NewQueryRelationFixtureStore(db *sql.DB) *QueryRelationFixtureStore { - return &QueryRelationFixtureStore{kallax.NewStore(db)} +func NewSchemaFixtureStore(db *sql.DB) *SchemaFixtureStore { + return &SchemaFixtureStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *QueryRelationFixtureStore) GenericStore() *kallax.Store { +func (s *SchemaFixtureStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *QueryRelationFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *SchemaFixtureStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *QueryRelationFixtureStore) Debug() *QueryRelationFixtureStore { - return &QueryRelationFixtureStore{s.Store.Debug()} +func (s *SchemaFixtureStore) Debug() *SchemaFixtureStore { + return &SchemaFixtureStore{s.Store.Debug()} +} + +// DebugWith returns a new store that will print all SQL statements using the +// given logger function. +func (s *SchemaFixtureStore) DebugWith(logger kallax.LoggerFunc) *SchemaFixtureStore { + return &SchemaFixtureStore{s.Store.DebugWith(logger)} } -// DebugWith returns a new store that will print all SQL statements using the -// given logger function. -func (s *QueryRelationFixtureStore) DebugWith(logger kallax.LoggerFunc) *QueryRelationFixtureStore { - return &QueryRelationFixtureStore{s.Store.DebugWith(logger)} +func (s *SchemaFixtureStore) relationshipRecords(record *SchemaFixture) []kallax.RecordWithSchema { + var records []kallax.RecordWithSchema + + if record.Nested != nil { + record.Nested.ClearVirtualColumns() + record.Nested.AddVirtualColumn("schema_fixture_id", record.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.SchemaFixture.BaseSchema, + Record: record.Nested, + }) + } + + return records } -func (s *QueryRelationFixtureStore) inverseRecords(record *QueryRelationFixture) []kallax.RecordWithSchema { +func (s *SchemaFixtureStore) inverseRecords(record *SchemaFixture) []kallax.RecordWithSchema { record.ClearVirtualColumns() var records []kallax.RecordWithSchema - if record.Owner != nil { - record.AddVirtualColumn("owner_id", record.Owner.GetID()) + if record.Inverse != nil { + record.AddVirtualColumn("rel_id", record.Inverse.GetID()) records = append(records, kallax.RecordWithSchema{ - Schema: Schema.QueryFixture.BaseSchema, - Record: record.Owner, + Schema: Schema.SchemaRelationshipFixture.BaseSchema, + Record: record.Inverse, }) } return records } -// Insert inserts a QueryRelationFixture in the database. A non-persisted object is +// Insert inserts a SchemaFixture in the database. A non-persisted object is // required for this operation. -func (s *QueryRelationFixtureStore) Insert(record *QueryRelationFixture) error { +func (s *SchemaFixtureStore) Insert(record *SchemaFixture) error { + records := s.relationshipRecords(record) inverseRecords := s.inverseRecords(record) - if len(inverseRecords) > 0 { + if len(records) > 0 && len(inverseRecords) > 0 { return s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -7375,16 +8842,30 @@ func (s *QueryRelationFixtureStore) Insert(record *QueryRelationFixture) error { } } - if err := s.Insert(Schema.QueryRelationFixture.BaseSchema, record); err != nil { + if err := s.Insert(Schema.SchemaFixture.BaseSchema, record); err != nil { return err } + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + return nil }) } - return s.Store.Insert(Schema.QueryRelationFixture.BaseSchema, record) - + return s.Store.Insert(Schema.SchemaFixture.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -7393,13 +8874,13 @@ func (s *QueryRelationFixtureStore) Insert(record *QueryRelationFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *QueryRelationFixtureStore) Update(record *QueryRelationFixture, cols ...kallax.SchemaField) (updated int64, err error) { +func (s *SchemaFixtureStore) Update(record *SchemaFixture, cols ...kallax.SchemaField) (updated int64, err error) { + records := s.relationshipRecords(record) inverseRecords := s.inverseRecords(record) - if len(inverseRecords) > 0 { + if len(records) > 0 && len(inverseRecords) > 0 { err = s.Store.Transaction(func(s *kallax.Store) error { - for _, r := range inverseRecords { if err := kallax.ApplyBeforeEvents(r.Record); err != nil { return err @@ -7415,11 +8896,26 @@ func (s *QueryRelationFixtureStore) Update(record *QueryRelationFixture, cols .. } } - updated, err = s.Update(Schema.QueryRelationFixture.BaseSchema, record, cols...) + updated, err = s.Update(Schema.SchemaFixture.BaseSchema, record, cols...) if err != nil { return err } + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + return nil }) if err != nil { @@ -7429,13 +8925,12 @@ func (s *QueryRelationFixtureStore) Update(record *QueryRelationFixture, cols .. return updated, nil } - return s.Store.Update(Schema.QueryRelationFixture.BaseSchema, record, cols...) - + return s.Store.Update(Schema.SchemaFixture.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *QueryRelationFixtureStore) Save(record *QueryRelationFixture) (updated bool, err error) { +func (s *SchemaFixtureStore) Save(record *SchemaFixture) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -7449,43 +8944,41 @@ func (s *QueryRelationFixtureStore) Save(record *QueryRelationFixture) (updated } // Delete removes the given record from the database. -func (s *QueryRelationFixtureStore) Delete(record *QueryRelationFixture) error { - - return s.Store.Delete(Schema.QueryRelationFixture.BaseSchema, record) - +func (s *SchemaFixtureStore) Delete(record *SchemaFixture) error { + return s.Store.Delete(Schema.SchemaFixture.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *QueryRelationFixtureStore) Find(q *QueryRelationFixtureQuery) (*QueryRelationFixtureResultSet, error) { +func (s *SchemaFixtureStore) Find(q *SchemaFixtureQuery) (*SchemaFixtureResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewQueryRelationFixtureResultSet(rs), nil + return NewSchemaFixtureResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *QueryRelationFixtureStore) MustFind(q *QueryRelationFixtureQuery) *QueryRelationFixtureResultSet { - return NewQueryRelationFixtureResultSet(s.Store.MustFind(q)) +func (s *SchemaFixtureStore) MustFind(q *SchemaFixtureQuery) *SchemaFixtureResultSet { + return NewSchemaFixtureResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *QueryRelationFixtureStore) Count(q *QueryRelationFixtureQuery) (int64, error) { +func (s *SchemaFixtureStore) Count(q *SchemaFixtureQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *QueryRelationFixtureStore) MustCount(q *QueryRelationFixtureQuery) int64 { +func (s *SchemaFixtureStore) MustCount(q *SchemaFixtureQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *QueryRelationFixtureStore) FindOne(q *QueryRelationFixtureQuery) (*QueryRelationFixture, error) { +func (s *SchemaFixtureStore) FindOne(q *SchemaFixtureQuery) (*SchemaFixture, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -7510,7 +9003,7 @@ func (s *QueryRelationFixtureStore) FindOne(q *QueryRelationFixtureQuery) (*Quer } // FindAll returns a list of all the rows returned by the given query. -func (s *QueryRelationFixtureStore) FindAll(q *QueryRelationFixtureQuery) ([]*QueryRelationFixture, error) { +func (s *SchemaFixtureStore) FindAll(q *SchemaFixtureQuery) ([]*SchemaFixture, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -7521,7 +9014,7 @@ func (s *QueryRelationFixtureStore) FindAll(q *QueryRelationFixtureQuery) ([]*Qu // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *QueryRelationFixtureStore) MustFindOne(q *QueryRelationFixtureQuery) *QueryRelationFixture { +func (s *SchemaFixtureStore) MustFindOne(q *SchemaFixtureQuery) *SchemaFixture { record, err := s.FindOne(q) if err != nil { panic(err) @@ -7529,41 +9022,72 @@ func (s *QueryRelationFixtureStore) MustFindOne(q *QueryRelationFixtureQuery) *Q return record } -// Reload refreshes the QueryRelationFixture with the data in the database and +// Reload refreshes the SchemaFixture with the data in the database and // makes it writable. -func (s *QueryRelationFixtureStore) Reload(record *QueryRelationFixture) error { - return s.Store.Reload(Schema.QueryRelationFixture.BaseSchema, record) +func (s *SchemaFixtureStore) Reload(record *SchemaFixture) error { + return s.Store.Reload(Schema.SchemaFixture.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *QueryRelationFixtureStore) Transaction(callback func(*QueryRelationFixtureStore) error) error { +func (s *SchemaFixtureStore) Transaction(callback func(*SchemaFixtureStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&QueryRelationFixtureStore{store}) + return callback(&SchemaFixtureStore{store}) }) } -// QueryRelationFixtureQuery is the object used to create queries for the QueryRelationFixture +// RemoveNested removes from the database the given relationship of the +// model. It also resets the field Nested of the model. +func (s *SchemaFixtureStore) RemoveNested(record *SchemaFixture) error { + var r kallax.Record = record.Nested + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + var err error + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + err = s.Store.Transaction(func(s *kallax.Store) error { + err := s.Delete(Schema.SchemaFixture.BaseSchema, r) + if err != nil { + return err + } + + return afterDeleter.AfterDelete() + }) + } else { + err = s.Store.Delete(Schema.SchemaFixture.BaseSchema, r) + } + if err != nil { + return err + } + + record.Nested = nil + return nil +} + +// SchemaFixtureQuery is the object used to create queries for the SchemaFixture // entity. -type QueryRelationFixtureQuery struct { +type SchemaFixtureQuery struct { *kallax.BaseQuery } -// NewQueryRelationFixtureQuery returns a new instance of QueryRelationFixtureQuery. -func NewQueryRelationFixtureQuery() *QueryRelationFixtureQuery { - return &QueryRelationFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.QueryRelationFixture.BaseSchema), +// NewSchemaFixtureQuery returns a new instance of SchemaFixtureQuery. +func NewSchemaFixtureQuery() *SchemaFixtureQuery { + return &SchemaFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.SchemaFixture.BaseSchema), } } // Select adds columns to select in the query. -func (q *QueryRelationFixtureQuery) Select(columns ...kallax.SchemaField) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) Select(columns ...kallax.SchemaField) *SchemaFixtureQuery { if len(columns) == 0 { return q } @@ -7572,60 +9096,69 @@ func (q *QueryRelationFixtureQuery) Select(columns ...kallax.SchemaField) *Query } // SelectNot excludes columns from being selected in the query. -func (q *QueryRelationFixtureQuery) SelectNot(columns ...kallax.SchemaField) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) SelectNot(columns ...kallax.SchemaField) *SchemaFixtureQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *QueryRelationFixtureQuery) Copy() *QueryRelationFixtureQuery { - return &QueryRelationFixtureQuery{ +func (q *SchemaFixtureQuery) Copy() *SchemaFixtureQuery { + return &SchemaFixtureQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *QueryRelationFixtureQuery) Order(cols ...kallax.ColumnOrder) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) Order(cols ...kallax.ColumnOrder) *SchemaFixtureQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *QueryRelationFixtureQuery) BatchSize(size uint64) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) BatchSize(size uint64) *SchemaFixtureQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *QueryRelationFixtureQuery) Limit(n uint64) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) Limit(n uint64) *SchemaFixtureQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *QueryRelationFixtureQuery) Offset(n uint64) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) Offset(n uint64) *SchemaFixtureQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *QueryRelationFixtureQuery) Where(cond kallax.Condition) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) Where(cond kallax.Condition) *SchemaFixtureQuery { q.BaseQuery.Where(cond) return q } -func (q *QueryRelationFixtureQuery) WithOwner() *QueryRelationFixtureQuery { - q.AddRelation(Schema.QueryFixture.BaseSchema, "Owner", kallax.OneToOne, nil) +// WithNested retrieves the Nested record associated with each +// record. +func (q *SchemaFixtureQuery) WithNested() *SchemaFixtureQuery { + q.AddRelation(Schema.SchemaFixture.BaseSchema, "Nested", kallax.OneToOne, nil) + return q +} + +// WithInverse retrieves the Inverse record associated with each +// record. +func (q *SchemaFixtureQuery) WithInverse() *SchemaFixtureQuery { + q.AddRelation(Schema.SchemaRelationshipFixture.BaseSchema, "Inverse", kallax.OneToOne, nil) return q } // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *QueryRelationFixtureQuery) FindByID(v ...kallax.ULID) *QueryRelationFixtureQuery { +func (q *SchemaFixtureQuery) FindByID(v ...kallax.ULID) *SchemaFixtureQuery { if len(v) == 0 { return q } @@ -7633,39 +9166,51 @@ func (q *QueryRelationFixtureQuery) FindByID(v ...kallax.ULID) *QueryRelationFix for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.QueryRelationFixture.ID, values...)) + return q.Where(kallax.In(Schema.SchemaFixture.ID, values...)) } -// FindByName adds a new filter to the query that will require that -// the Name property is equal to the passed value. -func (q *QueryRelationFixtureQuery) FindByName(v string) *QueryRelationFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryRelationFixture.Name, v)) +// FindByString adds a new filter to the query that will require that +// the String property is equal to the passed value. +func (q *SchemaFixtureQuery) FindByString(v string) *SchemaFixtureQuery { + return q.Where(kallax.Eq(Schema.SchemaFixture.String, v)) } -// FindByOwner adds a new filter to the query that will require that -// the foreign key of Owner is equal to the passed value. -func (q *QueryRelationFixtureQuery) FindByOwner(v kallax.ULID) *QueryRelationFixtureQuery { - return q.Where(kallax.Eq(Schema.QueryRelationFixture.OwnerFK, v)) +// FindByInt adds a new filter to the query that will require that +// the Int property is equal to the passed value. +func (q *SchemaFixtureQuery) FindByInt(cond kallax.ScalarCond, v int) *SchemaFixtureQuery { + return q.Where(cond(Schema.SchemaFixture.Int, v)) } -// QueryRelationFixtureResultSet is the set of results returned by a query to the +// FindByInline adds a new filter to the query that will require that +// the Inline property is equal to the passed value. +func (q *SchemaFixtureQuery) FindByInline(v string) *SchemaFixtureQuery { + return q.Where(kallax.Eq(Schema.SchemaFixture.Inline, v)) +} + +// FindByInverse adds a new filter to the query that will require that +// the foreign key of Inverse is equal to the passed value. +func (q *SchemaFixtureQuery) FindByInverse(v kallax.ULID) *SchemaFixtureQuery { + return q.Where(kallax.Eq(Schema.SchemaFixture.InverseFK, v)) +} + +// SchemaFixtureResultSet is the set of results returned by a query to the // database. -type QueryRelationFixtureResultSet struct { +type SchemaFixtureResultSet struct { ResultSet kallax.ResultSet - last *QueryRelationFixture + last *SchemaFixture lastErr error } -// NewQueryRelationFixtureResultSet creates a new result set for rows of the type -// QueryRelationFixture. -func NewQueryRelationFixtureResultSet(rs kallax.ResultSet) *QueryRelationFixtureResultSet { - return &QueryRelationFixtureResultSet{ResultSet: rs} +// NewSchemaFixtureResultSet creates a new result set for rows of the type +// SchemaFixture. +func NewSchemaFixtureResultSet(rs kallax.ResultSet) *SchemaFixtureResultSet { + return &SchemaFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *QueryRelationFixtureResultSet) Next() bool { +func (rs *SchemaFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -7673,14 +9218,14 @@ func (rs *QueryRelationFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.QueryRelationFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.SchemaFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*QueryRelationFixture) + rs.last, ok = record.(*SchemaFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *QueryRelationFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *SchemaFixture") rs.last = nil } } @@ -7689,7 +9234,7 @@ func (rs *QueryRelationFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *QueryRelationFixtureResultSet) Get() (*QueryRelationFixture, error) { +func (rs *SchemaFixtureResultSet) Get() (*SchemaFixture, error) { return rs.last, rs.lastErr } @@ -7697,7 +9242,7 @@ func (rs *QueryRelationFixtureResultSet) Get() (*QueryRelationFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *QueryRelationFixtureResultSet) ForEach(fn func(*QueryRelationFixture) error) error { +func (rs *SchemaFixtureResultSet) ForEach(fn func(*SchemaFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -7716,8 +9261,8 @@ func (rs *QueryRelationFixtureResultSet) ForEach(fn func(*QueryRelationFixture) } // All returns all records on the result set and closes the result set. -func (rs *QueryRelationFixtureResultSet) All() ([]*QueryRelationFixture, error) { - var result []*QueryRelationFixture +func (rs *SchemaFixtureResultSet) All() ([]*SchemaFixture, error) { + var result []*SchemaFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -7729,7 +9274,7 @@ func (rs *QueryRelationFixtureResultSet) All() ([]*QueryRelationFixture, error) } // One returns the first record on the result set and closes the result set. -func (rs *QueryRelationFixtureResultSet) One() (*QueryRelationFixture, error) { +func (rs *SchemaFixtureResultSet) One() (*SchemaFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -7747,102 +9292,96 @@ func (rs *QueryRelationFixtureResultSet) One() (*QueryRelationFixture, error) { } // Err returns the last error occurred. -func (rs *QueryRelationFixtureResultSet) Err() error { +func (rs *SchemaFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *QueryRelationFixtureResultSet) Close() error { +func (rs *SchemaFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewResultSetFixture returns a new instance of ResultSetFixture. -func NewResultSetFixture(f string) (record *ResultSetFixture) { - return newResultSetFixture(f) +// NewSchemaRelationshipFixture returns a new instance of SchemaRelationshipFixture. +func NewSchemaRelationshipFixture() (record *SchemaRelationshipFixture) { + return new(SchemaRelationshipFixture) } // GetID returns the primary key of the model. -func (r *ResultSetFixture) GetID() kallax.Identifier { +func (r *SchemaRelationshipFixture) GetID() kallax.Identifier { return (*kallax.ULID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *ResultSetFixture) ColumnAddress(col string) (interface{}, error) { +func (r *SchemaRelationshipFixture) ColumnAddress(col string) (interface{}, error) { switch col { case "id": return (*kallax.ULID)(&r.ID), nil - case "foo": - return &r.Foo, nil default: - return nil, fmt.Errorf("kallax: invalid column in ResultSetFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in SchemaRelationshipFixture: %s", col) } } // Value returns the value of the given column. -func (r *ResultSetFixture) Value(col string) (interface{}, error) { +func (r *SchemaRelationshipFixture) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil - case "foo": - return r.Foo, nil default: - return nil, fmt.Errorf("kallax: invalid column in ResultSetFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in SchemaRelationshipFixture: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *ResultSetFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - return nil, fmt.Errorf("kallax: model ResultSetFixture has no relationships") +func (r *SchemaRelationshipFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + return nil, fmt.Errorf("kallax: model SchemaRelationshipFixture has no relationships") } // SetRelationship sets the given relationship in the given field. -func (r *ResultSetFixture) SetRelationship(field string, rel interface{}) error { - return fmt.Errorf("kallax: model ResultSetFixture has no relationships") +func (r *SchemaRelationshipFixture) SetRelationship(field string, rel interface{}) error { + return fmt.Errorf("kallax: model SchemaRelationshipFixture has no relationships") } -// ResultSetFixtureStore is the entity to access the records of the type ResultSetFixture +// SchemaRelationshipFixtureStore is the entity to access the records of the type SchemaRelationshipFixture // in the database. -type ResultSetFixtureStore struct { +type SchemaRelationshipFixtureStore struct { *kallax.Store } -// NewResultSetFixtureStore creates a new instance of ResultSetFixtureStore +// NewSchemaRelationshipFixtureStore creates a new instance of SchemaRelationshipFixtureStore // using a SQL database. -func NewResultSetFixtureStore(db *sql.DB) *ResultSetFixtureStore { - return &ResultSetFixtureStore{kallax.NewStore(db)} +func NewSchemaRelationshipFixtureStore(db *sql.DB) *SchemaRelationshipFixtureStore { + return &SchemaRelationshipFixtureStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *ResultSetFixtureStore) GenericStore() *kallax.Store { +func (s *SchemaRelationshipFixtureStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *ResultSetFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *SchemaRelationshipFixtureStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *ResultSetFixtureStore) Debug() *ResultSetFixtureStore { - return &ResultSetFixtureStore{s.Store.Debug()} +func (s *SchemaRelationshipFixtureStore) Debug() *SchemaRelationshipFixtureStore { + return &SchemaRelationshipFixtureStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *ResultSetFixtureStore) DebugWith(logger kallax.LoggerFunc) *ResultSetFixtureStore { - return &ResultSetFixtureStore{s.Store.DebugWith(logger)} +func (s *SchemaRelationshipFixtureStore) DebugWith(logger kallax.LoggerFunc) *SchemaRelationshipFixtureStore { + return &SchemaRelationshipFixtureStore{s.Store.DebugWith(logger)} } -// Insert inserts a ResultSetFixture in the database. A non-persisted object is +// Insert inserts a SchemaRelationshipFixture in the database. A non-persisted object is // required for this operation. -func (s *ResultSetFixtureStore) Insert(record *ResultSetFixture) error { - - return s.Store.Insert(Schema.ResultSetFixture.BaseSchema, record) - +func (s *SchemaRelationshipFixtureStore) Insert(record *SchemaRelationshipFixture) error { + return s.Store.Insert(Schema.SchemaRelationshipFixture.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -7851,15 +9390,13 @@ func (s *ResultSetFixtureStore) Insert(record *ResultSetFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *ResultSetFixtureStore) Update(record *ResultSetFixture, cols ...kallax.SchemaField) (updated int64, err error) { - - return s.Store.Update(Schema.ResultSetFixture.BaseSchema, record, cols...) - +func (s *SchemaRelationshipFixtureStore) Update(record *SchemaRelationshipFixture, cols ...kallax.SchemaField) (updated int64, err error) { + return s.Store.Update(Schema.SchemaRelationshipFixture.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *ResultSetFixtureStore) Save(record *ResultSetFixture) (updated bool, err error) { +func (s *SchemaRelationshipFixtureStore) Save(record *SchemaRelationshipFixture) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -7873,43 +9410,41 @@ func (s *ResultSetFixtureStore) Save(record *ResultSetFixture) (updated bool, er } // Delete removes the given record from the database. -func (s *ResultSetFixtureStore) Delete(record *ResultSetFixture) error { - - return s.Store.Delete(Schema.ResultSetFixture.BaseSchema, record) - +func (s *SchemaRelationshipFixtureStore) Delete(record *SchemaRelationshipFixture) error { + return s.Store.Delete(Schema.SchemaRelationshipFixture.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *ResultSetFixtureStore) Find(q *ResultSetFixtureQuery) (*ResultSetFixtureResultSet, error) { +func (s *SchemaRelationshipFixtureStore) Find(q *SchemaRelationshipFixtureQuery) (*SchemaRelationshipFixtureResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewResultSetFixtureResultSet(rs), nil + return NewSchemaRelationshipFixtureResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *ResultSetFixtureStore) MustFind(q *ResultSetFixtureQuery) *ResultSetFixtureResultSet { - return NewResultSetFixtureResultSet(s.Store.MustFind(q)) +func (s *SchemaRelationshipFixtureStore) MustFind(q *SchemaRelationshipFixtureQuery) *SchemaRelationshipFixtureResultSet { + return NewSchemaRelationshipFixtureResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *ResultSetFixtureStore) Count(q *ResultSetFixtureQuery) (int64, error) { +func (s *SchemaRelationshipFixtureStore) Count(q *SchemaRelationshipFixtureQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *ResultSetFixtureStore) MustCount(q *ResultSetFixtureQuery) int64 { +func (s *SchemaRelationshipFixtureStore) MustCount(q *SchemaRelationshipFixtureQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *ResultSetFixtureStore) FindOne(q *ResultSetFixtureQuery) (*ResultSetFixture, error) { +func (s *SchemaRelationshipFixtureStore) FindOne(q *SchemaRelationshipFixtureQuery) (*SchemaRelationshipFixture, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -7934,7 +9469,7 @@ func (s *ResultSetFixtureStore) FindOne(q *ResultSetFixtureQuery) (*ResultSetFix } // FindAll returns a list of all the rows returned by the given query. -func (s *ResultSetFixtureStore) FindAll(q *ResultSetFixtureQuery) ([]*ResultSetFixture, error) { +func (s *SchemaRelationshipFixtureStore) FindAll(q *SchemaRelationshipFixtureQuery) ([]*SchemaRelationshipFixture, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -7945,7 +9480,7 @@ func (s *ResultSetFixtureStore) FindAll(q *ResultSetFixtureQuery) ([]*ResultSetF // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *ResultSetFixtureStore) MustFindOne(q *ResultSetFixtureQuery) *ResultSetFixture { +func (s *SchemaRelationshipFixtureStore) MustFindOne(q *SchemaRelationshipFixtureQuery) *SchemaRelationshipFixture { record, err := s.FindOne(q) if err != nil { panic(err) @@ -7953,41 +9488,41 @@ func (s *ResultSetFixtureStore) MustFindOne(q *ResultSetFixtureQuery) *ResultSet return record } -// Reload refreshes the ResultSetFixture with the data in the database and +// Reload refreshes the SchemaRelationshipFixture with the data in the database and // makes it writable. -func (s *ResultSetFixtureStore) Reload(record *ResultSetFixture) error { - return s.Store.Reload(Schema.ResultSetFixture.BaseSchema, record) +func (s *SchemaRelationshipFixtureStore) Reload(record *SchemaRelationshipFixture) error { + return s.Store.Reload(Schema.SchemaRelationshipFixture.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *ResultSetFixtureStore) Transaction(callback func(*ResultSetFixtureStore) error) error { +func (s *SchemaRelationshipFixtureStore) Transaction(callback func(*SchemaRelationshipFixtureStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&ResultSetFixtureStore{store}) + return callback(&SchemaRelationshipFixtureStore{store}) }) } -// ResultSetFixtureQuery is the object used to create queries for the ResultSetFixture +// SchemaRelationshipFixtureQuery is the object used to create queries for the SchemaRelationshipFixture // entity. -type ResultSetFixtureQuery struct { +type SchemaRelationshipFixtureQuery struct { *kallax.BaseQuery } -// NewResultSetFixtureQuery returns a new instance of ResultSetFixtureQuery. -func NewResultSetFixtureQuery() *ResultSetFixtureQuery { - return &ResultSetFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.ResultSetFixture.BaseSchema), +// NewSchemaRelationshipFixtureQuery returns a new instance of SchemaRelationshipFixtureQuery. +func NewSchemaRelationshipFixtureQuery() *SchemaRelationshipFixtureQuery { + return &SchemaRelationshipFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.SchemaRelationshipFixture.BaseSchema), } } // Select adds columns to select in the query. -func (q *ResultSetFixtureQuery) Select(columns ...kallax.SchemaField) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) Select(columns ...kallax.SchemaField) *SchemaRelationshipFixtureQuery { if len(columns) == 0 { return q } @@ -7996,47 +9531,47 @@ func (q *ResultSetFixtureQuery) Select(columns ...kallax.SchemaField) *ResultSet } // SelectNot excludes columns from being selected in the query. -func (q *ResultSetFixtureQuery) SelectNot(columns ...kallax.SchemaField) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) SelectNot(columns ...kallax.SchemaField) *SchemaRelationshipFixtureQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *ResultSetFixtureQuery) Copy() *ResultSetFixtureQuery { - return &ResultSetFixtureQuery{ +func (q *SchemaRelationshipFixtureQuery) Copy() *SchemaRelationshipFixtureQuery { + return &SchemaRelationshipFixtureQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *ResultSetFixtureQuery) Order(cols ...kallax.ColumnOrder) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) Order(cols ...kallax.ColumnOrder) *SchemaRelationshipFixtureQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *ResultSetFixtureQuery) BatchSize(size uint64) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) BatchSize(size uint64) *SchemaRelationshipFixtureQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *ResultSetFixtureQuery) Limit(n uint64) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) Limit(n uint64) *SchemaRelationshipFixtureQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *ResultSetFixtureQuery) Offset(n uint64) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) Offset(n uint64) *SchemaRelationshipFixtureQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *ResultSetFixtureQuery) Where(cond kallax.Condition) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) Where(cond kallax.Condition) *SchemaRelationshipFixtureQuery { q.BaseQuery.Where(cond) return q } @@ -8044,7 +9579,7 @@ func (q *ResultSetFixtureQuery) Where(cond kallax.Condition) *ResultSetFixtureQu // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *ResultSetFixtureQuery) FindByID(v ...kallax.ULID) *ResultSetFixtureQuery { +func (q *SchemaRelationshipFixtureQuery) FindByID(v ...kallax.ULID) *SchemaRelationshipFixtureQuery { if len(v) == 0 { return q } @@ -8052,33 +9587,27 @@ func (q *ResultSetFixtureQuery) FindByID(v ...kallax.ULID) *ResultSetFixtureQuer for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.ResultSetFixture.ID, values...)) -} - -// FindByFoo adds a new filter to the query that will require that -// the Foo property is equal to the passed value. -func (q *ResultSetFixtureQuery) FindByFoo(v string) *ResultSetFixtureQuery { - return q.Where(kallax.Eq(Schema.ResultSetFixture.Foo, v)) + return q.Where(kallax.In(Schema.SchemaRelationshipFixture.ID, values...)) } -// ResultSetFixtureResultSet is the set of results returned by a query to the +// SchemaRelationshipFixtureResultSet is the set of results returned by a query to the // database. -type ResultSetFixtureResultSet struct { +type SchemaRelationshipFixtureResultSet struct { ResultSet kallax.ResultSet - last *ResultSetFixture + last *SchemaRelationshipFixture lastErr error } -// NewResultSetFixtureResultSet creates a new result set for rows of the type -// ResultSetFixture. -func NewResultSetFixtureResultSet(rs kallax.ResultSet) *ResultSetFixtureResultSet { - return &ResultSetFixtureResultSet{ResultSet: rs} +// NewSchemaRelationshipFixtureResultSet creates a new result set for rows of the type +// SchemaRelationshipFixture. +func NewSchemaRelationshipFixtureResultSet(rs kallax.ResultSet) *SchemaRelationshipFixtureResultSet { + return &SchemaRelationshipFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *ResultSetFixtureResultSet) Next() bool { +func (rs *SchemaRelationshipFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -8086,14 +9615,14 @@ func (rs *ResultSetFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.ResultSetFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.SchemaRelationshipFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*ResultSetFixture) + rs.last, ok = record.(*SchemaRelationshipFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *ResultSetFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *SchemaRelationshipFixture") rs.last = nil } } @@ -8102,7 +9631,7 @@ func (rs *ResultSetFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *ResultSetFixtureResultSet) Get() (*ResultSetFixture, error) { +func (rs *SchemaRelationshipFixtureResultSet) Get() (*SchemaRelationshipFixture, error) { return rs.last, rs.lastErr } @@ -8110,7 +9639,7 @@ func (rs *ResultSetFixtureResultSet) Get() (*ResultSetFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *ResultSetFixtureResultSet) ForEach(fn func(*ResultSetFixture) error) error { +func (rs *SchemaRelationshipFixtureResultSet) ForEach(fn func(*SchemaRelationshipFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -8129,8 +9658,8 @@ func (rs *ResultSetFixtureResultSet) ForEach(fn func(*ResultSetFixture) error) e } // All returns all records on the result set and closes the result set. -func (rs *ResultSetFixtureResultSet) All() ([]*ResultSetFixture, error) { - var result []*ResultSetFixture +func (rs *SchemaRelationshipFixtureResultSet) All() ([]*SchemaRelationshipFixture, error) { + var result []*SchemaRelationshipFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -8142,7 +9671,7 @@ func (rs *ResultSetFixtureResultSet) All() ([]*ResultSetFixture, error) { } // One returns the first record on the result set and closes the result set. -func (rs *ResultSetFixtureResultSet) One() (*ResultSetFixture, error) { +func (rs *SchemaRelationshipFixtureResultSet) One() (*SchemaRelationshipFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -8160,231 +9689,108 @@ func (rs *ResultSetFixtureResultSet) One() (*ResultSetFixture, error) { } // Err returns the last error occurred. -func (rs *ResultSetFixtureResultSet) Err() error { +func (rs *SchemaRelationshipFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *ResultSetFixtureResultSet) Close() error { +func (rs *SchemaRelationshipFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewSchemaFixture returns a new instance of SchemaFixture. -func NewSchemaFixture() (record *SchemaFixture) { - return newSchemaFixture() +// NewStoreFixture returns a new instance of StoreFixture. +func NewStoreFixture() (record *StoreFixture) { + return newStoreFixture() } // GetID returns the primary key of the model. -func (r *SchemaFixture) GetID() kallax.Identifier { +func (r *StoreFixture) GetID() kallax.Identifier { return (*kallax.ULID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *SchemaFixture) ColumnAddress(col string) (interface{}, error) { +func (r *StoreFixture) ColumnAddress(col string) (interface{}, error) { switch col { case "id": return (*kallax.ULID)(&r.ID), nil - case "string": - return &r.String, nil - case "int": - return &r.Int, nil - case "inline": - return &r.Inline.Inline, nil - case "map_of_string": - return types.JSON(&r.MapOfString), nil - case "map_of_interface": - return types.JSON(&r.MapOfInterface), nil - case "map_of_some_type": - return types.JSON(&r.MapOfSomeType), nil - case "rel_id": - return types.Nullable(kallax.VirtualColumn("rel_id", r, new(kallax.ULID))), nil - - default: - return nil, fmt.Errorf("kallax: invalid column in SchemaFixture: %s", col) - } -} - -// Value returns the value of the given column. -func (r *SchemaFixture) Value(col string) (interface{}, error) { - switch col { - case "id": - return r.ID, nil - case "string": - return r.String, nil - case "int": - return r.Int, nil - case "inline": - return r.Inline.Inline, nil - case "map_of_string": - return types.JSON(r.MapOfString), nil - case "map_of_interface": - return types.JSON(r.MapOfInterface), nil - case "map_of_some_type": - return types.JSON(r.MapOfSomeType), nil - case "rel_id": - return r.Model.VirtualColumn(col), nil + case "foo": + return &r.Foo, nil + case "slice_prop": + return types.Slice(&r.SliceProp), nil + case "alias_slice_prop": + return types.Slice((*[]string)(&r.AliasSliceProp)), nil default: - return nil, fmt.Errorf("kallax: invalid column in SchemaFixture: %s", col) - } -} - -// NewRelationshipRecord returns a new record for the relatiobship in the given -// field. -func (r *SchemaFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - switch field { - case "Nested": - return new(SchemaFixture), nil - case "Inverse": - return new(SchemaRelationshipFixture), nil - + return nil, fmt.Errorf("kallax: invalid column in StoreFixture: %s", col) } - return nil, fmt.Errorf("kallax: model SchemaFixture has no relationship %s", field) -} - -// SetRelationship sets the given relationship in the given field. -func (r *SchemaFixture) SetRelationship(field string, rel interface{}) error { - switch field { - case "Nested": - val, ok := rel.(*SchemaFixture) - if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Nested", rel) - } - if !val.GetID().IsEmpty() { - r.Nested = val - } - - return nil - case "Inverse": - val, ok := rel.(*SchemaRelationshipFixture) - if !ok { - return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Inverse", rel) - } - if !val.GetID().IsEmpty() { - r.Inverse = val - } +} - return nil +// Value returns the value of the given column. +func (r *StoreFixture) Value(col string) (interface{}, error) { + switch col { + case "id": + return r.ID, nil + case "foo": + return r.Foo, nil + case "slice_prop": + return types.Slice(r.SliceProp), nil + case "alias_slice_prop": + return types.Slice(r.AliasSliceProp), nil + default: + return nil, fmt.Errorf("kallax: invalid column in StoreFixture: %s", col) } - return fmt.Errorf("kallax: model SchemaFixture has no relationship %s", field) } -// SchemaFixtureStore is the entity to access the records of the type SchemaFixture +// NewRelationshipRecord returns a new record for the relatiobship in the given +// field. +func (r *StoreFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + return nil, fmt.Errorf("kallax: model StoreFixture has no relationships") +} + +// SetRelationship sets the given relationship in the given field. +func (r *StoreFixture) SetRelationship(field string, rel interface{}) error { + return fmt.Errorf("kallax: model StoreFixture has no relationships") +} + +// StoreFixtureStore is the entity to access the records of the type StoreFixture // in the database. -type SchemaFixtureStore struct { +type StoreFixtureStore struct { *kallax.Store } -// NewSchemaFixtureStore creates a new instance of SchemaFixtureStore +// NewStoreFixtureStore creates a new instance of StoreFixtureStore // using a SQL database. -func NewSchemaFixtureStore(db *sql.DB) *SchemaFixtureStore { - return &SchemaFixtureStore{kallax.NewStore(db)} +func NewStoreFixtureStore(db *sql.DB) *StoreFixtureStore { + return &StoreFixtureStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *SchemaFixtureStore) GenericStore() *kallax.Store { +func (s *StoreFixtureStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *SchemaFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *StoreFixtureStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *SchemaFixtureStore) Debug() *SchemaFixtureStore { - return &SchemaFixtureStore{s.Store.Debug()} +func (s *StoreFixtureStore) Debug() *StoreFixtureStore { + return &StoreFixtureStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *SchemaFixtureStore) DebugWith(logger kallax.LoggerFunc) *SchemaFixtureStore { - return &SchemaFixtureStore{s.Store.DebugWith(logger)} -} - -func (s *SchemaFixtureStore) relationshipRecords(record *SchemaFixture) []kallax.RecordWithSchema { - var records []kallax.RecordWithSchema - - if record.Nested != nil { - record.Nested.ClearVirtualColumns() - record.Nested.AddVirtualColumn("schema_fixture_id", record.GetID()) - records = append(records, kallax.RecordWithSchema{ - Schema: Schema.SchemaFixture.BaseSchema, - Record: record.Nested, - }) - } - - return records -} - -func (s *SchemaFixtureStore) inverseRecords(record *SchemaFixture) []kallax.RecordWithSchema { - record.ClearVirtualColumns() - var records []kallax.RecordWithSchema - - if record.Inverse != nil { - record.AddVirtualColumn("rel_id", record.Inverse.GetID()) - records = append(records, kallax.RecordWithSchema{ - Schema: Schema.SchemaRelationshipFixture.BaseSchema, - Record: record.Inverse, - }) - } - - return records +func (s *StoreFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreFixtureStore { + return &StoreFixtureStore{s.Store.DebugWith(logger)} } -// Insert inserts a SchemaFixture in the database. A non-persisted object is +// Insert inserts a StoreFixture in the database. A non-persisted object is // required for this operation. -func (s *SchemaFixtureStore) Insert(record *SchemaFixture) error { - - records := s.relationshipRecords(record) - - inverseRecords := s.inverseRecords(record) - - if len(records) > 0 && len(inverseRecords) > 0 { - return s.Store.Transaction(func(s *kallax.Store) error { - - for _, r := range inverseRecords { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - if err := s.Insert(Schema.SchemaFixture.BaseSchema, record); err != nil { - return err - } - - for _, r := range records { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - return nil - }) - } - - return s.Store.Insert(Schema.SchemaFixture.BaseSchema, record) - +func (s *StoreFixtureStore) Insert(record *StoreFixture) error { + return s.Store.Insert(Schema.StoreFixture.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -8393,66 +9799,13 @@ func (s *SchemaFixtureStore) Insert(record *SchemaFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *SchemaFixtureStore) Update(record *SchemaFixture, cols ...kallax.SchemaField) (updated int64, err error) { - - records := s.relationshipRecords(record) - - inverseRecords := s.inverseRecords(record) - - if len(records) > 0 && len(inverseRecords) > 0 { - err = s.Store.Transaction(func(s *kallax.Store) error { - - for _, r := range inverseRecords { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - updated, err = s.Update(Schema.SchemaFixture.BaseSchema, record, cols...) - if err != nil { - return err - } - - for _, r := range records { - if err := kallax.ApplyBeforeEvents(r.Record); err != nil { - return err - } - persisted := r.Record.IsPersisted() - - if _, err := s.Save(r.Schema, r.Record); err != nil { - return err - } - - if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { - return err - } - } - - return nil - }) - if err != nil { - return 0, err - } - - return updated, nil - } - - return s.Store.Update(Schema.SchemaFixture.BaseSchema, record, cols...) - +func (s *StoreFixtureStore) Update(record *StoreFixture, cols ...kallax.SchemaField) (updated int64, err error) { + return s.Store.Update(Schema.StoreFixture.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *SchemaFixtureStore) Save(record *SchemaFixture) (updated bool, err error) { +func (s *StoreFixtureStore) Save(record *StoreFixture) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -8466,43 +9819,41 @@ func (s *SchemaFixtureStore) Save(record *SchemaFixture) (updated bool, err erro } // Delete removes the given record from the database. -func (s *SchemaFixtureStore) Delete(record *SchemaFixture) error { - - return s.Store.Delete(Schema.SchemaFixture.BaseSchema, record) - +func (s *StoreFixtureStore) Delete(record *StoreFixture) error { + return s.Store.Delete(Schema.StoreFixture.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *SchemaFixtureStore) Find(q *SchemaFixtureQuery) (*SchemaFixtureResultSet, error) { +func (s *StoreFixtureStore) Find(q *StoreFixtureQuery) (*StoreFixtureResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewSchemaFixtureResultSet(rs), nil + return NewStoreFixtureResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *SchemaFixtureStore) MustFind(q *SchemaFixtureQuery) *SchemaFixtureResultSet { - return NewSchemaFixtureResultSet(s.Store.MustFind(q)) +func (s *StoreFixtureStore) MustFind(q *StoreFixtureQuery) *StoreFixtureResultSet { + return NewStoreFixtureResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *SchemaFixtureStore) Count(q *SchemaFixtureQuery) (int64, error) { +func (s *StoreFixtureStore) Count(q *StoreFixtureQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *SchemaFixtureStore) MustCount(q *SchemaFixtureQuery) int64 { +func (s *StoreFixtureStore) MustCount(q *StoreFixtureQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *SchemaFixtureStore) FindOne(q *SchemaFixtureQuery) (*SchemaFixture, error) { +func (s *StoreFixtureStore) FindOne(q *StoreFixtureQuery) (*StoreFixture, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -8527,7 +9878,7 @@ func (s *SchemaFixtureStore) FindOne(q *SchemaFixtureQuery) (*SchemaFixture, err } // FindAll returns a list of all the rows returned by the given query. -func (s *SchemaFixtureStore) FindAll(q *SchemaFixtureQuery) ([]*SchemaFixture, error) { +func (s *StoreFixtureStore) FindAll(q *StoreFixtureQuery) ([]*StoreFixture, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -8538,7 +9889,7 @@ func (s *SchemaFixtureStore) FindAll(q *SchemaFixtureQuery) ([]*SchemaFixture, e // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *SchemaFixtureStore) MustFindOne(q *SchemaFixtureQuery) *SchemaFixture { +func (s *StoreFixtureStore) MustFindOne(q *StoreFixtureQuery) *StoreFixture { record, err := s.FindOne(q) if err != nil { panic(err) @@ -8546,72 +9897,41 @@ func (s *SchemaFixtureStore) MustFindOne(q *SchemaFixtureQuery) *SchemaFixture { return record } -// Reload refreshes the SchemaFixture with the data in the database and +// Reload refreshes the StoreFixture with the data in the database and // makes it writable. -func (s *SchemaFixtureStore) Reload(record *SchemaFixture) error { - return s.Store.Reload(Schema.SchemaFixture.BaseSchema, record) +func (s *StoreFixtureStore) Reload(record *StoreFixture) error { + return s.Store.Reload(Schema.StoreFixture.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *SchemaFixtureStore) Transaction(callback func(*SchemaFixtureStore) error) error { +func (s *StoreFixtureStore) Transaction(callback func(*StoreFixtureStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&SchemaFixtureStore{store}) + return callback(&StoreFixtureStore{store}) }) } -// RemoveNested removes from the database the given relationship of the -// model. It also resets the field Nested of the model. -func (s *SchemaFixtureStore) RemoveNested(record *SchemaFixture) error { - var r kallax.Record = record.Nested - if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { - if err := beforeDeleter.BeforeDelete(); err != nil { - return err - } - } - - var err error - if afterDeleter, ok := r.(kallax.AfterDeleter); ok { - err = s.Store.Transaction(func(s *kallax.Store) error { - err := s.Delete(Schema.SchemaFixture.BaseSchema, r) - if err != nil { - return err - } - - return afterDeleter.AfterDelete() - }) - } else { - err = s.Store.Delete(Schema.SchemaFixture.BaseSchema, r) - } - if err != nil { - return err - } - - record.Nested = nil - return nil -} - -// SchemaFixtureQuery is the object used to create queries for the SchemaFixture +// StoreFixtureQuery is the object used to create queries for the StoreFixture // entity. -type SchemaFixtureQuery struct { +type StoreFixtureQuery struct { *kallax.BaseQuery } -// NewSchemaFixtureQuery returns a new instance of SchemaFixtureQuery. -func NewSchemaFixtureQuery() *SchemaFixtureQuery { - return &SchemaFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.SchemaFixture.BaseSchema), +// NewStoreFixtureQuery returns a new instance of StoreFixtureQuery. +func NewStoreFixtureQuery() *StoreFixtureQuery { + return &StoreFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.StoreFixture.BaseSchema), } } // Select adds columns to select in the query. -func (q *SchemaFixtureQuery) Select(columns ...kallax.SchemaField) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) Select(columns ...kallax.SchemaField) *StoreFixtureQuery { if len(columns) == 0 { return q } @@ -8620,65 +9940,55 @@ func (q *SchemaFixtureQuery) Select(columns ...kallax.SchemaField) *SchemaFixtur } // SelectNot excludes columns from being selected in the query. -func (q *SchemaFixtureQuery) SelectNot(columns ...kallax.SchemaField) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreFixtureQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *SchemaFixtureQuery) Copy() *SchemaFixtureQuery { - return &SchemaFixtureQuery{ +func (q *StoreFixtureQuery) Copy() *StoreFixtureQuery { + return &StoreFixtureQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *SchemaFixtureQuery) Order(cols ...kallax.ColumnOrder) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreFixtureQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *SchemaFixtureQuery) BatchSize(size uint64) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) BatchSize(size uint64) *StoreFixtureQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *SchemaFixtureQuery) Limit(n uint64) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) Limit(n uint64) *StoreFixtureQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *SchemaFixtureQuery) Offset(n uint64) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) Offset(n uint64) *StoreFixtureQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *SchemaFixtureQuery) Where(cond kallax.Condition) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) Where(cond kallax.Condition) *StoreFixtureQuery { q.BaseQuery.Where(cond) return q } -func (q *SchemaFixtureQuery) WithNested() *SchemaFixtureQuery { - q.AddRelation(Schema.SchemaFixture.BaseSchema, "Nested", kallax.OneToOne, nil) - return q -} - -func (q *SchemaFixtureQuery) WithInverse() *SchemaFixtureQuery { - q.AddRelation(Schema.SchemaRelationshipFixture.BaseSchema, "Inverse", kallax.OneToOne, nil) - return q -} - // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *SchemaFixtureQuery) FindByID(v ...kallax.ULID) *SchemaFixtureQuery { +func (q *StoreFixtureQuery) FindByID(v ...kallax.ULID) *StoreFixtureQuery { if len(v) == 0 { return q } @@ -8686,51 +9996,61 @@ func (q *SchemaFixtureQuery) FindByID(v ...kallax.ULID) *SchemaFixtureQuery { for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.SchemaFixture.ID, values...)) -} - -// FindByString adds a new filter to the query that will require that -// the String property is equal to the passed value. -func (q *SchemaFixtureQuery) FindByString(v string) *SchemaFixtureQuery { - return q.Where(kallax.Eq(Schema.SchemaFixture.String, v)) + return q.Where(kallax.In(Schema.StoreFixture.ID, values...)) } -// FindByInt adds a new filter to the query that will require that -// the Int property is equal to the passed value. -func (q *SchemaFixtureQuery) FindByInt(cond kallax.ScalarCond, v int) *SchemaFixtureQuery { - return q.Where(cond(Schema.SchemaFixture.Int, v)) +// FindByFoo adds a new filter to the query that will require that +// the Foo property is equal to the passed value. +func (q *StoreFixtureQuery) FindByFoo(v string) *StoreFixtureQuery { + return q.Where(kallax.Eq(Schema.StoreFixture.Foo, v)) } -// FindByInline adds a new filter to the query that will require that -// the Inline property is equal to the passed value. -func (q *SchemaFixtureQuery) FindByInline(v string) *SchemaFixtureQuery { - return q.Where(kallax.Eq(Schema.SchemaFixture.Inline, v)) +// FindBySliceProp adds a new filter to the query that will require that +// the SliceProp property contains all the passed values; if no passed values, +// it will do nothing. +func (q *StoreFixtureQuery) FindBySliceProp(v ...string) *StoreFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.StoreFixture.SliceProp, values...)) } -// FindByInverse adds a new filter to the query that will require that -// the foreign key of Inverse is equal to the passed value. -func (q *SchemaFixtureQuery) FindByInverse(v kallax.ULID) *SchemaFixtureQuery { - return q.Where(kallax.Eq(Schema.SchemaFixture.InverseFK, v)) +// FindByAliasSliceProp adds a new filter to the query that will require that +// the AliasSliceProp property contains all the passed values; if no passed values, +// it will do nothing. +func (q *StoreFixtureQuery) FindByAliasSliceProp(v ...string) *StoreFixtureQuery { + if len(v) == 0 { + return q + } + values := make([]interface{}, len(v)) + for i, val := range v { + values[i] = val + } + return q.Where(kallax.ArrayContains(Schema.StoreFixture.AliasSliceProp, values...)) } -// SchemaFixtureResultSet is the set of results returned by a query to the +// StoreFixtureResultSet is the set of results returned by a query to the // database. -type SchemaFixtureResultSet struct { +type StoreFixtureResultSet struct { ResultSet kallax.ResultSet - last *SchemaFixture + last *StoreFixture lastErr error } -// NewSchemaFixtureResultSet creates a new result set for rows of the type -// SchemaFixture. -func NewSchemaFixtureResultSet(rs kallax.ResultSet) *SchemaFixtureResultSet { - return &SchemaFixtureResultSet{ResultSet: rs} +// NewStoreFixtureResultSet creates a new result set for rows of the type +// StoreFixture. +func NewStoreFixtureResultSet(rs kallax.ResultSet) *StoreFixtureResultSet { + return &StoreFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *SchemaFixtureResultSet) Next() bool { +func (rs *StoreFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -8738,14 +10058,14 @@ func (rs *SchemaFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.SchemaFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.StoreFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*SchemaFixture) + rs.last, ok = record.(*StoreFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *SchemaFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreFixture") rs.last = nil } } @@ -8754,7 +10074,7 @@ func (rs *SchemaFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *SchemaFixtureResultSet) Get() (*SchemaFixture, error) { +func (rs *StoreFixtureResultSet) Get() (*StoreFixture, error) { return rs.last, rs.lastErr } @@ -8762,7 +10082,7 @@ func (rs *SchemaFixtureResultSet) Get() (*SchemaFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *SchemaFixtureResultSet) ForEach(fn func(*SchemaFixture) error) error { +func (rs *StoreFixtureResultSet) ForEach(fn func(*StoreFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -8781,8 +10101,8 @@ func (rs *SchemaFixtureResultSet) ForEach(fn func(*SchemaFixture) error) error { } // All returns all records on the result set and closes the result set. -func (rs *SchemaFixtureResultSet) All() ([]*SchemaFixture, error) { - var result []*SchemaFixture +func (rs *StoreFixtureResultSet) All() ([]*StoreFixture, error) { + var result []*StoreFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -8794,7 +10114,7 @@ func (rs *SchemaFixtureResultSet) All() ([]*SchemaFixture, error) { } // One returns the first record on the result set and closes the result set. -func (rs *SchemaFixtureResultSet) One() (*SchemaFixture, error) { +func (rs *StoreFixtureResultSet) One() (*StoreFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -8812,98 +10132,100 @@ func (rs *SchemaFixtureResultSet) One() (*SchemaFixture, error) { } // Err returns the last error occurred. -func (rs *SchemaFixtureResultSet) Err() error { +func (rs *StoreFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *SchemaFixtureResultSet) Close() error { +func (rs *StoreFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewSchemaRelationshipFixture returns a new instance of SchemaRelationshipFixture. -func NewSchemaRelationshipFixture() (record *SchemaRelationshipFixture) { - return new(SchemaRelationshipFixture) +// NewStoreWithConstructFixture returns a new instance of StoreWithConstructFixture. +func NewStoreWithConstructFixture(f string) (record *StoreWithConstructFixture) { + return newStoreWithConstructFixture(f) } // GetID returns the primary key of the model. -func (r *SchemaRelationshipFixture) GetID() kallax.Identifier { +func (r *StoreWithConstructFixture) GetID() kallax.Identifier { return (*kallax.ULID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *SchemaRelationshipFixture) ColumnAddress(col string) (interface{}, error) { +func (r *StoreWithConstructFixture) ColumnAddress(col string) (interface{}, error) { switch col { case "id": return (*kallax.ULID)(&r.ID), nil + case "foo": + return &r.Foo, nil default: - return nil, fmt.Errorf("kallax: invalid column in SchemaRelationshipFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in StoreWithConstructFixture: %s", col) } } // Value returns the value of the given column. -func (r *SchemaRelationshipFixture) Value(col string) (interface{}, error) { +func (r *StoreWithConstructFixture) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil + case "foo": + return r.Foo, nil default: - return nil, fmt.Errorf("kallax: invalid column in SchemaRelationshipFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in StoreWithConstructFixture: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *SchemaRelationshipFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - return nil, fmt.Errorf("kallax: model SchemaRelationshipFixture has no relationships") +func (r *StoreWithConstructFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + return nil, fmt.Errorf("kallax: model StoreWithConstructFixture has no relationships") } // SetRelationship sets the given relationship in the given field. -func (r *SchemaRelationshipFixture) SetRelationship(field string, rel interface{}) error { - return fmt.Errorf("kallax: model SchemaRelationshipFixture has no relationships") +func (r *StoreWithConstructFixture) SetRelationship(field string, rel interface{}) error { + return fmt.Errorf("kallax: model StoreWithConstructFixture has no relationships") } -// SchemaRelationshipFixtureStore is the entity to access the records of the type SchemaRelationshipFixture +// StoreWithConstructFixtureStore is the entity to access the records of the type StoreWithConstructFixture // in the database. -type SchemaRelationshipFixtureStore struct { +type StoreWithConstructFixtureStore struct { *kallax.Store } -// NewSchemaRelationshipFixtureStore creates a new instance of SchemaRelationshipFixtureStore +// NewStoreWithConstructFixtureStore creates a new instance of StoreWithConstructFixtureStore // using a SQL database. -func NewSchemaRelationshipFixtureStore(db *sql.DB) *SchemaRelationshipFixtureStore { - return &SchemaRelationshipFixtureStore{kallax.NewStore(db)} +func NewStoreWithConstructFixtureStore(db *sql.DB) *StoreWithConstructFixtureStore { + return &StoreWithConstructFixtureStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *SchemaRelationshipFixtureStore) GenericStore() *kallax.Store { +func (s *StoreWithConstructFixtureStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *SchemaRelationshipFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *StoreWithConstructFixtureStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *SchemaRelationshipFixtureStore) Debug() *SchemaRelationshipFixtureStore { - return &SchemaRelationshipFixtureStore{s.Store.Debug()} +func (s *StoreWithConstructFixtureStore) Debug() *StoreWithConstructFixtureStore { + return &StoreWithConstructFixtureStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *SchemaRelationshipFixtureStore) DebugWith(logger kallax.LoggerFunc) *SchemaRelationshipFixtureStore { - return &SchemaRelationshipFixtureStore{s.Store.DebugWith(logger)} +func (s *StoreWithConstructFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreWithConstructFixtureStore { + return &StoreWithConstructFixtureStore{s.Store.DebugWith(logger)} } -// Insert inserts a SchemaRelationshipFixture in the database. A non-persisted object is +// Insert inserts a StoreWithConstructFixture in the database. A non-persisted object is // required for this operation. -func (s *SchemaRelationshipFixtureStore) Insert(record *SchemaRelationshipFixture) error { - - return s.Store.Insert(Schema.SchemaRelationshipFixture.BaseSchema, record) - +func (s *StoreWithConstructFixtureStore) Insert(record *StoreWithConstructFixture) error { + return s.Store.Insert(Schema.StoreWithConstructFixture.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -8912,15 +10234,13 @@ func (s *SchemaRelationshipFixtureStore) Insert(record *SchemaRelationshipFixtur // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *SchemaRelationshipFixtureStore) Update(record *SchemaRelationshipFixture, cols ...kallax.SchemaField) (updated int64, err error) { - - return s.Store.Update(Schema.SchemaRelationshipFixture.BaseSchema, record, cols...) - +func (s *StoreWithConstructFixtureStore) Update(record *StoreWithConstructFixture, cols ...kallax.SchemaField) (updated int64, err error) { + return s.Store.Update(Schema.StoreWithConstructFixture.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *SchemaRelationshipFixtureStore) Save(record *SchemaRelationshipFixture) (updated bool, err error) { +func (s *StoreWithConstructFixtureStore) Save(record *StoreWithConstructFixture) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -8934,43 +10254,41 @@ func (s *SchemaRelationshipFixtureStore) Save(record *SchemaRelationshipFixture) } // Delete removes the given record from the database. -func (s *SchemaRelationshipFixtureStore) Delete(record *SchemaRelationshipFixture) error { - - return s.Store.Delete(Schema.SchemaRelationshipFixture.BaseSchema, record) - +func (s *StoreWithConstructFixtureStore) Delete(record *StoreWithConstructFixture) error { + return s.Store.Delete(Schema.StoreWithConstructFixture.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *SchemaRelationshipFixtureStore) Find(q *SchemaRelationshipFixtureQuery) (*SchemaRelationshipFixtureResultSet, error) { +func (s *StoreWithConstructFixtureStore) Find(q *StoreWithConstructFixtureQuery) (*StoreWithConstructFixtureResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewSchemaRelationshipFixtureResultSet(rs), nil + return NewStoreWithConstructFixtureResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *SchemaRelationshipFixtureStore) MustFind(q *SchemaRelationshipFixtureQuery) *SchemaRelationshipFixtureResultSet { - return NewSchemaRelationshipFixtureResultSet(s.Store.MustFind(q)) +func (s *StoreWithConstructFixtureStore) MustFind(q *StoreWithConstructFixtureQuery) *StoreWithConstructFixtureResultSet { + return NewStoreWithConstructFixtureResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *SchemaRelationshipFixtureStore) Count(q *SchemaRelationshipFixtureQuery) (int64, error) { +func (s *StoreWithConstructFixtureStore) Count(q *StoreWithConstructFixtureQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *SchemaRelationshipFixtureStore) MustCount(q *SchemaRelationshipFixtureQuery) int64 { +func (s *StoreWithConstructFixtureStore) MustCount(q *StoreWithConstructFixtureQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *SchemaRelationshipFixtureStore) FindOne(q *SchemaRelationshipFixtureQuery) (*SchemaRelationshipFixture, error) { +func (s *StoreWithConstructFixtureStore) FindOne(q *StoreWithConstructFixtureQuery) (*StoreWithConstructFixture, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -8995,7 +10313,7 @@ func (s *SchemaRelationshipFixtureStore) FindOne(q *SchemaRelationshipFixtureQue } // FindAll returns a list of all the rows returned by the given query. -func (s *SchemaRelationshipFixtureStore) FindAll(q *SchemaRelationshipFixtureQuery) ([]*SchemaRelationshipFixture, error) { +func (s *StoreWithConstructFixtureStore) FindAll(q *StoreWithConstructFixtureQuery) ([]*StoreWithConstructFixture, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -9006,7 +10324,7 @@ func (s *SchemaRelationshipFixtureStore) FindAll(q *SchemaRelationshipFixtureQue // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *SchemaRelationshipFixtureStore) MustFindOne(q *SchemaRelationshipFixtureQuery) *SchemaRelationshipFixture { +func (s *StoreWithConstructFixtureStore) MustFindOne(q *StoreWithConstructFixtureQuery) *StoreWithConstructFixture { record, err := s.FindOne(q) if err != nil { panic(err) @@ -9014,41 +10332,41 @@ func (s *SchemaRelationshipFixtureStore) MustFindOne(q *SchemaRelationshipFixtur return record } -// Reload refreshes the SchemaRelationshipFixture with the data in the database and +// Reload refreshes the StoreWithConstructFixture with the data in the database and // makes it writable. -func (s *SchemaRelationshipFixtureStore) Reload(record *SchemaRelationshipFixture) error { - return s.Store.Reload(Schema.SchemaRelationshipFixture.BaseSchema, record) +func (s *StoreWithConstructFixtureStore) Reload(record *StoreWithConstructFixture) error { + return s.Store.Reload(Schema.StoreWithConstructFixture.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *SchemaRelationshipFixtureStore) Transaction(callback func(*SchemaRelationshipFixtureStore) error) error { +func (s *StoreWithConstructFixtureStore) Transaction(callback func(*StoreWithConstructFixtureStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&SchemaRelationshipFixtureStore{store}) + return callback(&StoreWithConstructFixtureStore{store}) }) } -// SchemaRelationshipFixtureQuery is the object used to create queries for the SchemaRelationshipFixture +// StoreWithConstructFixtureQuery is the object used to create queries for the StoreWithConstructFixture // entity. -type SchemaRelationshipFixtureQuery struct { +type StoreWithConstructFixtureQuery struct { *kallax.BaseQuery } -// NewSchemaRelationshipFixtureQuery returns a new instance of SchemaRelationshipFixtureQuery. -func NewSchemaRelationshipFixtureQuery() *SchemaRelationshipFixtureQuery { - return &SchemaRelationshipFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.SchemaRelationshipFixture.BaseSchema), +// NewStoreWithConstructFixtureQuery returns a new instance of StoreWithConstructFixtureQuery. +func NewStoreWithConstructFixtureQuery() *StoreWithConstructFixtureQuery { + return &StoreWithConstructFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.StoreWithConstructFixture.BaseSchema), } } // Select adds columns to select in the query. -func (q *SchemaRelationshipFixtureQuery) Select(columns ...kallax.SchemaField) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) Select(columns ...kallax.SchemaField) *StoreWithConstructFixtureQuery { if len(columns) == 0 { return q } @@ -9057,47 +10375,47 @@ func (q *SchemaRelationshipFixtureQuery) Select(columns ...kallax.SchemaField) * } // SelectNot excludes columns from being selected in the query. -func (q *SchemaRelationshipFixtureQuery) SelectNot(columns ...kallax.SchemaField) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreWithConstructFixtureQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *SchemaRelationshipFixtureQuery) Copy() *SchemaRelationshipFixtureQuery { - return &SchemaRelationshipFixtureQuery{ +func (q *StoreWithConstructFixtureQuery) Copy() *StoreWithConstructFixtureQuery { + return &StoreWithConstructFixtureQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *SchemaRelationshipFixtureQuery) Order(cols ...kallax.ColumnOrder) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreWithConstructFixtureQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *SchemaRelationshipFixtureQuery) BatchSize(size uint64) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) BatchSize(size uint64) *StoreWithConstructFixtureQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *SchemaRelationshipFixtureQuery) Limit(n uint64) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) Limit(n uint64) *StoreWithConstructFixtureQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *SchemaRelationshipFixtureQuery) Offset(n uint64) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) Offset(n uint64) *StoreWithConstructFixtureQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *SchemaRelationshipFixtureQuery) Where(cond kallax.Condition) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) Where(cond kallax.Condition) *StoreWithConstructFixtureQuery { q.BaseQuery.Where(cond) return q } @@ -9105,7 +10423,7 @@ func (q *SchemaRelationshipFixtureQuery) Where(cond kallax.Condition) *SchemaRel // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *SchemaRelationshipFixtureQuery) FindByID(v ...kallax.ULID) *SchemaRelationshipFixtureQuery { +func (q *StoreWithConstructFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithConstructFixtureQuery { if len(v) == 0 { return q } @@ -9113,27 +10431,33 @@ func (q *SchemaRelationshipFixtureQuery) FindByID(v ...kallax.ULID) *SchemaRelat for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.SchemaRelationshipFixture.ID, values...)) + return q.Where(kallax.In(Schema.StoreWithConstructFixture.ID, values...)) } -// SchemaRelationshipFixtureResultSet is the set of results returned by a query to the +// FindByFoo adds a new filter to the query that will require that +// the Foo property is equal to the passed value. +func (q *StoreWithConstructFixtureQuery) FindByFoo(v string) *StoreWithConstructFixtureQuery { + return q.Where(kallax.Eq(Schema.StoreWithConstructFixture.Foo, v)) +} + +// StoreWithConstructFixtureResultSet is the set of results returned by a query to the // database. -type SchemaRelationshipFixtureResultSet struct { +type StoreWithConstructFixtureResultSet struct { ResultSet kallax.ResultSet - last *SchemaRelationshipFixture + last *StoreWithConstructFixture lastErr error } -// NewSchemaRelationshipFixtureResultSet creates a new result set for rows of the type -// SchemaRelationshipFixture. -func NewSchemaRelationshipFixtureResultSet(rs kallax.ResultSet) *SchemaRelationshipFixtureResultSet { - return &SchemaRelationshipFixtureResultSet{ResultSet: rs} +// NewStoreWithConstructFixtureResultSet creates a new result set for rows of the type +// StoreWithConstructFixture. +func NewStoreWithConstructFixtureResultSet(rs kallax.ResultSet) *StoreWithConstructFixtureResultSet { + return &StoreWithConstructFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *SchemaRelationshipFixtureResultSet) Next() bool { +func (rs *StoreWithConstructFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -9141,14 +10465,14 @@ func (rs *SchemaRelationshipFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.SchemaRelationshipFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.StoreWithConstructFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*SchemaRelationshipFixture) + rs.last, ok = record.(*StoreWithConstructFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *SchemaRelationshipFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreWithConstructFixture") rs.last = nil } } @@ -9157,7 +10481,7 @@ func (rs *SchemaRelationshipFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *SchemaRelationshipFixtureResultSet) Get() (*SchemaRelationshipFixture, error) { +func (rs *StoreWithConstructFixtureResultSet) Get() (*StoreWithConstructFixture, error) { return rs.last, rs.lastErr } @@ -9165,7 +10489,7 @@ func (rs *SchemaRelationshipFixtureResultSet) Get() (*SchemaRelationshipFixture, // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *SchemaRelationshipFixtureResultSet) ForEach(fn func(*SchemaRelationshipFixture) error) error { +func (rs *StoreWithConstructFixtureResultSet) ForEach(fn func(*StoreWithConstructFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -9184,8 +10508,8 @@ func (rs *SchemaRelationshipFixtureResultSet) ForEach(fn func(*SchemaRelationshi } // All returns all records on the result set and closes the result set. -func (rs *SchemaRelationshipFixtureResultSet) All() ([]*SchemaRelationshipFixture, error) { - var result []*SchemaRelationshipFixture +func (rs *StoreWithConstructFixtureResultSet) All() ([]*StoreWithConstructFixture, error) { + var result []*StoreWithConstructFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -9197,7 +10521,7 @@ func (rs *SchemaRelationshipFixtureResultSet) All() ([]*SchemaRelationshipFixtur } // One returns the first record on the result set and closes the result set. -func (rs *SchemaRelationshipFixtureResultSet) One() (*SchemaRelationshipFixture, error) { +func (rs *StoreWithConstructFixtureResultSet) One() (*StoreWithConstructFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -9215,110 +10539,104 @@ func (rs *SchemaRelationshipFixtureResultSet) One() (*SchemaRelationshipFixture, } // Err returns the last error occurred. -func (rs *SchemaRelationshipFixtureResultSet) Err() error { +func (rs *StoreWithConstructFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *SchemaRelationshipFixtureResultSet) Close() error { +func (rs *StoreWithConstructFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewStoreFixture returns a new instance of StoreFixture. -func NewStoreFixture() (record *StoreFixture) { - return newStoreFixture() +// NewStoreWithNewFixture returns a new instance of StoreWithNewFixture. +func NewStoreWithNewFixture() (record *StoreWithNewFixture) { + return newStoreWithNewFixture() } // GetID returns the primary key of the model. -func (r *StoreFixture) GetID() kallax.Identifier { +func (r *StoreWithNewFixture) GetID() kallax.Identifier { return (*kallax.ULID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *StoreFixture) ColumnAddress(col string) (interface{}, error) { +func (r *StoreWithNewFixture) ColumnAddress(col string) (interface{}, error) { switch col { case "id": return (*kallax.ULID)(&r.ID), nil case "foo": return &r.Foo, nil - case "slice_prop": - return types.Slice(&r.SliceProp), nil - case "alias_slice_prop": - return types.Slice((*[]string)(&r.AliasSliceProp)), nil + case "bar": + return &r.Bar, nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in StoreWithNewFixture: %s", col) } } // Value returns the value of the given column. -func (r *StoreFixture) Value(col string) (interface{}, error) { +func (r *StoreWithNewFixture) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil case "foo": return r.Foo, nil - case "slice_prop": - return types.Slice(r.SliceProp), nil - case "alias_slice_prop": - return types.Slice(r.AliasSliceProp), nil + case "bar": + return r.Bar, nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in StoreWithNewFixture: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *StoreFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - return nil, fmt.Errorf("kallax: model StoreFixture has no relationships") +func (r *StoreWithNewFixture) NewRelationshipRecord(field string) (kallax.Record, error) { + return nil, fmt.Errorf("kallax: model StoreWithNewFixture has no relationships") } // SetRelationship sets the given relationship in the given field. -func (r *StoreFixture) SetRelationship(field string, rel interface{}) error { - return fmt.Errorf("kallax: model StoreFixture has no relationships") +func (r *StoreWithNewFixture) SetRelationship(field string, rel interface{}) error { + return fmt.Errorf("kallax: model StoreWithNewFixture has no relationships") } -// StoreFixtureStore is the entity to access the records of the type StoreFixture +// StoreWithNewFixtureStore is the entity to access the records of the type StoreWithNewFixture // in the database. -type StoreFixtureStore struct { +type StoreWithNewFixtureStore struct { *kallax.Store } -// NewStoreFixtureStore creates a new instance of StoreFixtureStore +// NewStoreWithNewFixtureStore creates a new instance of StoreWithNewFixtureStore // using a SQL database. -func NewStoreFixtureStore(db *sql.DB) *StoreFixtureStore { - return &StoreFixtureStore{kallax.NewStore(db)} +func NewStoreWithNewFixtureStore(db *sql.DB) *StoreWithNewFixtureStore { + return &StoreWithNewFixtureStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *StoreFixtureStore) GenericStore() *kallax.Store { +func (s *StoreWithNewFixtureStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *StoreFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *StoreWithNewFixtureStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *StoreFixtureStore) Debug() *StoreFixtureStore { - return &StoreFixtureStore{s.Store.Debug()} +func (s *StoreWithNewFixtureStore) Debug() *StoreWithNewFixtureStore { + return &StoreWithNewFixtureStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *StoreFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreFixtureStore { - return &StoreFixtureStore{s.Store.DebugWith(logger)} +func (s *StoreWithNewFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreWithNewFixtureStore { + return &StoreWithNewFixtureStore{s.Store.DebugWith(logger)} } -// Insert inserts a StoreFixture in the database. A non-persisted object is +// Insert inserts a StoreWithNewFixture in the database. A non-persisted object is // required for this operation. -func (s *StoreFixtureStore) Insert(record *StoreFixture) error { - - return s.Store.Insert(Schema.StoreFixture.BaseSchema, record) - +func (s *StoreWithNewFixtureStore) Insert(record *StoreWithNewFixture) error { + return s.Store.Insert(Schema.StoreWithNewFixture.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -9327,15 +10645,13 @@ func (s *StoreFixtureStore) Insert(record *StoreFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *StoreFixtureStore) Update(record *StoreFixture, cols ...kallax.SchemaField) (updated int64, err error) { - - return s.Store.Update(Schema.StoreFixture.BaseSchema, record, cols...) - +func (s *StoreWithNewFixtureStore) Update(record *StoreWithNewFixture, cols ...kallax.SchemaField) (updated int64, err error) { + return s.Store.Update(Schema.StoreWithNewFixture.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *StoreFixtureStore) Save(record *StoreFixture) (updated bool, err error) { +func (s *StoreWithNewFixtureStore) Save(record *StoreWithNewFixture) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -9349,43 +10665,41 @@ func (s *StoreFixtureStore) Save(record *StoreFixture) (updated bool, err error) } // Delete removes the given record from the database. -func (s *StoreFixtureStore) Delete(record *StoreFixture) error { - - return s.Store.Delete(Schema.StoreFixture.BaseSchema, record) - +func (s *StoreWithNewFixtureStore) Delete(record *StoreWithNewFixture) error { + return s.Store.Delete(Schema.StoreWithNewFixture.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *StoreFixtureStore) Find(q *StoreFixtureQuery) (*StoreFixtureResultSet, error) { +func (s *StoreWithNewFixtureStore) Find(q *StoreWithNewFixtureQuery) (*StoreWithNewFixtureResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewStoreFixtureResultSet(rs), nil + return NewStoreWithNewFixtureResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *StoreFixtureStore) MustFind(q *StoreFixtureQuery) *StoreFixtureResultSet { - return NewStoreFixtureResultSet(s.Store.MustFind(q)) +func (s *StoreWithNewFixtureStore) MustFind(q *StoreWithNewFixtureQuery) *StoreWithNewFixtureResultSet { + return NewStoreWithNewFixtureResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *StoreFixtureStore) Count(q *StoreFixtureQuery) (int64, error) { +func (s *StoreWithNewFixtureStore) Count(q *StoreWithNewFixtureQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *StoreFixtureStore) MustCount(q *StoreFixtureQuery) int64 { +func (s *StoreWithNewFixtureStore) MustCount(q *StoreWithNewFixtureQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *StoreFixtureStore) FindOne(q *StoreFixtureQuery) (*StoreFixture, error) { +func (s *StoreWithNewFixtureStore) FindOne(q *StoreWithNewFixtureQuery) (*StoreWithNewFixture, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -9410,7 +10724,7 @@ func (s *StoreFixtureStore) FindOne(q *StoreFixtureQuery) (*StoreFixture, error) } // FindAll returns a list of all the rows returned by the given query. -func (s *StoreFixtureStore) FindAll(q *StoreFixtureQuery) ([]*StoreFixture, error) { +func (s *StoreWithNewFixtureStore) FindAll(q *StoreWithNewFixtureQuery) ([]*StoreWithNewFixture, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -9421,7 +10735,7 @@ func (s *StoreFixtureStore) FindAll(q *StoreFixtureQuery) ([]*StoreFixture, erro // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *StoreFixtureStore) MustFindOne(q *StoreFixtureQuery) *StoreFixture { +func (s *StoreWithNewFixtureStore) MustFindOne(q *StoreWithNewFixtureQuery) *StoreWithNewFixture { record, err := s.FindOne(q) if err != nil { panic(err) @@ -9429,41 +10743,41 @@ func (s *StoreFixtureStore) MustFindOne(q *StoreFixtureQuery) *StoreFixture { return record } -// Reload refreshes the StoreFixture with the data in the database and +// Reload refreshes the StoreWithNewFixture with the data in the database and // makes it writable. -func (s *StoreFixtureStore) Reload(record *StoreFixture) error { - return s.Store.Reload(Schema.StoreFixture.BaseSchema, record) +func (s *StoreWithNewFixtureStore) Reload(record *StoreWithNewFixture) error { + return s.Store.Reload(Schema.StoreWithNewFixture.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *StoreFixtureStore) Transaction(callback func(*StoreFixtureStore) error) error { +func (s *StoreWithNewFixtureStore) Transaction(callback func(*StoreWithNewFixtureStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&StoreFixtureStore{store}) + return callback(&StoreWithNewFixtureStore{store}) }) } -// StoreFixtureQuery is the object used to create queries for the StoreFixture +// StoreWithNewFixtureQuery is the object used to create queries for the StoreWithNewFixture // entity. -type StoreFixtureQuery struct { +type StoreWithNewFixtureQuery struct { *kallax.BaseQuery } -// NewStoreFixtureQuery returns a new instance of StoreFixtureQuery. -func NewStoreFixtureQuery() *StoreFixtureQuery { - return &StoreFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.StoreFixture.BaseSchema), +// NewStoreWithNewFixtureQuery returns a new instance of StoreWithNewFixtureQuery. +func NewStoreWithNewFixtureQuery() *StoreWithNewFixtureQuery { + return &StoreWithNewFixtureQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.StoreWithNewFixture.BaseSchema), } } // Select adds columns to select in the query. -func (q *StoreFixtureQuery) Select(columns ...kallax.SchemaField) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) Select(columns ...kallax.SchemaField) *StoreWithNewFixtureQuery { if len(columns) == 0 { return q } @@ -9472,47 +10786,47 @@ func (q *StoreFixtureQuery) Select(columns ...kallax.SchemaField) *StoreFixtureQ } // SelectNot excludes columns from being selected in the query. -func (q *StoreFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreWithNewFixtureQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *StoreFixtureQuery) Copy() *StoreFixtureQuery { - return &StoreFixtureQuery{ +func (q *StoreWithNewFixtureQuery) Copy() *StoreWithNewFixtureQuery { + return &StoreWithNewFixtureQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *StoreFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreWithNewFixtureQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *StoreFixtureQuery) BatchSize(size uint64) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) BatchSize(size uint64) *StoreWithNewFixtureQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *StoreFixtureQuery) Limit(n uint64) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) Limit(n uint64) *StoreWithNewFixtureQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *StoreFixtureQuery) Offset(n uint64) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) Offset(n uint64) *StoreWithNewFixtureQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *StoreFixtureQuery) Where(cond kallax.Condition) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) Where(cond kallax.Condition) *StoreWithNewFixtureQuery { q.BaseQuery.Where(cond) return q } @@ -9520,7 +10834,7 @@ func (q *StoreFixtureQuery) Where(cond kallax.Condition) *StoreFixtureQuery { // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *StoreFixtureQuery) FindByID(v ...kallax.ULID) *StoreFixtureQuery { +func (q *StoreWithNewFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithNewFixtureQuery { if len(v) == 0 { return q } @@ -9528,61 +10842,39 @@ func (q *StoreFixtureQuery) FindByID(v ...kallax.ULID) *StoreFixtureQuery { for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.StoreFixture.ID, values...)) + return q.Where(kallax.In(Schema.StoreWithNewFixture.ID, values...)) } // FindByFoo adds a new filter to the query that will require that // the Foo property is equal to the passed value. -func (q *StoreFixtureQuery) FindByFoo(v string) *StoreFixtureQuery { - return q.Where(kallax.Eq(Schema.StoreFixture.Foo, v)) -} - -// FindBySliceProp adds a new filter to the query that will require that -// the SliceProp property contains all the passed values; if no passed values, -// it will do nothing. -func (q *StoreFixtureQuery) FindBySliceProp(v ...string) *StoreFixtureQuery { - if len(v) == 0 { - return q - } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val - } - return q.Where(kallax.ArrayContains(Schema.StoreFixture.SliceProp, values...)) +func (q *StoreWithNewFixtureQuery) FindByFoo(v string) *StoreWithNewFixtureQuery { + return q.Where(kallax.Eq(Schema.StoreWithNewFixture.Foo, v)) } -// FindByAliasSliceProp adds a new filter to the query that will require that -// the AliasSliceProp property contains all the passed values; if no passed values, -// it will do nothing. -func (q *StoreFixtureQuery) FindByAliasSliceProp(v ...string) *StoreFixtureQuery { - if len(v) == 0 { - return q - } - values := make([]interface{}, len(v)) - for i, val := range v { - values[i] = val - } - return q.Where(kallax.ArrayContains(Schema.StoreFixture.AliasSliceProp, values...)) +// FindByBar adds a new filter to the query that will require that +// the Bar property is equal to the passed value. +func (q *StoreWithNewFixtureQuery) FindByBar(v string) *StoreWithNewFixtureQuery { + return q.Where(kallax.Eq(Schema.StoreWithNewFixture.Bar, v)) } -// StoreFixtureResultSet is the set of results returned by a query to the +// StoreWithNewFixtureResultSet is the set of results returned by a query to the // database. -type StoreFixtureResultSet struct { +type StoreWithNewFixtureResultSet struct { ResultSet kallax.ResultSet - last *StoreFixture + last *StoreWithNewFixture lastErr error } -// NewStoreFixtureResultSet creates a new result set for rows of the type -// StoreFixture. -func NewStoreFixtureResultSet(rs kallax.ResultSet) *StoreFixtureResultSet { - return &StoreFixtureResultSet{ResultSet: rs} +// NewStoreWithNewFixtureResultSet creates a new result set for rows of the type +// StoreWithNewFixture. +func NewStoreWithNewFixtureResultSet(rs kallax.ResultSet) *StoreWithNewFixtureResultSet { + return &StoreWithNewFixtureResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *StoreFixtureResultSet) Next() bool { +func (rs *StoreWithNewFixtureResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -9590,14 +10882,14 @@ func (rs *StoreFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.StoreFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.StoreWithNewFixture.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*StoreFixture) + rs.last, ok = record.(*StoreWithNewFixture) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreWithNewFixture") rs.last = nil } } @@ -9606,7 +10898,7 @@ func (rs *StoreFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *StoreFixtureResultSet) Get() (*StoreFixture, error) { +func (rs *StoreWithNewFixtureResultSet) Get() (*StoreWithNewFixture, error) { return rs.last, rs.lastErr } @@ -9614,7 +10906,7 @@ func (rs *StoreFixtureResultSet) Get() (*StoreFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *StoreFixtureResultSet) ForEach(fn func(*StoreFixture) error) error { +func (rs *StoreWithNewFixtureResultSet) ForEach(fn func(*StoreWithNewFixture) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -9633,8 +10925,8 @@ func (rs *StoreFixtureResultSet) ForEach(fn func(*StoreFixture) error) error { } // All returns all records on the result set and closes the result set. -func (rs *StoreFixtureResultSet) All() ([]*StoreFixture, error) { - var result []*StoreFixture +func (rs *StoreWithNewFixtureResultSet) All() ([]*StoreWithNewFixture, error) { + var result []*StoreWithNewFixture for rs.Next() { record, err := rs.Get() if err != nil { @@ -9646,7 +10938,7 @@ func (rs *StoreFixtureResultSet) All() ([]*StoreFixture, error) { } // One returns the first record on the result set and closes the result set. -func (rs *StoreFixtureResultSet) One() (*StoreFixture, error) { +func (rs *StoreWithNewFixtureResultSet) One() (*StoreWithNewFixture, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -9664,102 +10956,165 @@ func (rs *StoreFixtureResultSet) One() (*StoreFixture, error) { } // Err returns the last error occurred. -func (rs *StoreFixtureResultSet) Err() error { +func (rs *StoreWithNewFixtureResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *StoreFixtureResultSet) Close() error { +func (rs *StoreWithNewFixtureResultSet) Close() error { return rs.ResultSet.Close() } -// NewStoreWithConstructFixture returns a new instance of StoreWithConstructFixture. -func NewStoreWithConstructFixture(f string) (record *StoreWithConstructFixture) { - return newStoreWithConstructFixture(f) +// NewUser returns a new instance of User. +func NewUser(name string) (record *User) { + return newUser(name) } // GetID returns the primary key of the model. -func (r *StoreWithConstructFixture) GetID() kallax.Identifier { - return (*kallax.ULID)(&r.ID) +func (r *User) GetID() kallax.Identifier { + return (*kallax.NumericID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *StoreWithConstructFixture) ColumnAddress(col string) (interface{}, error) { +func (r *User) ColumnAddress(col string) (interface{}, error) { switch col { case "id": - return (*kallax.ULID)(&r.ID), nil - case "foo": - return &r.Foo, nil + return (*kallax.NumericID)(&r.ID), nil + case "name": + return &r.Name, nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreWithConstructFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in User: %s", col) } } // Value returns the value of the given column. -func (r *StoreWithConstructFixture) Value(col string) (interface{}, error) { +func (r *User) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil - case "foo": - return r.Foo, nil + case "name": + return r.Name, nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreWithConstructFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in User: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *StoreWithConstructFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - return nil, fmt.Errorf("kallax: model StoreWithConstructFixture has no relationships") +func (r *User) NewRelationshipRecord(field string) (kallax.Record, error) { + switch field { + case "Posts": + return new(Post), nil + + } + return nil, fmt.Errorf("kallax: model User has no relationship %s", field) } // SetRelationship sets the given relationship in the given field. -func (r *StoreWithConstructFixture) SetRelationship(field string, rel interface{}) error { - return fmt.Errorf("kallax: model StoreWithConstructFixture has no relationships") +func (r *User) SetRelationship(field string, rel interface{}) error { + switch field { + case "Posts": + records, ok := rel.([]kallax.Record) + if !ok { + return fmt.Errorf("kallax: relationship field %s needs a collection of records, not %T", field, rel) + } + + r.Posts = make([]*Post, len(records)) + for i, record := range records { + rel, ok := record.(*Post) + if !ok { + return fmt.Errorf("kallax: element of type %T cannot be added to relationship %s", record, field) + } + r.Posts[i] = rel + } + return nil + + } + return fmt.Errorf("kallax: model User has no relationship %s", field) } -// StoreWithConstructFixtureStore is the entity to access the records of the type StoreWithConstructFixture +// UserStore is the entity to access the records of the type User // in the database. -type StoreWithConstructFixtureStore struct { +type UserStore struct { *kallax.Store } -// NewStoreWithConstructFixtureStore creates a new instance of StoreWithConstructFixtureStore +// NewUserStore creates a new instance of UserStore // using a SQL database. -func NewStoreWithConstructFixtureStore(db *sql.DB) *StoreWithConstructFixtureStore { - return &StoreWithConstructFixtureStore{kallax.NewStore(db)} +func NewUserStore(db *sql.DB) *UserStore { + return &UserStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *StoreWithConstructFixtureStore) GenericStore() *kallax.Store { +func (s *UserStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *StoreWithConstructFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *UserStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *StoreWithConstructFixtureStore) Debug() *StoreWithConstructFixtureStore { - return &StoreWithConstructFixtureStore{s.Store.Debug()} +func (s *UserStore) Debug() *UserStore { + return &UserStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *StoreWithConstructFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreWithConstructFixtureStore { - return &StoreWithConstructFixtureStore{s.Store.DebugWith(logger)} +func (s *UserStore) DebugWith(logger kallax.LoggerFunc) *UserStore { + return &UserStore{s.Store.DebugWith(logger)} } -// Insert inserts a StoreWithConstructFixture in the database. A non-persisted object is +func (s *UserStore) relationshipRecords(record *User) []kallax.RecordWithSchema { + var records []kallax.RecordWithSchema + + for i := range record.Posts { + record.Posts[i].ClearVirtualColumns() + record.Posts[i].AddVirtualColumn("user_id", record.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.Post.BaseSchema, + Record: record.Posts[i], + }) + } + + return records +} + +// Insert inserts a User in the database. A non-persisted object is // required for this operation. -func (s *StoreWithConstructFixtureStore) Insert(record *StoreWithConstructFixture) error { +func (s *UserStore) Insert(record *User) error { + records := s.relationshipRecords(record) - return s.Store.Insert(Schema.StoreWithConstructFixture.BaseSchema, record) + if len(records) > 0 { + return s.Store.Transaction(func(s *kallax.Store) error { + if err := s.Insert(Schema.User.BaseSchema, record); err != nil { + return err + } + + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + return nil + }) + } + return s.Store.Insert(Schema.User.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -9768,15 +11123,46 @@ func (s *StoreWithConstructFixtureStore) Insert(record *StoreWithConstructFixtur // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *StoreWithConstructFixtureStore) Update(record *StoreWithConstructFixture, cols ...kallax.SchemaField) (updated int64, err error) { +func (s *UserStore) Update(record *User, cols ...kallax.SchemaField) (updated int64, err error) { + records := s.relationshipRecords(record) - return s.Store.Update(Schema.StoreWithConstructFixture.BaseSchema, record, cols...) + if len(records) > 0 { + err = s.Store.Transaction(func(s *kallax.Store) error { + updated, err = s.Update(Schema.User.BaseSchema, record, cols...) + if err != nil { + return err + } + + for _, r := range records { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + return nil + }) + if err != nil { + return 0, err + } + + return updated, nil + } + return s.Store.Update(Schema.User.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *StoreWithConstructFixtureStore) Save(record *StoreWithConstructFixture) (updated bool, err error) { +func (s *UserStore) Save(record *User) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -9790,43 +11176,41 @@ func (s *StoreWithConstructFixtureStore) Save(record *StoreWithConstructFixture) } // Delete removes the given record from the database. -func (s *StoreWithConstructFixtureStore) Delete(record *StoreWithConstructFixture) error { - - return s.Store.Delete(Schema.StoreWithConstructFixture.BaseSchema, record) - +func (s *UserStore) Delete(record *User) error { + return s.Store.Delete(Schema.User.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *StoreWithConstructFixtureStore) Find(q *StoreWithConstructFixtureQuery) (*StoreWithConstructFixtureResultSet, error) { +func (s *UserStore) Find(q *UserQuery) (*UserResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewStoreWithConstructFixtureResultSet(rs), nil + return NewUserResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *StoreWithConstructFixtureStore) MustFind(q *StoreWithConstructFixtureQuery) *StoreWithConstructFixtureResultSet { - return NewStoreWithConstructFixtureResultSet(s.Store.MustFind(q)) +func (s *UserStore) MustFind(q *UserQuery) *UserResultSet { + return NewUserResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *StoreWithConstructFixtureStore) Count(q *StoreWithConstructFixtureQuery) (int64, error) { +func (s *UserStore) Count(q *UserQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *StoreWithConstructFixtureStore) MustCount(q *StoreWithConstructFixtureQuery) int64 { +func (s *UserStore) MustCount(q *UserQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *StoreWithConstructFixtureStore) FindOne(q *StoreWithConstructFixtureQuery) (*StoreWithConstructFixture, error) { +func (s *UserStore) FindOne(q *UserQuery) (*User, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -9851,7 +11235,7 @@ func (s *StoreWithConstructFixtureStore) FindOne(q *StoreWithConstructFixtureQue } // FindAll returns a list of all the rows returned by the given query. -func (s *StoreWithConstructFixtureStore) FindAll(q *StoreWithConstructFixtureQuery) ([]*StoreWithConstructFixture, error) { +func (s *UserStore) FindAll(q *UserQuery) ([]*User, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -9862,7 +11246,7 @@ func (s *StoreWithConstructFixtureStore) FindAll(q *StoreWithConstructFixtureQue // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *StoreWithConstructFixtureStore) MustFindOne(q *StoreWithConstructFixtureQuery) *StoreWithConstructFixture { +func (s *UserStore) MustFindOne(q *UserQuery) *User { record, err := s.FindOne(q) if err != nil { panic(err) @@ -9870,41 +11254,130 @@ func (s *StoreWithConstructFixtureStore) MustFindOne(q *StoreWithConstructFixtur return record } -// Reload refreshes the StoreWithConstructFixture with the data in the database and +// Reload refreshes the User with the data in the database and // makes it writable. -func (s *StoreWithConstructFixtureStore) Reload(record *StoreWithConstructFixture) error { - return s.Store.Reload(Schema.StoreWithConstructFixture.BaseSchema, record) +func (s *UserStore) Reload(record *User) error { + return s.Store.Reload(Schema.User.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *StoreWithConstructFixtureStore) Transaction(callback func(*StoreWithConstructFixtureStore) error) error { +func (s *UserStore) Transaction(callback func(*UserStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&StoreWithConstructFixtureStore{store}) + return callback(&UserStore{store}) }) } -// StoreWithConstructFixtureQuery is the object used to create queries for the StoreWithConstructFixture +// RemovePosts removes the given items of the Posts field of the +// model. If no items are given, it removes all of them. +// The items will also be removed from the passed record inside this method. +func (s *UserStore) RemovePosts(record *User, deleted ...*Post) error { + var updated []*Post + var clear bool + if len(deleted) == 0 { + clear = true + deleted = record.Posts + if len(deleted) == 0 { + return nil + } + } + + if len(deleted) > 1 { + err := s.Store.Transaction(func(s *kallax.Store) error { + for _, d := range deleted { + var r kallax.Record = d + + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + if err := s.Delete(Schema.Post.BaseSchema, d); err != nil { + return err + } + + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + if err := afterDeleter.AfterDelete(); err != nil { + return err + } + } + } + return nil + }) + + if err != nil { + return err + } + + if clear { + record.Posts = nil + return nil + } + } else { + var r kallax.Record = deleted[0] + if beforeDeleter, ok := r.(kallax.BeforeDeleter); ok { + if err := beforeDeleter.BeforeDelete(); err != nil { + return err + } + } + + var err error + if afterDeleter, ok := r.(kallax.AfterDeleter); ok { + err = s.Store.Transaction(func(s *kallax.Store) error { + err := s.Delete(Schema.Post.BaseSchema, r) + if err != nil { + return err + } + + return afterDeleter.AfterDelete() + }) + } else { + err = s.Store.Delete(Schema.Post.BaseSchema, deleted[0]) + } + + if err != nil { + return err + } + } + + for _, r := range record.Posts { + var found bool + for _, d := range deleted { + if d.GetID().Equals(r.GetID()) { + found = true + break + } + } + if !found { + updated = append(updated, r) + } + } + record.Posts = updated + return nil +} + +// UserQuery is the object used to create queries for the User // entity. -type StoreWithConstructFixtureQuery struct { +type UserQuery struct { *kallax.BaseQuery } -// NewStoreWithConstructFixtureQuery returns a new instance of StoreWithConstructFixtureQuery. -func NewStoreWithConstructFixtureQuery() *StoreWithConstructFixtureQuery { - return &StoreWithConstructFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.StoreWithConstructFixture.BaseSchema), +// NewUserQuery returns a new instance of UserQuery. +func NewUserQuery() *UserQuery { + return &UserQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.User.BaseSchema), } } // Select adds columns to select in the query. -func (q *StoreWithConstructFixtureQuery) Select(columns ...kallax.SchemaField) *StoreWithConstructFixtureQuery { +func (q *UserQuery) Select(columns ...kallax.SchemaField) *UserQuery { if len(columns) == 0 { return q } @@ -9913,55 +11386,73 @@ func (q *StoreWithConstructFixtureQuery) Select(columns ...kallax.SchemaField) * } // SelectNot excludes columns from being selected in the query. -func (q *StoreWithConstructFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreWithConstructFixtureQuery { +func (q *UserQuery) SelectNot(columns ...kallax.SchemaField) *UserQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *StoreWithConstructFixtureQuery) Copy() *StoreWithConstructFixtureQuery { - return &StoreWithConstructFixtureQuery{ +func (q *UserQuery) Copy() *UserQuery { + return &UserQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *StoreWithConstructFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreWithConstructFixtureQuery { +func (q *UserQuery) Order(cols ...kallax.ColumnOrder) *UserQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *StoreWithConstructFixtureQuery) BatchSize(size uint64) *StoreWithConstructFixtureQuery { +func (q *UserQuery) BatchSize(size uint64) *UserQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *StoreWithConstructFixtureQuery) Limit(n uint64) *StoreWithConstructFixtureQuery { +func (q *UserQuery) Limit(n uint64) *UserQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *StoreWithConstructFixtureQuery) Offset(n uint64) *StoreWithConstructFixtureQuery { +func (q *UserQuery) Offset(n uint64) *UserQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *StoreWithConstructFixtureQuery) Where(cond kallax.Condition) *StoreWithConstructFixtureQuery { +func (q *UserQuery) Where(cond kallax.Condition) *UserQuery { q.BaseQuery.Where(cond) return q } +// WithPosts retrieves all the Posts records associated with each +// record. Two conditions can be passed, the first to filter the table used +// to join Posts and User and the second one to filter +// Posts directly. +func (q *UserQuery) WithPosts( + filterUserPost kallax.Condition, + filterPost kallax.Condition, +) *UserQuery { + q.AddRelationThrough( + Schema.Post.BaseSchema, + Schema.UserPost.BaseSchema, + "Posts", + filterUserPost, + filterPost, + ) + return q +} + // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *StoreWithConstructFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithConstructFixtureQuery { +func (q *UserQuery) FindByID(v ...int64) *UserQuery { if len(v) == 0 { return q } @@ -9969,33 +11460,33 @@ func (q *StoreWithConstructFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithCo for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.StoreWithConstructFixture.ID, values...)) + return q.Where(kallax.In(Schema.User.ID, values...)) } -// FindByFoo adds a new filter to the query that will require that -// the Foo property is equal to the passed value. -func (q *StoreWithConstructFixtureQuery) FindByFoo(v string) *StoreWithConstructFixtureQuery { - return q.Where(kallax.Eq(Schema.StoreWithConstructFixture.Foo, v)) +// FindByName adds a new filter to the query that will require that +// the Name property is equal to the passed value. +func (q *UserQuery) FindByName(v string) *UserQuery { + return q.Where(kallax.Eq(Schema.User.Name, v)) } -// StoreWithConstructFixtureResultSet is the set of results returned by a query to the +// UserResultSet is the set of results returned by a query to the // database. -type StoreWithConstructFixtureResultSet struct { +type UserResultSet struct { ResultSet kallax.ResultSet - last *StoreWithConstructFixture + last *User lastErr error } -// NewStoreWithConstructFixtureResultSet creates a new result set for rows of the type -// StoreWithConstructFixture. -func NewStoreWithConstructFixtureResultSet(rs kallax.ResultSet) *StoreWithConstructFixtureResultSet { - return &StoreWithConstructFixtureResultSet{ResultSet: rs} +// NewUserResultSet creates a new result set for rows of the type +// User. +func NewUserResultSet(rs kallax.ResultSet) *UserResultSet { + return &UserResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *StoreWithConstructFixtureResultSet) Next() bool { +func (rs *UserResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -10003,14 +11494,14 @@ func (rs *StoreWithConstructFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.StoreWithConstructFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.User.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*StoreWithConstructFixture) + rs.last, ok = record.(*User) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreWithConstructFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *User") rs.last = nil } } @@ -10019,7 +11510,7 @@ func (rs *StoreWithConstructFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *StoreWithConstructFixtureResultSet) Get() (*StoreWithConstructFixture, error) { +func (rs *UserResultSet) Get() (*User, error) { return rs.last, rs.lastErr } @@ -10027,7 +11518,7 @@ func (rs *StoreWithConstructFixtureResultSet) Get() (*StoreWithConstructFixture, // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *StoreWithConstructFixtureResultSet) ForEach(fn func(*StoreWithConstructFixture) error) error { +func (rs *UserResultSet) ForEach(fn func(*User) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -10046,8 +11537,8 @@ func (rs *StoreWithConstructFixtureResultSet) ForEach(fn func(*StoreWithConstruc } // All returns all records on the result set and closes the result set. -func (rs *StoreWithConstructFixtureResultSet) All() ([]*StoreWithConstructFixture, error) { - var result []*StoreWithConstructFixture +func (rs *UserResultSet) All() ([]*User, error) { + var result []*User for rs.Next() { record, err := rs.Get() if err != nil { @@ -10059,7 +11550,7 @@ func (rs *StoreWithConstructFixtureResultSet) All() ([]*StoreWithConstructFixtur } // One returns the first record on the result set and closes the result set. -func (rs *StoreWithConstructFixtureResultSet) One() (*StoreWithConstructFixture, error) { +func (rs *UserResultSet) One() (*User, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -10077,106 +11568,185 @@ func (rs *StoreWithConstructFixtureResultSet) One() (*StoreWithConstructFixture, } // Err returns the last error occurred. -func (rs *StoreWithConstructFixtureResultSet) Err() error { +func (rs *UserResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *StoreWithConstructFixtureResultSet) Close() error { +func (rs *UserResultSet) Close() error { return rs.ResultSet.Close() } -// NewStoreWithNewFixture returns a new instance of StoreWithNewFixture. -func NewStoreWithNewFixture() (record *StoreWithNewFixture) { - return newStoreWithNewFixture() +// NewUserPost returns a new instance of UserPost. +func NewUserPost(user *User, post *Post) (record *UserPost) { + return newUserPost(user, post) } // GetID returns the primary key of the model. -func (r *StoreWithNewFixture) GetID() kallax.Identifier { - return (*kallax.ULID)(&r.ID) +func (r *UserPost) GetID() kallax.Identifier { + return (*kallax.NumericID)(&r.ID) } // ColumnAddress returns the pointer to the value of the given column. -func (r *StoreWithNewFixture) ColumnAddress(col string) (interface{}, error) { +func (r *UserPost) ColumnAddress(col string) (interface{}, error) { switch col { case "id": - return (*kallax.ULID)(&r.ID), nil - case "foo": - return &r.Foo, nil - case "bar": - return &r.Bar, nil + return (*kallax.NumericID)(&r.ID), nil + case "user_id": + return types.Nullable(kallax.VirtualColumn("user_id", r, new(kallax.NumericID))), nil + case "post_id": + return types.Nullable(kallax.VirtualColumn("post_id", r, new(kallax.NumericID))), nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreWithNewFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in UserPost: %s", col) } } // Value returns the value of the given column. -func (r *StoreWithNewFixture) Value(col string) (interface{}, error) { +func (r *UserPost) Value(col string) (interface{}, error) { switch col { case "id": return r.ID, nil - case "foo": - return r.Foo, nil - case "bar": - return r.Bar, nil + case "user_id": + return r.Model.VirtualColumn(col), nil + case "post_id": + return r.Model.VirtualColumn(col), nil default: - return nil, fmt.Errorf("kallax: invalid column in StoreWithNewFixture: %s", col) + return nil, fmt.Errorf("kallax: invalid column in UserPost: %s", col) } } // NewRelationshipRecord returns a new record for the relatiobship in the given // field. -func (r *StoreWithNewFixture) NewRelationshipRecord(field string) (kallax.Record, error) { - return nil, fmt.Errorf("kallax: model StoreWithNewFixture has no relationships") +func (r *UserPost) NewRelationshipRecord(field string) (kallax.Record, error) { + switch field { + case "User": + return new(User), nil + case "Post": + return new(Post), nil + + } + return nil, fmt.Errorf("kallax: model UserPost has no relationship %s", field) } // SetRelationship sets the given relationship in the given field. -func (r *StoreWithNewFixture) SetRelationship(field string, rel interface{}) error { - return fmt.Errorf("kallax: model StoreWithNewFixture has no relationships") +func (r *UserPost) SetRelationship(field string, rel interface{}) error { + switch field { + case "User": + val, ok := rel.(*User) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship User", rel) + } + if !val.GetID().IsEmpty() { + r.User = val + } + + return nil + + case "Post": + val, ok := rel.(*Post) + if !ok { + return fmt.Errorf("kallax: record of type %t can't be assigned to relationship Post", rel) + } + if !val.GetID().IsEmpty() { + r.Post = val + } + + return nil + + } + return fmt.Errorf("kallax: model UserPost has no relationship %s", field) } -// StoreWithNewFixtureStore is the entity to access the records of the type StoreWithNewFixture +// UserPostStore is the entity to access the records of the type UserPost // in the database. -type StoreWithNewFixtureStore struct { +type UserPostStore struct { *kallax.Store } -// NewStoreWithNewFixtureStore creates a new instance of StoreWithNewFixtureStore +// NewUserPostStore creates a new instance of UserPostStore // using a SQL database. -func NewStoreWithNewFixtureStore(db *sql.DB) *StoreWithNewFixtureStore { - return &StoreWithNewFixtureStore{kallax.NewStore(db)} +func NewUserPostStore(db *sql.DB) *UserPostStore { + return &UserPostStore{kallax.NewStore(db)} } // GenericStore returns the generic store of this store. -func (s *StoreWithNewFixtureStore) GenericStore() *kallax.Store { +func (s *UserPostStore) GenericStore() *kallax.Store { return s.Store } // SetGenericStore changes the generic store of this store. -func (s *StoreWithNewFixtureStore) SetGenericStore(store *kallax.Store) { +func (s *UserPostStore) SetGenericStore(store *kallax.Store) { s.Store = store } // Debug returns a new store that will print all SQL statements to stdout using // the log.Printf function. -func (s *StoreWithNewFixtureStore) Debug() *StoreWithNewFixtureStore { - return &StoreWithNewFixtureStore{s.Store.Debug()} +func (s *UserPostStore) Debug() *UserPostStore { + return &UserPostStore{s.Store.Debug()} } // DebugWith returns a new store that will print all SQL statements using the // given logger function. -func (s *StoreWithNewFixtureStore) DebugWith(logger kallax.LoggerFunc) *StoreWithNewFixtureStore { - return &StoreWithNewFixtureStore{s.Store.DebugWith(logger)} +func (s *UserPostStore) DebugWith(logger kallax.LoggerFunc) *UserPostStore { + return &UserPostStore{s.Store.DebugWith(logger)} } -// Insert inserts a StoreWithNewFixture in the database. A non-persisted object is +func (s *UserPostStore) inverseRecords(record *UserPost) []kallax.RecordWithSchema { + record.ClearVirtualColumns() + var records []kallax.RecordWithSchema + + if record.User != nil { + record.AddVirtualColumn("user_id", record.User.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.User.BaseSchema, + Record: record.User, + }) + } + + if record.Post != nil { + record.AddVirtualColumn("post_id", record.Post.GetID()) + records = append(records, kallax.RecordWithSchema{ + Schema: Schema.Post.BaseSchema, + Record: record.Post, + }) + } + + return records +} + +// Insert inserts a UserPost in the database. A non-persisted object is // required for this operation. -func (s *StoreWithNewFixtureStore) Insert(record *StoreWithNewFixture) error { +func (s *UserPostStore) Insert(record *UserPost) error { + inverseRecords := s.inverseRecords(record) - return s.Store.Insert(Schema.StoreWithNewFixture.BaseSchema, record) + if len(inverseRecords) > 0 { + return s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + if err := s.Insert(Schema.UserPost.BaseSchema, record); err != nil { + return err + } + + return nil + }) + } + return s.Store.Insert(Schema.UserPost.BaseSchema, record) } // Update updates the given record on the database. If the columns are given, @@ -10185,15 +11755,46 @@ func (s *StoreWithNewFixtureStore) Insert(record *StoreWithNewFixture) error { // in memory but not on the database. // Only writable records can be updated. Writable objects are those that have // been just inserted or retrieved using a query with no custom select fields. -func (s *StoreWithNewFixtureStore) Update(record *StoreWithNewFixture, cols ...kallax.SchemaField) (updated int64, err error) { +func (s *UserPostStore) Update(record *UserPost, cols ...kallax.SchemaField) (updated int64, err error) { + inverseRecords := s.inverseRecords(record) - return s.Store.Update(Schema.StoreWithNewFixture.BaseSchema, record, cols...) + if len(inverseRecords) > 0 { + err = s.Store.Transaction(func(s *kallax.Store) error { + for _, r := range inverseRecords { + if err := kallax.ApplyBeforeEvents(r.Record); err != nil { + return err + } + persisted := r.Record.IsPersisted() + + if _, err := s.Save(r.Schema, r.Record); err != nil { + return err + } + + if err := kallax.ApplyAfterEvents(r.Record, persisted); err != nil { + return err + } + } + + updated, err = s.Update(Schema.UserPost.BaseSchema, record, cols...) + if err != nil { + return err + } + return nil + }) + if err != nil { + return 0, err + } + + return updated, nil + } + + return s.Store.Update(Schema.UserPost.BaseSchema, record, cols...) } // Save inserts the object if the record is not persisted, otherwise it updates // it. Same rules of Update and Insert apply depending on the case. -func (s *StoreWithNewFixtureStore) Save(record *StoreWithNewFixture) (updated bool, err error) { +func (s *UserPostStore) Save(record *UserPost) (updated bool, err error) { if !record.IsPersisted() { return false, s.Insert(record) } @@ -10207,43 +11808,41 @@ func (s *StoreWithNewFixtureStore) Save(record *StoreWithNewFixture) (updated bo } // Delete removes the given record from the database. -func (s *StoreWithNewFixtureStore) Delete(record *StoreWithNewFixture) error { - - return s.Store.Delete(Schema.StoreWithNewFixture.BaseSchema, record) - +func (s *UserPostStore) Delete(record *UserPost) error { + return s.Store.Delete(Schema.UserPost.BaseSchema, record) } // Find returns the set of results for the given query. -func (s *StoreWithNewFixtureStore) Find(q *StoreWithNewFixtureQuery) (*StoreWithNewFixtureResultSet, error) { +func (s *UserPostStore) Find(q *UserPostQuery) (*UserPostResultSet, error) { rs, err := s.Store.Find(q) if err != nil { return nil, err } - return NewStoreWithNewFixtureResultSet(rs), nil + return NewUserPostResultSet(rs), nil } // MustFind returns the set of results for the given query, but panics if there // is any error. -func (s *StoreWithNewFixtureStore) MustFind(q *StoreWithNewFixtureQuery) *StoreWithNewFixtureResultSet { - return NewStoreWithNewFixtureResultSet(s.Store.MustFind(q)) +func (s *UserPostStore) MustFind(q *UserPostQuery) *UserPostResultSet { + return NewUserPostResultSet(s.Store.MustFind(q)) } // Count returns the number of rows that would be retrieved with the given // query. -func (s *StoreWithNewFixtureStore) Count(q *StoreWithNewFixtureQuery) (int64, error) { +func (s *UserPostStore) Count(q *UserPostQuery) (int64, error) { return s.Store.Count(q) } // MustCount returns the number of rows that would be retrieved with the given // query, but panics if there is an error. -func (s *StoreWithNewFixtureStore) MustCount(q *StoreWithNewFixtureQuery) int64 { +func (s *UserPostStore) MustCount(q *UserPostQuery) int64 { return s.Store.MustCount(q) } // FindOne returns the first row returned by the given query. // `ErrNotFound` is returned if there are no results. -func (s *StoreWithNewFixtureStore) FindOne(q *StoreWithNewFixtureQuery) (*StoreWithNewFixture, error) { +func (s *UserPostStore) FindOne(q *UserPostQuery) (*UserPost, error) { q.Limit(1) q.Offset(0) rs, err := s.Find(q) @@ -10268,7 +11867,7 @@ func (s *StoreWithNewFixtureStore) FindOne(q *StoreWithNewFixtureQuery) (*StoreW } // FindAll returns a list of all the rows returned by the given query. -func (s *StoreWithNewFixtureStore) FindAll(q *StoreWithNewFixtureQuery) ([]*StoreWithNewFixture, error) { +func (s *UserPostStore) FindAll(q *UserPostQuery) ([]*UserPost, error) { rs, err := s.Find(q) if err != nil { return nil, err @@ -10279,7 +11878,7 @@ func (s *StoreWithNewFixtureStore) FindAll(q *StoreWithNewFixtureQuery) ([]*Stor // MustFindOne returns the first row retrieved by the given query. It panics // if there is an error or if there are no rows. -func (s *StoreWithNewFixtureStore) MustFindOne(q *StoreWithNewFixtureQuery) *StoreWithNewFixture { +func (s *UserPostStore) MustFindOne(q *UserPostQuery) *UserPost { record, err := s.FindOne(q) if err != nil { panic(err) @@ -10287,41 +11886,41 @@ func (s *StoreWithNewFixtureStore) MustFindOne(q *StoreWithNewFixtureQuery) *Sto return record } -// Reload refreshes the StoreWithNewFixture with the data in the database and +// Reload refreshes the UserPost with the data in the database and // makes it writable. -func (s *StoreWithNewFixtureStore) Reload(record *StoreWithNewFixture) error { - return s.Store.Reload(Schema.StoreWithNewFixture.BaseSchema, record) +func (s *UserPostStore) Reload(record *UserPost) error { + return s.Store.Reload(Schema.UserPost.BaseSchema, record) } // Transaction executes the given callback in a transaction and rollbacks if // an error is returned. // The transaction is only open in the store passed as a parameter to the // callback. -func (s *StoreWithNewFixtureStore) Transaction(callback func(*StoreWithNewFixtureStore) error) error { +func (s *UserPostStore) Transaction(callback func(*UserPostStore) error) error { if callback == nil { return kallax.ErrInvalidTxCallback } return s.Store.Transaction(func(store *kallax.Store) error { - return callback(&StoreWithNewFixtureStore{store}) + return callback(&UserPostStore{store}) }) } -// StoreWithNewFixtureQuery is the object used to create queries for the StoreWithNewFixture +// UserPostQuery is the object used to create queries for the UserPost // entity. -type StoreWithNewFixtureQuery struct { +type UserPostQuery struct { *kallax.BaseQuery } -// NewStoreWithNewFixtureQuery returns a new instance of StoreWithNewFixtureQuery. -func NewStoreWithNewFixtureQuery() *StoreWithNewFixtureQuery { - return &StoreWithNewFixtureQuery{ - BaseQuery: kallax.NewBaseQuery(Schema.StoreWithNewFixture.BaseSchema), +// NewUserPostQuery returns a new instance of UserPostQuery. +func NewUserPostQuery() *UserPostQuery { + return &UserPostQuery{ + BaseQuery: kallax.NewBaseQuery(Schema.UserPost.BaseSchema), } } // Select adds columns to select in the query. -func (q *StoreWithNewFixtureQuery) Select(columns ...kallax.SchemaField) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) Select(columns ...kallax.SchemaField) *UserPostQuery { if len(columns) == 0 { return q } @@ -10330,55 +11929,69 @@ func (q *StoreWithNewFixtureQuery) Select(columns ...kallax.SchemaField) *StoreW } // SelectNot excludes columns from being selected in the query. -func (q *StoreWithNewFixtureQuery) SelectNot(columns ...kallax.SchemaField) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) SelectNot(columns ...kallax.SchemaField) *UserPostQuery { q.BaseQuery.SelectNot(columns...) return q } // Copy returns a new identical copy of the query. Remember queries are mutable // so make a copy any time you need to reuse them. -func (q *StoreWithNewFixtureQuery) Copy() *StoreWithNewFixtureQuery { - return &StoreWithNewFixtureQuery{ +func (q *UserPostQuery) Copy() *UserPostQuery { + return &UserPostQuery{ BaseQuery: q.BaseQuery.Copy(), } } // Order adds order clauses to the query for the given columns. -func (q *StoreWithNewFixtureQuery) Order(cols ...kallax.ColumnOrder) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) Order(cols ...kallax.ColumnOrder) *UserPostQuery { q.BaseQuery.Order(cols...) return q } // BatchSize sets the number of items to fetch per batch when there are 1:N // relationships selected in the query. -func (q *StoreWithNewFixtureQuery) BatchSize(size uint64) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) BatchSize(size uint64) *UserPostQuery { q.BaseQuery.BatchSize(size) return q } // Limit sets the max number of items to retrieve. -func (q *StoreWithNewFixtureQuery) Limit(n uint64) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) Limit(n uint64) *UserPostQuery { q.BaseQuery.Limit(n) return q } // Offset sets the number of items to skip from the result set of items. -func (q *StoreWithNewFixtureQuery) Offset(n uint64) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) Offset(n uint64) *UserPostQuery { q.BaseQuery.Offset(n) return q } // Where adds a condition to the query. All conditions added are concatenated // using a logical AND. -func (q *StoreWithNewFixtureQuery) Where(cond kallax.Condition) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) Where(cond kallax.Condition) *UserPostQuery { q.BaseQuery.Where(cond) return q } +// WithUser retrieves the User record associated with each +// record. +func (q *UserPostQuery) WithUser() *UserPostQuery { + q.AddRelation(Schema.User.BaseSchema, "User", kallax.OneToOne, nil) + return q +} + +// WithPost retrieves the Post record associated with each +// record. +func (q *UserPostQuery) WithPost() *UserPostQuery { + q.AddRelation(Schema.Post.BaseSchema, "Post", kallax.OneToOne, nil) + return q +} + // FindByID adds a new filter to the query that will require that // the ID property is equal to one of the passed values; if no passed values, // it will do nothing. -func (q *StoreWithNewFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithNewFixtureQuery { +func (q *UserPostQuery) FindByID(v ...int64) *UserPostQuery { if len(v) == 0 { return q } @@ -10386,39 +11999,39 @@ func (q *StoreWithNewFixtureQuery) FindByID(v ...kallax.ULID) *StoreWithNewFixtu for i, val := range v { values[i] = val } - return q.Where(kallax.In(Schema.StoreWithNewFixture.ID, values...)) + return q.Where(kallax.In(Schema.UserPost.ID, values...)) } -// FindByFoo adds a new filter to the query that will require that -// the Foo property is equal to the passed value. -func (q *StoreWithNewFixtureQuery) FindByFoo(v string) *StoreWithNewFixtureQuery { - return q.Where(kallax.Eq(Schema.StoreWithNewFixture.Foo, v)) +// FindByUser adds a new filter to the query that will require that +// the foreign key of User is equal to the passed value. +func (q *UserPostQuery) FindByUser(v int64) *UserPostQuery { + return q.Where(kallax.Eq(Schema.UserPost.UserFK, v)) } -// FindByBar adds a new filter to the query that will require that -// the Bar property is equal to the passed value. -func (q *StoreWithNewFixtureQuery) FindByBar(v string) *StoreWithNewFixtureQuery { - return q.Where(kallax.Eq(Schema.StoreWithNewFixture.Bar, v)) +// FindByPost adds a new filter to the query that will require that +// the foreign key of Post is equal to the passed value. +func (q *UserPostQuery) FindByPost(v int64) *UserPostQuery { + return q.Where(kallax.Eq(Schema.UserPost.PostFK, v)) } -// StoreWithNewFixtureResultSet is the set of results returned by a query to the +// UserPostResultSet is the set of results returned by a query to the // database. -type StoreWithNewFixtureResultSet struct { +type UserPostResultSet struct { ResultSet kallax.ResultSet - last *StoreWithNewFixture + last *UserPost lastErr error } -// NewStoreWithNewFixtureResultSet creates a new result set for rows of the type -// StoreWithNewFixture. -func NewStoreWithNewFixtureResultSet(rs kallax.ResultSet) *StoreWithNewFixtureResultSet { - return &StoreWithNewFixtureResultSet{ResultSet: rs} +// NewUserPostResultSet creates a new result set for rows of the type +// UserPost. +func NewUserPostResultSet(rs kallax.ResultSet) *UserPostResultSet { + return &UserPostResultSet{ResultSet: rs} } // Next fetches the next item in the result set and returns true if there is // a next item. // The result set is closed automatically when there are no more items. -func (rs *StoreWithNewFixtureResultSet) Next() bool { +func (rs *UserPostResultSet) Next() bool { if !rs.ResultSet.Next() { rs.lastErr = rs.ResultSet.Close() rs.last = nil @@ -10426,14 +12039,14 @@ func (rs *StoreWithNewFixtureResultSet) Next() bool { } var record kallax.Record - record, rs.lastErr = rs.ResultSet.Get(Schema.StoreWithNewFixture.BaseSchema) + record, rs.lastErr = rs.ResultSet.Get(Schema.UserPost.BaseSchema) if rs.lastErr != nil { rs.last = nil } else { var ok bool - rs.last, ok = record.(*StoreWithNewFixture) + rs.last, ok = record.(*UserPost) if !ok { - rs.lastErr = fmt.Errorf("kallax: unable to convert record to *StoreWithNewFixture") + rs.lastErr = fmt.Errorf("kallax: unable to convert record to *UserPost") rs.last = nil } } @@ -10442,7 +12055,7 @@ func (rs *StoreWithNewFixtureResultSet) Next() bool { } // Get retrieves the last fetched item from the result set and the last error. -func (rs *StoreWithNewFixtureResultSet) Get() (*StoreWithNewFixture, error) { +func (rs *UserPostResultSet) Get() (*UserPost, error) { return rs.last, rs.lastErr } @@ -10450,7 +12063,7 @@ func (rs *StoreWithNewFixtureResultSet) Get() (*StoreWithNewFixture, error) { // the given callback. It is possible to stop the iteration by returning // `kallax.ErrStop` in the callback. // Result set is always closed at the end. -func (rs *StoreWithNewFixtureResultSet) ForEach(fn func(*StoreWithNewFixture) error) error { +func (rs *UserPostResultSet) ForEach(fn func(*UserPost) error) error { for rs.Next() { record, err := rs.Get() if err != nil { @@ -10469,8 +12082,8 @@ func (rs *StoreWithNewFixtureResultSet) ForEach(fn func(*StoreWithNewFixture) er } // All returns all records on the result set and closes the result set. -func (rs *StoreWithNewFixtureResultSet) All() ([]*StoreWithNewFixture, error) { - var result []*StoreWithNewFixture +func (rs *UserPostResultSet) All() ([]*UserPost, error) { + var result []*UserPost for rs.Next() { record, err := rs.Get() if err != nil { @@ -10482,7 +12095,7 @@ func (rs *StoreWithNewFixtureResultSet) All() ([]*StoreWithNewFixture, error) { } // One returns the first record on the result set and closes the result set. -func (rs *StoreWithNewFixtureResultSet) One() (*StoreWithNewFixture, error) { +func (rs *UserPostResultSet) One() (*UserPost, error) { if !rs.Next() { return nil, kallax.ErrNotFound } @@ -10500,12 +12113,12 @@ func (rs *StoreWithNewFixtureResultSet) One() (*StoreWithNewFixture, error) { } // Err returns the last error occurred. -func (rs *StoreWithNewFixtureResultSet) Err() error { +func (rs *UserPostResultSet) Err() error { return rs.lastErr } // Close closes the result set. -func (rs *StoreWithNewFixtureResultSet) Close() error { +func (rs *UserPostResultSet) Close() error { return rs.ResultSet.Close() } @@ -10522,6 +12135,7 @@ type schema struct { ParentNoPtr *schemaParentNoPtr Person *schemaPerson Pet *schemaPet + Post *schemaPost QueryFixture *schemaQueryFixture QueryRelationFixture *schemaQueryRelationFixture ResultSetFixture *schemaResultSetFixture @@ -10530,6 +12144,8 @@ type schema struct { StoreFixture *schemaStoreFixture StoreWithConstructFixture *schemaStoreWithConstructFixture StoreWithNewFixture *schemaStoreWithNewFixture + User *schemaUser + UserPost *schemaUserPost } type schemaCar struct { @@ -10620,6 +12236,12 @@ type schemaPet struct { OwnerFK kallax.SchemaField } +type schemaPost struct { + *kallax.BaseSchema + ID kallax.SchemaField + Text kallax.SchemaField +} + type schemaQueryFixture struct { *kallax.BaseSchema ID kallax.SchemaField @@ -10705,6 +12327,19 @@ type schemaStoreWithNewFixture struct { Bar kallax.SchemaField } +type schemaUser struct { + *kallax.BaseSchema + ID kallax.SchemaField + Name kallax.SchemaField +} + +type schemaUserPost struct { + *kallax.BaseSchema + ID kallax.SchemaField + UserFK kallax.SchemaField + PostFK kallax.SchemaField +} + type schemaJSONModelBar struct { *kallax.BaseSchemaField Qux *schemaJSONModelBarQux @@ -10751,7 +12386,9 @@ var Schema = &schema{ "__car", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Owner": kallax.NewForeignKey("owner_id", true), + "Owner": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", true), + }, }, func() kallax.Record { return new(Car) @@ -10925,7 +12562,9 @@ var Schema = &schema{ "__parent", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Children": kallax.NewForeignKey("parent_id", false), + "Children": []*kallax.ForeignKey{ + kallax.NewForeignKey("parent_id", false), + }, }, func() kallax.Record { return new(Parent) @@ -10943,7 +12582,9 @@ var Schema = &schema{ "__parentnoptr", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Children": kallax.NewForeignKey("parent_id", false), + "Children": []*kallax.ForeignKey{ + kallax.NewForeignKey("parent_id", false), + }, }, func() kallax.Record { return new(ParentNoPtr) @@ -10961,8 +12602,13 @@ var Schema = &schema{ "__person", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Pets": kallax.NewForeignKey("owner_id", false), - "Car": kallax.NewForeignKey("owner_id", false), + "Pets": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", false), + }, + + "Car": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", false), + }, }, func() kallax.Record { return new(Person) @@ -10980,7 +12626,9 @@ var Schema = &schema{ "__pet", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Owner": kallax.NewForeignKey("owner_id", true), + "Owner": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", true), + }, }, func() kallax.Record { return new(Pet) @@ -10996,15 +12644,43 @@ var Schema = &schema{ Kind: kallax.NewSchemaField("kind"), OwnerFK: kallax.NewSchemaField("owner_id"), }, + Post: &schemaPost{ + BaseSchema: kallax.NewBaseSchema( + "posts", + "__post", + kallax.NewSchemaField("id"), + kallax.ForeignKeys{ + "User": []*kallax.ForeignKey{ + kallax.NewForeignKey("post_id", true), kallax.NewForeignKey("user_id", true), + }, + }, + func() kallax.Record { + return new(Post) + }, + true, + kallax.NewSchemaField("id"), + kallax.NewSchemaField("text"), + ), + ID: kallax.NewSchemaField("id"), + Text: kallax.NewSchemaField("text"), + }, QueryFixture: &schemaQueryFixture{ BaseSchema: kallax.NewBaseSchema( "query", "__queryfixture", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Relation": kallax.NewForeignKey("owner_id", false), - "Inverse": kallax.NewForeignKey("inverse_id", true), - "NRelation": kallax.NewForeignKey("owner_id", false), + "Relation": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", false), + }, + + "Inverse": []*kallax.ForeignKey{ + kallax.NewForeignKey("inverse_id", true), + }, + + "NRelation": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", false), + }, }, func() kallax.Record { return new(QueryFixture) @@ -11078,7 +12754,9 @@ var Schema = &schema{ "__queryrelationfixture", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Owner": kallax.NewForeignKey("owner_id", true), + "Owner": []*kallax.ForeignKey{ + kallax.NewForeignKey("owner_id", true), + }, }, func() kallax.Record { return new(QueryRelationFixture) @@ -11114,8 +12792,13 @@ var Schema = &schema{ "__schemafixture", kallax.NewSchemaField("id"), kallax.ForeignKeys{ - "Nested": kallax.NewForeignKey("schema_fixture_id", false), - "Inverse": kallax.NewForeignKey("rel_id", true), + "Nested": []*kallax.ForeignKey{ + kallax.NewForeignKey("schema_fixture_id", false), + }, + + "Inverse": []*kallax.ForeignKey{ + kallax.NewForeignKey("rel_id", true), + }, }, func() kallax.Record { return new(SchemaFixture) @@ -11207,4 +12890,50 @@ var Schema = &schema{ Foo: kallax.NewSchemaField("foo"), Bar: kallax.NewSchemaField("bar"), }, + User: &schemaUser{ + BaseSchema: kallax.NewBaseSchema( + "users", + "__user", + kallax.NewSchemaField("id"), + kallax.ForeignKeys{ + "Posts": []*kallax.ForeignKey{ + kallax.NewForeignKey("user_id", true), kallax.NewForeignKey("post_id", true), + }, + }, + func() kallax.Record { + return new(User) + }, + true, + kallax.NewSchemaField("id"), + kallax.NewSchemaField("name"), + ), + ID: kallax.NewSchemaField("id"), + Name: kallax.NewSchemaField("name"), + }, + UserPost: &schemaUserPost{ + BaseSchema: kallax.NewBaseSchema( + "user_posts", + "__userpost", + kallax.NewSchemaField("id"), + kallax.ForeignKeys{ + "User": []*kallax.ForeignKey{ + kallax.NewForeignKey("user_id", true), + }, + + "Post": []*kallax.ForeignKey{ + kallax.NewForeignKey("post_id", true), + }, + }, + func() kallax.Record { + return new(UserPost) + }, + true, + kallax.NewSchemaField("id"), + kallax.NewSchemaField("user_id"), + kallax.NewSchemaField("post_id"), + ), + ID: kallax.NewSchemaField("id"), + UserFK: kallax.NewSchemaField("user_id"), + PostFK: kallax.NewSchemaField("post_id"), + }, } diff --git a/tests/store.go b/tests/store.go index 73f596e..db9a37b 100644 --- a/tests/store.go +++ b/tests/store.go @@ -9,8 +9,8 @@ import ( type AliasSliceString []string type StoreFixture struct { - kallax.Model `table:"store"` - ID kallax.ULID `pk:""` + kallax.Model `table:"store" pk:"id"` + ID kallax.ULID Foo string SliceProp []string AliasSliceProp AliasSliceString @@ -69,8 +69,8 @@ type Nullable struct { } type Parent struct { - kallax.Model `table:"parents"` - ID int64 `pk:"autoincr"` + kallax.Model `table:"parents" pk:"id,autoincr"` + ID int64 Name string Children []*Child } diff --git a/tests/through.go b/tests/through.go new file mode 100644 index 0000000..897167f --- /dev/null +++ b/tests/through.go @@ -0,0 +1,36 @@ +package tests + +import kallax "gopkg.in/src-d/go-kallax.v1" + +type User struct { + kallax.Model `table:"users" pk:"id,autoincr"` + ID int64 + Name string + Posts []*Post `through:"user_posts"` +} + +func newUser(name string) *User { + return &User{Name: name} +} + +type Post struct { + kallax.Model `table:"posts" pk:"id,autoincr"` + ID int64 + Text string + User *User `through:"user_posts"` +} + +func newPost(text string) *Post { + return &Post{Text: text} +} + +type UserPost struct { + kallax.Model `table:"user_posts" pk:"id,autoincr"` + ID int64 + User *User `fk:",inverse"` + Post *Post `fk:",inverse"` +} + +func newUserPost(user *User, post *Post) *UserPost { + return &UserPost{User: user, Post: post} +} diff --git a/tests/through_test.go b/tests/through_test.go new file mode 100644 index 0000000..f1c0eeb --- /dev/null +++ b/tests/through_test.go @@ -0,0 +1,130 @@ +package tests + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type ThroughSuite struct { + BaseTestSuite +} + +func (s *ThroughSuite) insertFixtures() ([]*User, []*Post) { + require := s.Require() + + var ( + userStore = NewUserStore(s.db) + postStore = NewPostStore(s.db) + userPostStore = NewUserPostStore(s.db) + ) + + users := []*User{ + NewUser("a"), + NewUser("b"), + } + + for _, u := range users { + require.NoError(userStore.Debug().Insert(u)) + } + + posts := []*Post{ + NewPost("a"), + NewPost("b"), + NewPost("c"), + NewPost("d"), + NewPost("e"), + NewPost("f"), + } + + for _, p := range posts { + require.NoError(postStore.Debug().Insert(p)) + } + + userPosts := []*UserPost{ + NewUserPost(users[0], posts[0]), + NewUserPost(users[0], posts[1]), + NewUserPost(users[0], posts[2]), + NewUserPost(users[1], posts[3]), + NewUserPost(users[1], posts[4]), + NewUserPost(users[1], posts[5]), + } + + for _, up := range userPosts { + require.NoError(userPostStore.Debug().Insert(up)) + } + + return users, posts +} + +func (s *ThroughSuite) TestFind() { + s.insertFixtures() + require := s.Require() + + q := NewUserQuery(). + WithPosts(nil, nil) + users, err := NewUserStore(s.db).Debug().FindAll(q) + require.NoError(err) + + require.Len(users, 2) + require.Equal("a", users[0].Name) + require.Len(users[0].Posts, 3) + for i, txt := range []string{"a", "b", "c"} { + require.Equal(txt, users[0].Posts[i].Text) + } + + require.Equal("b", users[1].Name) + require.Len(users[1].Posts, 3) + for i, txt := range []string{"d", "e", "f"} { + require.Equal(txt, users[1].Posts[i].Text) + } +} + +func (s *ThroughSuite) TestFind_Single() { + s.insertFixtures() + require := s.Require() + + q := NewPostQuery(). + WithUser(nil, nil) + posts, err := NewPostStore(s.db).Debug().FindAll(q) + require.NoError(err) + + require.Len(posts, 6) + for i, p := range []string{"a", "b", "c", "d", "e", "f"} { + require.Equal(p, posts[i].Text) + } + + userByPost := map[string]string{ + "a": "a", + "b": "a", + "c": "a", + "d": "b", + "e": "b", + "f": "b", + } + for _, p := range posts { + require.Equal(userByPost[p.Text], p.User.Name) + } +} + +func TestThrough(t *testing.T) { + schema := []string{ + `CREATE TABLE IF NOT EXISTS posts ( + id serial primary key, + text text not null + )`, + `CREATE TABLE IF NOT EXISTS users ( + id serial primary key, + name text not null + )`, + `CREATE TABLE IF NOT EXISTS user_posts ( + id serial primary key, + user_id bigint not null references users(id), + post_id bigint not null references posts(id) + )`, + } + suite.Run(t, &ThroughSuite{NewBaseSuite( + schema, + "user_posts", "posts", "users", + )}) +}