Giter Site home page Giter Site logo

volatiletech / sqlboiler Goto Github PK

View Code? Open in Web Editor NEW
6.4K 77.0 526.0 11.38 MB

Generate a Go ORM tailored to your database schema.

License: BSD 3-Clause "New" or "Revised" License

Go 66.57% Smarty 31.48% Shell 1.29% TSQL 0.66%
go orm golang sqlboiler database postgresql mysql sqlite3 postgres mssql

sqlboiler's People

Contributors

aarondl avatar autarch avatar c9s avatar ceshihao avatar chochihim avatar emmanuel099 avatar gemscng avatar glerchundi avatar jackdoe avatar lucaslsl avatar natsukagami avatar nemec784 avatar nickymateev avatar nullbio avatar oderwat avatar optiman avatar pankona avatar parnic avatar peterldowns avatar pilatuz avatar saulortega avatar severedsea avatar stefafafan avatar stephenafamo avatar tomscholz avatar tooolbox avatar tzachshabtay avatar yuzuy avatar zapo avatar zikaeroh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlboiler's Issues

Generating models with self-reference fails

Possibly related to #45, but I see a different behavior, so I wanted to file a separate ticket.

Here is the SQL this time:

CREATE TABLE industries (
    id integer NOT NULL,
    name text,
    parent_id integer
);

ALTER TABLE ONLY industries
    ADD CONSTRAINT industries_pkey PRIMARY KEY (id);


ALTER TABLE ONLY industries
    ADD CONSTRAINT industries_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES industries(id);

So, parent_id references another industry.

The models build works, but generates invalid code:

type Industry struct {
    ID       int         `boil:"id" json:"id" toml:"id" yaml:"id"`
    Name     null.String `boil:"name" json:"name,omitempty" toml:"name" yaml:"name,omitempty"`
    ParentID null.Int    `boil:"parent_id" json:"parent_id,omitempty" toml:"parent_id" yaml:"parent_id,omitempty"`

    R *industryR `boil:"-" json:"-" toml:"-" yaml:"-"`
    L industryL  `boil:"-" json:"-" toml:"-" yaml:"-"`
}

// industryR is where relationships are stored.
type industryR struct {
    Parent           *Industry
    Parent           *Industry
    Parent           *Industry
    Parent           *Industry
    ParentIndustries IndustrySlice
    ParentIndustries IndustrySlice
    ParentIndustries IndustrySlice
    ParentIndustries IndustrySlice
}
...

It generates 4 copies of Parent, and 4 copies of ParentIndustries. There should only be a single instance of each. It also appears that the code for Adding/Replacing on the relationship does not compile.

v1.1 StatementMods

For 1.1, to expand each query type functionality (update, delete, upsert etc) we can consider having the function signatures take a *[]StatementMod that allow for complex modification of the statements. Example:

type UpsertMod func(q *boil.Thing)
type UpsertMods *[]UpsertMod

func Conflict(cols ...string) UpsertMod
func Update(cols ...string) UpsertMod
func Where(clause string, args ...interface{}) UpsertMod

func Upsert(update bool, mods UpsertMods, whitelist ...string)

This allows for complex modifications of the query statements without requiring a bucketload of additional function params.

Generating models fails with many-to-many on same table

We have a table which can reference back to itself in a many to many relationship. When generating the schema, we get the an error.

Here are the (abbreviated) tables in question, pulled from a database dump:

CREATE TABLE industries (
    id integer NOT NULL,
    name text
);

ALTER TABLE ONLY industries
    ADD CONSTRAINT industries_pkey PRIMARY KEY (id);

CREATE TABLE industries_industries (
    industry_id integer NOT NULL,
    mapped_industry_id integer NOT NULL,
    relation text NOT NULL
);

ALTER TABLE ONLY industries_industries 
    ADD CONSTRAINT industries_industries_pkey PRIMARY KEY (industry_id, mapped_industry_id);

ALTER TABLE ONLY industries_industries
    ADD CONSTRAINT industries_industries_industry_id_fkey FOREIGN KEY (industry_id) REFERENCES industries(id);

ALTER TABLE ONLY industries_industries
    ADD CONSTRAINT industries_industries_mapped_industry_id_fkey FOREIGN KEY (mapped_industry_id) REFERENCES industries(id);

Upon running sqlboiler, I get the following output:

Error: 3:22: expected ')', found '(' (and 10 more errors)
failed to format template

  0 // G retrieves all the industry's .
  1 func (i *Industry) G(mods ...qm.QueryMod) Query {
  2     return i.(boil.GetDB(), mods...)
>>> }
  4
  5 //  retrieves all the industry's  with an executor.
  6 func (i *Industry) (exec boil.Executor, mods ...qm.QueryMod) Query {
  7     queryMods := []qm.QueryMod{
  8         qm.Select("\"a\".*"),

To generate this output, I ran the sql script above in its own schema, and then used:

sqlboiler -s test_schema postgres

v1.1 paginate method

Do we want a paginate method like in ActiveRecord?

@battles = Battle
  .unscoped
  .where('challengee_id = ? or challenger_id = ?', v.id, v.id)
  .order('id desc')
  .paginate(page: params[:page], per_page: 100)

todo

Try to change prerun and postrun to PreRunE and PostRunE and bubble up errors to main func opposed to errorQuit().

Remove all commented out code that isnt be used, and use linter tool to check for any unused functions in the project for removal.

support hstore and array columns?

I really like the sqlboiler so far. It looks like a great project!

I searched the code base and didn't see any reference to it on master or dev branches.

I have one table which has both hstore and text[] columns. How much work would be involved in supporting these?

(I also have jsonb but I see you support that on the dev branch now).

SetX fails silently for nullable foreign keys

SetX doesn't work when you can have a nullable foreign key. This is an easy fix and results from manually assigning the null.Int.Int value but not setting null.Int.Valid to true.

For example, in this scenario, every user might have a plan, but the foreign key plan_id can be null if they don't yet have a plan assigned. So, the generated code represents plan_id as a null.Int

CREATE TYPE plan_name AS ENUM ('trial', 'small', 'medium', 'large', 'cancel', 'unpaid');

CREATE TABLE plans (
    id serial NOT NULL,
    created_at timestamp,
    updated_at timestamp,
    start timestamp NOT NULL,
    expire timestamp,
    name plan_name NOT NULL,
    user_name text NOT NULL
);

ALTER TABLE plans ADD CONSTRAINT plan_pkey PRIMARY KEY (id);

CREATE TABLE users (
    id serial NOT NULL,
    name text UNIQUE NOT NULL,
    password text NOT NULL,
    email text UNIQUE NOT NULL,
    first_name text,
    last_name text,
    plan_id integer,
    created_at timestamp,
    updated_at timestamp
);

ALTER TABLE users ADD CONSTRAINT user_pkey PRIMARY KEY (id);
ALTER TABLE users ADD CONSTRAINT plans_fkey FOREIGN KEY (plan_id) REFERENCES plans(id);

In the generated code, you have a user.SetPlan() method that is implemented like this:

func (u *User) SetPlan(exec boil.Executor, insert bool, related *Plan) error {
    var err error
    if insert {
        if err = related.Insert(exec); err != nil {
            return errors.Wrap(err, "failed to insert into foreign table")
        }
    }

    oldVal := u.PlanID
    u.PlanID.Int = related.ID
       // u.PlanID.Valid = true  <========== needs this line
    if err = u.Update(exec, "plan_id"); err != nil {
        u.PlanID = oldVal
        return errors.Wrap(err, "failed to update local table")
    }

The generated code reaches into the null.Int struct to set the Int value directly, but does not set Valid to true. This causes the subsequent update to silently fail with no error. Should probably be using null.IntFrom(related.ID) rather than directly manipulating the struct values.

Why is uuid/char translated as string?

If I use a uuid (as a primary key) in a postgres table, sqlboiler generates a string field in the model. Is there a reasoning behind this?

I'm not too bothered by this, but I think it should either be [16]byte or a type UUID [16]byte. It would make using https://github.com/satori/go.uuid easier, and it would consume less memory as it would be 16 bytes instead of 36 bytes (characters) plus the string header.

CC @teasherm

Slices missing InsertAll()

Generated slices are missing InsertAll(); it would be nice to be able to do multiple row inserts:

INSERT INTO x(col1, col2) VALUES
("a1", "a2"),
("b1", "b2"),
...

Not sure how that will work for the maximum query size settings for each database. Should probably have a UpsertAll() as well?

select cases

/*
fix "count(thing)" to count(thing)

select colName
select count(*)
select count(colname)
select count(colname), colName
select count("colname") as "blah"
select count(colname) as blah, colName
select (select * from blah)
select (select * from blah) as blah
select "a"."id", "b"."id"
from "x" as "a"
inner join "y" "b" on "a"."id" = "b"."id"

select v.id, u.name
from videos as v
inner join users u on u.id=v.user_id
where v.id=15

Videos(
Select("v.title, u.name"),
InnerJoin("users u on u.id=v.user_id"),
Where("v.id=?", 15)
).Bind(&thing)

*/

After Eager, empty lists result in null "R" field

When doing an eager, the R field is left as null if no eager objects are loaded. I think a non-null R, with an empty array in the loaded relationship would be more appropriate.

To reproduce, here is the schema I used:

CREATE SCHEMA test_schema;

CREATE TABLE test_schema.parents (
    id BIGSERIAL PRIMARY KEY,
    name TEXT
);

CREATE TABLE test_schema.children (
    id BIGSERIAL PRIMARY KEY,
    parent_id BIGINT REFERENCES test_schema.parents(id),
    name TEXT
);

INSERT INTO test_schema.parents (name) values ('P1');
INSERT INTO test_schema.parents (name) values ('P2');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C21');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C22');

So, P1 has no children, and P2 has two children. Create the models for this schema, then run the following:

package main

import (
    "database/sql"
    "fmt"

    "github.com/jseriff/sqltest/models"
    _ "github.com/lib/pq"
    "github.com/vattle/sqlboiler/queries/qm"
)

func main() {
    db, _ := sql.Open("postgres", "postgres://evsr_development:evsr_development@localhost:5432/evsr_development?options=+-c+search_path%%3Dtest_schema")

    parents, _ := models.Parents(db,
        qm.Load("Children"),
    ).All()

    for i := range parents {
        fmt.Printf("Parent %d.R: %v\n", i, parents[i].R)
    }
}

The output is:

Parent 0.R: <nil>
Parent 1.R: &{[0xc4200118c0 0xc420011900]}

You can see in the output that Parent 0.R is nil. This forces me to check R for nil before looking at the relationship, adding quite a bit of verbosity.

RowsAffected in the API

We're considering doing this but it's a breaking change.

So far we can't come up with any real use case of when you would want to use this, but we see it in other public APIs. If you require this feature please Thumbs up this issue instead of making a new one.

So people get a better idea of what I mean I'll edit here:

Currently queries like Update/Delete etc do not return rows affected:

jet, err := models.Jets(tx).One()
jet.Fast = true
err := jet.Update(tx)

jets, err := models.Jets(tx).All()
err := jets.UpdateAll(tx, models.M{"fast": true})

After this change they would:

jet, err := models.Jets(tx).One()
jet.Fast = true
affected, err := jet.Update(tx)

jets, err := models.Jets(tx).All()
affected, err := jets.UpdateAll(tx, models.M{"fast": true})

This is a breaking change and will be driven by user need. Please let us know.

v1.1 better logging options

A cleaner debug logging option for all generated statements. A Debug query mod to debug single statements would be useful too.

Feature Request: Refactor main.go into packages for easy downstream integration

End Goal:

I want to be able to easily embed sqlboiler into my own single-binary Cobra project

Justification:

  • I enjoy single-binary projects
  • Easier to ensure the entire team is using the same version of sqlboiler without needing distribute a binary separately or have them build from a specific commit

Steps involved:

  • break up the main package into discrete sub-packages as needed (e.g. cmd)

I'd be happy to draft a PR for review, but would like to see what you think about the idea first.
Let me know if I can clarify anything.

Multiple multi-level eager loads ignore all but last load command

In this situation, I have a table, with a child table, which in turn has multiple children. I want to eager load all of these. The test case:

CREATE SCHEMA test_schema;

CREATE TABLE test_schema.parents (
    id BIGSERIAL PRIMARY KEY,
    name TEXT
);

CREATE TABLE test_schema.children (
    id BIGSERIAL PRIMARY KEY,
    parent_id BIGINT REFERENCES test_schema.parents(id),
    name TEXT
);

CREATE TABLE test_schema.third (
    id BIGSERIAL PRIMARY KEY,
    children_id BIGINT REFERENCES test_schema.children(id),
    name TEXT
);

CREATE TABLE test_schema.another (
    id BIGSERIAL PRIMARY KEY,
    children_id BIGINT REFERENCES test_schema.children(id),
    name TEXT
);

INSERT INTO test_schema.parents (name) values ('P1');
INSERT INTO test_schema.parents (name) values ('P2');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P1'), 'C11');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C21');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C22');
INSERT INTO test_schema.third (children_id, name) values ((select id from test_schema.children where name = 'C21'), 'T211');
INSERT INTO test_schema.third (children_id, name) values ((select id from test_schema.children where name = 'C21'), 'T212');
INSERT INTO test_schema.another (children_id, name) values ((select id from test_schema.children where name = 'C21'), 'A211');

Generate models, and then run:

package main

import (
    "database/sql"
    "fmt"

    "github.com/jseriff/sqltest/models"
    _ "github.com/lib/pq"
    "github.com/vattle/sqlboiler/boil"
    "github.com/vattle/sqlboiler/queries/qm"
)

func main() {
    db, _ := sql.Open("postgres", "postgres://...?options=+-c+search_path%%3Dtest_schema")

    boil.DebugMode = true

    parents, _ := models.Parents(db,
        qm.Load("Children.Thirds"),
        qm.Load("Children.Anothers"),
    ).All()
}

The debug output generated here is:

SELECT * FROM "test_schema"."parents";
[]
select * from "test_schema"."children" where "parent_id" in ($1,$2)
[1 2]
select * from "test_schema"."another" where "children_id" in ($1,$2,$3)
[1 2 3]

Notice, that "another" is queried, but "thirds" is not. If you switch the order of the qm.Load calls, you will find the opposite is true.

Add configuration opton to white-list tables

It would be nice to have "include" option in configuration that would allow us to specify just the tables that we want to be processed by the generator, as opposite to "exclude".

Insert test cases and expected results

non-whitelist case: checks for all columns without default values, and includes that in the insert. it additionally appends any default values that have non-zero default values.
whitelist: it will only insert columns specified, default values is the same rule as non-whitelist.
returning: what is available in default values, minus what is being inserted in default values.

all template funcs

type VideoSlice []*Video

type videoQuery struct {
*boil.Query
}

All:

func Videos(querymods) videoQuery
func VideosX(executor, querymods) videoQuery

Delete:

func (v *Video) Delete(...querymods) error
func (v videoQuery) DeleteAll() error

Find:

func VideoFind(id int64, selectList ...string) (*Video, error)
func VideoFindX(executor, id int64, selectList ...string) (*Video, error)

Insert:

func (v *Video) Insert(querymods) error
func (v *Video) InsertX(executor, querymods) error

Update:

func (v *Video) Update(whitelist ... string) error
func (v *Video) UpdateX(executor, whitelist ... string) error
func (v videoQuery) UpdateAll(boil.M) error

Bind:
func (q *Query) Bind(interface{}) error

Do functions:
func (videoQuery) One() (*Video, error)
func (videoQuery) All() (VideoSlice, error)

todo for binds


Bind: 
- It needs to look for a fully qualified table name, so if you get an as with a dot, split on the dot, look for the table name. If you can't find a struct with that table name then you just bind to the column name in the current struct.
- If there is no dot, you first try to bind it to the from table struct if it exists in the object, if that doesn't exist then you just bind the column name to columns inside the object.

Eager loading:
- Eager loading is defined through the Load("tablename", ...querymods) query mod. Once that's there then bind will know to do additional queries for each load invocation (it splits up the query into multiple to get all column data). The Relationship struct on the model (exported) will be filled with the results of each one of these loads. 
- For all the relationship stuffs it needs to short circuit on cached copies in the relationship struct. For example, if you see a user that's already loaded in the relationship struct, you don't do the query.
- Need a reload method for reloading cache data. Example:

v.Reload()
v.Relationships.Videos.Reload()```

Feature request: Pass db object as a configuration

Hi,

The db object is passed repetitively, for example:

err = p1.Insert(db)
pilot, err := models.PilotFind(db, 1)
pilot, err := models.Pilots(db, qm.Where("name=?", "Tim")).One()

Why we don't just pass the db object to the models package as a configuration?

postgres "char" is translated as string

Similar to #58, if I use a "char" column on postgres, this gets mapped to string in the generated model. Like the other issue, this isn't a dealbreaker but it would be much better to have it as byte. rune could also be used, but it's a little silly to use a 4-byte type when "char" in postgres is 1-byte.

Generate types for views?

Will you add a feature to generate types for views in the future?
Currently it is not possible, because Views don't have primary keys.

Multi level eager failing

When attempting a multi-level eager load, I am seeing a reflection error. Here is a reproduction case:

I constructed a simple 3 level hierarchy to show this error:

CREATE SCHEMA test_schema;

CREATE TABLE test_schema.parents (
    id BIGSERIAL PRIMARY KEY,
    name TEXT
);

CREATE TABLE test_schema.children (
    id BIGSERIAL PRIMARY KEY,
    parent_id BIGINT REFERENCES test_schema.parents(id),
    name TEXT
);

CREATE TABLE test_schema.third (
    id BIGSERIAL PRIMARY KEY,
    children_id BIGINT REFERENCES test_schema.children(id),
    name TEXT
);

INSERT INTO test_schema.parents (name) values ('P1');
INSERT INTO test_schema.parents (name) values ('P2');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P1'), 'C11');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C21');
INSERT INTO test_schema.children (parent_id, name) values ((select id from test_schema.parents where name = 'P2'), 'C22');
INSERT INTO test_schema.third (children_id, name) values ((select id from test_schema.children where name = 'C21'), 'T211');
INSERT INTO test_schema.third (children_id, name) values ((select id from test_schema.children where name = 'C21'), 'T212');

Generated the models on this schema, and then ran a the following code:

package main

import (
    "database/sql"

    "github.com/jseriff/sqltest/models"
    _ "github.com/lib/pq"
    "github.com/vattle/sqlboiler/queries/qm"
)

func main() {
    db, _ := sql.Open("postgres", "postgres://evsr_development:evsr_development@localhost:5432/evsr_development?options=+-c+search_path%%3Dtest_schema")

    _, _ = models.Parents(db,
        qm.Load("Children.Thirds"),
    ).All()
}

I receive the following error:

panic: reflect.Value.Addr of unaddressable value

goroutine 1 [running]:
panic(0x2acb60, 0xc4201ba2a0)
    /usr/local/Cellar/go/1.7/libexec/src/runtime/panic.go:500 +0x1a1
reflect.Value.Addr(0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.7/libexec/src/reflect/value.go:239 +0xbc
github.com/vattle/sqlboiler/queries.loadRelationshipState.loadRelationshipsRecurse(0x4546c0, 0xc420016630, 0xc4200db260, 0xc42011e920, 0x2, 0x2, 0x1, 0x2e2bc0, 0xc4200db200, 0x199, ...)
    /Users/jseriff/go/src/github.com/vattle/sqlboiler/queries/eager_load.go:145 +0x337
github.com/vattle/sqlboiler/queries.loadRelationshipState.loadRelationships(0x4546c0, 0xc420016630, 0xc4200db260, 0xc42011e920, 0x2, 0x2, 0x1, 0x2eaf60, 0xc420014d20, 0x2, ...)
    /Users/jseriff/go/src/github.com/vattle/sqlboiler/queries/eager_load.go:126 +0x2c3
github.com/vattle/sqlboiler/queries.(*Query).Bind(0xc4200a9b80, 0x2eaf60, 0xc420014d20, 0x0, 0x0)
    /Users/jseriff/go/src/github.com/vattle/sqlboiler/queries/reflect.go:123 +0x2d6
github.com/jseriff/sqltest/models.parentQuery.All(0xc4200a9b80, 0xc420016630, 0xc42000d660, 0x2, 0x2, 0xc4200a9b80)
    /Users/jseriff/go/src/github.com/jseriff/sqltest/models/parents.go:254 +0x71
main.main()
    /Users/jseriff/go/src/github.com/jseriff/sqltest/main.go:16 +0xea
exit status 2

I spent a few minutes looking into loadRelationships - it looks like when it recurses, the loadRelationshipsRecurse method is expecting to receive the "Children"'s R, but instead receives the "Parent"s R, which does not have a Thirds member.

Failed to create join table

I use Mysql workbench to design tables, the database works fine, but sqlboiler can't recognize the join table. Below is the sql scripts, store_coupons is the join table.

-- -----------------------------------------------------
-- Table `htk_dev`.`coupons`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `htk_dev`.`coupons` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `category` INT(11) NOT NULL DEFAULT '0',
  `user_id` INT(11) NOT NULL,
  `created_at` DATETIME NOT NULL,
  `count` INT(11) NOT NULL,
  `remain_count` INT(11) NOT NULL,
  `content` TEXT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `index_coupons_on_user_id` (`user_id` ASC),
  CONSTRAINT `fk_rails_69b54b3afe`
    FOREIGN KEY (`user_id`)
    REFERENCES `htk_dev`.`users` (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `htk_dev`.`stores`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `htk_dev`.`stores` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `user_id` INT(11) NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  `license_url` VARCHAR(255) NOT NULL,
  `verify` INT(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  INDEX `index_stores_on_user_id` (`user_id` ASC),
  CONSTRAINT `fk_rails_b526db2ffb`
    FOREIGN KEY (`user_id`)
    REFERENCES `htk_dev`.`users` (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 8
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `htk_dev`.`store_coupons`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `htk_dev`.`store_coupons` (
  `stores_id` INT(11) NOT NULL,
  `coupons_id` INT(11) NOT NULL,
  PRIMARY KEY (`stores_id`, `coupons_id`),
  INDEX `fk_stores_has_coupons_coupons1_idx` (`coupons_id` ASC),
  INDEX `fk_stores_has_coupons_stores1_idx` (`stores_id` ASC),
  CONSTRAINT `fk_stores_has_coupons_coupons1`
    FOREIGN KEY (`coupons_id`)
    REFERENCES `htk_dev`.`coupons` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_stores_has_coupons_stores1`
    FOREIGN KEY (`stores_id`)
    REFERENCES `htk_dev`.`stores` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

Using ENUM type

Hi,

At first thanks for such great tool! The workflow combined with both goose and sqlboiler works very well and conveys the impression of doing things in elegant manner :)

I have encountered a problem when ENUM type is used, for example:

CREATE TYPE workday AS ENUM('monday', 'tuesday', 'wednesday', 'thursday', 'friday');
CREATE TABLE event (
  id     SERIAL,
  name   VARCHAR(255),
  day    workday NOT NULL
);

ALTER TABLE event ADD CONSTRAINT event_key PRIMARY KEY(id);

Executing sqlboiler output warning:
Warning: Incompatible data type detected: workday

Thus the models directory is created, running tests
go test models/
results in massive fail log:

--- FAIL: TestDelete (0.00s)
    --- FAIL: TestDelete/Events (0.01s)
    	event_test.go:35: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:39: models: unable to delete from event: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:44: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestQueryDeleteAll (0.00s)
    --- FAIL: TestQueryDeleteAll/Events (0.00s)
    	event_test.go:65: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:69: models: unable to delete all from event: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:74: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestSliceDeleteAll (0.00s)
    --- FAIL: TestSliceDeleteAll/Events (0.00s)
    	event_test.go:95: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:101: models: unable to delete all from event slice: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:106: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestExists (0.00s)
    --- FAIL: TestExists/Events (0.00s)
    	event_test.go:126: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:131: Unable to check if Event exists: models: unable to check if event exists: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:134: Expected EventExistsG to return true, but got false.
--- FAIL: TestFind (0.00s)
    --- FAIL: TestFind/Events (0.00s)
    	event_test.go:150: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:155: models: unable to select from event: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:159: want a record, got nil
--- FAIL: TestBind (0.00s)
    --- FAIL: TestBind/Events (0.00s)
    	event_test.go:175: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:179: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestOne (0.00s)
    --- FAIL: TestOne/Events (0.00s)
    	event_test.go:196: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:200: models: failed to execute a one query for event: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestAll (0.00s)
    --- FAIL: TestAll/Events (0.00s)
    	event_test.go:223: models: unable to insert into event: pq: invalid input value for enum workday: "a"
    	event_test.go:226: models: unable to insert into event: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:231: models: failed to assign all query results to Event slice: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:235: want 2 records, got: 0
--- FAIL: TestCount (0.00s)
    --- FAIL: TestCount/Events (0.00s)
    	event_test.go:256: models: unable to insert into event: pq: invalid input value for enum workday: "a"
    	event_test.go:259: models: unable to insert into event: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:264: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:268: want 2 records, got: 0
--- FAIL: TestInsert (0.00s)
    --- FAIL: TestInsert/Events (0.00s)
    	event_test.go:423: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:428: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:432: want one record, got: 0
    --- FAIL: TestInsert/Events#01 (0.01s)
    	event_test.go:449: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:454: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:458: want one record, got: 0
--- FAIL: TestReload (0.00s)
    --- FAIL: TestReload/Events (0.00s)
    	event_test.go:475: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:479: models: unable to select from event: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestReloadAll (0.00s)
    --- FAIL: TestReloadAll/Events (0.00s)
    	event_test.go:496: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:502: models: unable to reload all in EventSlice: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestSelect (0.00s)
    --- FAIL: TestSelect/Events (0.00s)
    	event_test.go:518: models: unable to insert into event: pq: invalid input value for enum workday: "b"
    	event_test.go:523: models: failed to assign all query results to Event slice: bind failed to execute query: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:527: want one record, got: 0
--- FAIL: TestUpdate (0.00s)
    --- FAIL: TestUpdate/Events (0.00s)
    	event_test.go:553: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:558: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:562: want one record, got: 0
    	event_test.go:570: models: unable to update event row: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestSliceUpdateAll (0.00s)
    --- FAIL: TestSliceUpdateAll/Events (0.00s)
    	event_test.go:591: models: unable to insert into event: pq: invalid input value for enum workday: ""
    	event_test.go:596: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:600: want one record, got: 0
    	event_test.go:626: models: unable to update all in event slice: pq: current transaction is aborted, commands ignored until end of transaction block
--- FAIL: TestUpsert (0.00s)
    --- FAIL: TestUpsert/Events (0.00s)
    	event_test.go:647: Unable to upsert Event: models: unable to upsert for event: pq: syntax error at or near "ON"
    	event_test.go:652: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:655: want one record, got: 0
    	event_test.go:664: Unable to upsert Event: models: unable to upsert for event: pq: syntax error at or near "ON"
    	event_test.go:669: models: failed to count event rows: pq: current transaction is aborted, commands ignored until end of transaction block
    	event_test.go:672: want one record, got: 0

models/event.go

type Event struct {
  ID   int         `boil:"id" json:"id" toml:"id" yaml:"id"`
  Name null.String `boil:"name" json:"name,omitempty" toml:"name" yaml:"name,omitempty"`
  Day  string      `boil:"day" json:"day,omitempty" toml:"day" yaml:"day,omitempty"`

  R *eventR `boil:"-" json:"-" toml:"-" yaml:"-"`
  L eventL  `boil:"-" json:"-" toml:"-" yaml:"-"`
}

If combine the warning, test output and generated code the answer is simple: enum type is not handled properly and it is treated as string type.

Are there any workarounds (other than editing generated files) for such case? (or maybe I have done something wrong?).

Thanks for your help!
Have a nice day

EDIT:
Of course the easiest workaround:

create table workday (
name VARCHAR(20) PRIMARY KEY
);

How to add custom tag for different properties

For example, I have a user model

    type User struct {
    ID             int       `boil:"id" json:"id" toml:"id" yaml:"id"`
    Name           string    `boil:"name" json:"name" toml:"name" yaml:"name"`
    PasswordDigest string    `boil:"password_digest" json:"password_digest" toml:"password_digest" yaml:"password_digest"`
    Phone          string    `boil:"phone" json:"phone" toml:"phone" yaml:"phone"`
    CreatedAt      time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
    UpdatedAt      time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`

    R *userR `boil:"-" json:"-" toml:"-" yaml:"-"`
    L userL  `boil:"-" json:"-" toml:"-" yaml:"-"`
}

I want to change Name's tag to

    Name string `boil:"name" json:"name" toml:"name" yaml:"name" valid:"Required;MinSize(5);MaxSize(26)"`  

so I can run my valid function to check if the parameter in http request is valid
and I also want to change passwordDiagest's json tag to json:"-", so when I send user struct over http response, the password will not be included.

How to specific tags for different tables and different properties?

Password is asked when running models tests

Hi there!

First of all, I want to start by thanking you guys for this great project.
Now, on to the helping part:

In my project, we're using gb as the primary build tool (although we experienced the same issues with the go tool)
Sqlboiler version is tag 2.0.1

$ gb test ./models
Password: *types password*
Password: *types password*
Password: Password: *types password*
(hangs forever)

This is my sqlboiler.toml:

[postgres]
dbname="mydbname"
host="localhost"
port=5432
user="postgres"
pass="postgres"

Any idea what could be happening?
Thanks!

problem when table has FK to itself

i've got the following table (postgres):

create table if not exists posts (
       id serial primary key not null,
       uuid uuid not null default (uuid_generate_v4()) unique,
       created_at_utc timestamp without time zone not null default (now() at time zone 'utc'),
       approved boolean not null default false,
       flagged boolean not null default false,
       -- problem here:
       parent_uuid uuid references posts (uuid),
       --
       updated_at_utc timestamp without time zone default null
);

but the generated code gives the following errors when building:

models/posts.go:330: cannot call non-function p.ParentUUID (type null.String)
models/posts.go:334: type Post has both field and method named ParentUUID

am i doing something wrong? is there a way to name things that won't cause this problem? Thanks in advance! Other than this minor issue, I'm really enjoying using this!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.