From 830678c914cb9099d666988b0af4ceb15149953f Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 9 Feb 2021 16:49:48 +0100 Subject: [PATCH] admindb: add migrations based on rubenv/sql-migrate This removes the nasty need for creating the database manually. Migrations are kept in an embedded filesystem, just like the templates and assets for the web frontend. The same -tags dev trick applies for them. --- .gitignore | 9 + README.md | 26 +- admindb/sqlite/generate_models.sh | 8 +- admindb/sqlite/migrations.go | 9 + .../migrations/create-auth-fallback.sql | 9 + admindb/sqlite/migrations_dev.go | 23 + admindb/sqlite/migrations_generate.go | 25 + admindb/sqlite/migrations_vfsdata.go | 186 ++++ admindb/sqlite/models/aliases.go | 819 ------------------ admindb/sqlite/models/aliases_test.go | 684 --------------- admindb/sqlite/models/auth_fallback.go | 46 + admindb/sqlite/models/boil_suites_test.go | 18 - admindb/sqlite/models/boil_table_names.go | 2 - admindb/sqlite/new.go | 30 +- admindb/sqlite/new_test.go | 30 + admindb/sqlite/schema-v1.sql | 7 - admindb/sqlite/sqlboiler.toml | 5 +- cmd/server/main.go | 3 +- go.mod | 2 + go.sum | 52 ++ 20 files changed, 441 insertions(+), 1552 deletions(-) create mode 100644 .gitignore create mode 100644 admindb/sqlite/migrations.go create mode 100644 admindb/sqlite/migrations/create-auth-fallback.sql create mode 100644 admindb/sqlite/migrations_dev.go create mode 100644 admindb/sqlite/migrations_generate.go create mode 100644 admindb/sqlite/migrations_vfsdata.go delete mode 100644 admindb/sqlite/models/aliases.go delete mode 100644 admindb/sqlite/models/aliases_test.go create mode 100644 admindb/sqlite/new_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e175e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# the binaries +cmd/server/server +cmd/insert-user/insert-user + +# testrun contains repos that were use for tests +test/go/testrun +test/nodejs/testrun +web/handlers/testrun +admindb/sqlite/testrun \ No newline at end of file diff --git a/README.md b/README.md index d52a94b..42a5535 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,10 @@ Usage of ./server: print version number and build date ``` -If you are working on the html templates or assets for them, build the server with `go build -tags dev`. +If you are working on the sqlite migrations, html templates or website assets, build the server with `go build -tags dev`. This way it won't use the assets that are embedded in the binary but read them directly from the local filesystem. -Once you are done with your changes run `go generate` in package web to update them. +Once you are done with your changes run `go generate` in the changed packages to update them. ## Tooling @@ -53,31 +53,33 @@ Once you are done with your changes run `go generate` in package web to update t [counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) enables generating mocks for defined interfaces. To update them run `go generate` in package admindb. -TODO: automate setup of tool +TODO: setup tool as dependency (no manual install) + + +### Database schema + +This project uses [sql-migrate](https://github.com/rubenv/sql-migrate) to upgrate the sqlite database when necessary. + +Just create a new file in `admindb/sqlite/migrations` with your changes but be reminded: Similar to the web assets, you need to use `go test -tags dev` to test them. Afterwards run `go generate` to embedd them in the code and thus the resulting server binary. ### No ORM We use [sqlboiler](github.com/volatiletech/sqlboiler) to generate type-safe Go code code directly from SQL statements and table definitions. This approach suits the programming language much more then classical ORM approaches, which usually rely havily on reflection for (un)packing structs. To generate them run the following commands. This will populate `admindb/sqlite/models`: - + (TODO: automate this with `go generate`) ```bash +# also included as generate_models.sh cd admindb/sqlite -rm generate.db -sqlite3 generate.db < schema-v1.sql +go test sqlboiler sqlite3 --wipe ``` -The generated package `admindb/sqlite/models` is then used to implemente the custom logic of the different services in `admindb/sqlite` - -TODO: automate this with `go generate` - -TODO: we still need to incorporate automatic migrations. Until then use this workaround before starting the server: `mkdir $HOME/.ssb-go-room; sqlite3 $HOME/.ssb-go-room/roomdb < $src/admindb/sqlite/schema-v1.sql`. +The generated package `admindb/sqlite/models` is then used to implemente the custom logic of the different services in `admindb/sqlite`. Aside: I would have used `sqlc` since it's a bit more minimal and uses hand written SQL queries instead of generic query builders but it [currently doesn't support sqlite](https://github.com/kyleconroy/sqlc/issues/161). - ### Development user creation `cmd/insert-user` contains code to create a fallback user. Build it and point it too your database with a username, like so: diff --git a/admindb/sqlite/generate_models.sh b/admindb/sqlite/generate_models.sh index d4bf82c..0b8d07b 100644 --- a/admindb/sqlite/generate_models.sh +++ b/admindb/sqlite/generate_models.sh @@ -1,7 +1,7 @@ #!/bin/sh -dbName=generated.db +set -e -test -f $dbName && rm $dbName -sqlite3 $dbName < schema-v1.sql -sqlboiler sqlite3 --wipe \ No newline at end of file +go test +sqlboiler sqlite3 --wipe +echo "all done!" \ No newline at end of file diff --git a/admindb/sqlite/migrations.go b/admindb/sqlite/migrations.go new file mode 100644 index 0000000..a10c61c --- /dev/null +++ b/admindb/sqlite/migrations.go @@ -0,0 +1,9 @@ +package sqlite + +import migrate "github.com/rubenv/sql-migrate" + +//go:generate go run -tags=dev migrations_generate.go + +var migrationSource = &migrate.HttpFileSystemMigrationSource{ + FileSystem: Migrations, +} diff --git a/admindb/sqlite/migrations/create-auth-fallback.sql b/admindb/sqlite/migrations/create-auth-fallback.sql new file mode 100644 index 0000000..7de84b8 --- /dev/null +++ b/admindb/sqlite/migrations/create-auth-fallback.sql @@ -0,0 +1,9 @@ +-- +migrate Up +CREATE TABLE auth_fallback ( + id int PRIMARY KEY NOT NULL, + name text NOT NULL UNIQUE, + password_hash blob not null +); + +-- +migrate Down +DROP TABLE auth_fallback; \ No newline at end of file diff --git a/admindb/sqlite/migrations_dev.go b/admindb/sqlite/migrations_dev.go new file mode 100644 index 0000000..c9b8d39 --- /dev/null +++ b/admindb/sqlite/migrations_dev.go @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +// +build dev + +/* +This is the development version of the migrations folder, where they are read directly from the local filesystem. + +to use this pass '-tags dev' to your go build or test commands. +*/ + +package sqlite + +import ( + "net/http" + "path/filepath" + + "go.mindeco.de/goutils" +) + +// absolute path of where this package is located +var pkgDir = goutils.MustLocatePackage("github.com/ssb-ngi-pointer/gossb-rooms/admindb/sqlite") + +var Migrations http.FileSystem = http.Dir(filepath.Join(pkgDir, "migrations")) diff --git a/admindb/sqlite/migrations_generate.go b/admindb/sqlite/migrations_generate.go new file mode 100644 index 0000000..a6b9292 --- /dev/null +++ b/admindb/sqlite/migrations_generate.go @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +// +build ignore + +package main + +import ( + "log" + + "github.com/shurcooL/vfsgen" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb/sqlite" +) + +func main() { + err := vfsgen.Generate(sqlite.Migrations, vfsgen.Options{ + PackageName: "sqlite", + BuildTags: "!dev", + VariableName: "Migrations", + }) + if err != nil { + log.Fatalln(err) + } + +} diff --git a/admindb/sqlite/migrations_vfsdata.go b/admindb/sqlite/migrations_vfsdata.go new file mode 100644 index 0000000..a6b7ef3 --- /dev/null +++ b/admindb/sqlite/migrations_vfsdata.go @@ -0,0 +1,186 @@ +// Code generated by vfsgen; DO NOT EDIT. + +// +build !dev + +package sqlite + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + pathpkg "path" + "time" +) + +// Migrations statically implements the virtual filesystem provided to vfsgen. +var Migrations = func() http.FileSystem { + fs := vfsgen۰FS{ + "/": &vfsgen۰DirInfo{ + name: "/", + modTime: time.Date(2021, 2, 9, 15, 7, 28, 781106037, time.UTC), + }, + "/create-auth-fallback.sql": &vfsgen۰CompressedFileInfo{ + name: "create-auth-fallback.sql", + modTime: time.Date(2021, 2, 9, 15, 13, 52, 278658510, time.UTC), + uncompressedSize: 189, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\x6c\xce\xb1\x0e\x82\x30\x14\x85\xe1\xfd\x3e\xc5\x19\x35\xca\x13\x30\xa1\x74\x20\x22\x60\x43\x07\x26\x72\x11\x14\x62\x69\x09\x2d\xc1\xc7\x37\x9a\x98\x38\x78\xd6\xf3\x0f\x5f\x10\x60\x37\x0e\xf7\x99\x7d\x07\x35\xd1\x51\x8a\xa8\x14\x28\xa3\x43\x2a\xc0\x8b\xef\xeb\x1b\x6b\xdd\xf0\xf5\x81\x0d\x01\x43\x0b\x60\x30\x1e\x85\x4c\xce\x91\xac\x70\x12\x15\xb2\xbc\x44\xa6\xd2\x74\x4f\x80\xe1\xb1\x83\xef\x9e\x1e\x9f\x7d\x2f\xa8\x2c\xb9\x28\xf1\x2e\x26\x76\x6e\xb5\x73\x5b\xf7\xec\x7a\x34\xda\x36\x30\xd6\xc3\x2c\x5a\x03\xb4\x0d\x89\x7e\x49\xb1\x5d\x0d\xc5\x32\x2f\xfe\x91\xc2\x57\x00\x00\x00\xff\xff\x23\xca\x06\xae\xbd\x00\x00\x00"), + }, + } + fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{ + fs["/create-auth-fallback.sql"].(os.FileInfo), + } + + return fs +}() + +type vfsgen۰FS map[string]interface{} + +func (fs vfsgen۰FS) Open(path string) (http.File, error) { + path = pathpkg.Clean("/" + path) + f, ok := fs[path] + if !ok { + return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist} + } + + switch f := f.(type) { + case *vfsgen۰CompressedFileInfo: + gr, err := gzip.NewReader(bytes.NewReader(f.compressedContent)) + if err != nil { + // This should never happen because we generate the gzip bytes such that they are always valid. + panic("unexpected error reading own gzip compressed bytes: " + err.Error()) + } + return &vfsgen۰CompressedFile{ + vfsgen۰CompressedFileInfo: f, + gr: gr, + }, nil + case *vfsgen۰DirInfo: + return &vfsgen۰Dir{ + vfsgen۰DirInfo: f, + }, nil + default: + // This should never happen because we generate only the above types. + panic(fmt.Sprintf("unexpected type %T", f)) + } +} + +// vfsgen۰CompressedFileInfo is a static definition of a gzip compressed file. +type vfsgen۰CompressedFileInfo struct { + name string + modTime time.Time + compressedContent []byte + uncompressedSize int64 +} + +func (f *vfsgen۰CompressedFileInfo) Readdir(count int) ([]os.FileInfo, error) { + return nil, fmt.Errorf("cannot Readdir from file %s", f.name) +} +func (f *vfsgen۰CompressedFileInfo) Stat() (os.FileInfo, error) { return f, nil } + +func (f *vfsgen۰CompressedFileInfo) GzipBytes() []byte { + return f.compressedContent +} + +func (f *vfsgen۰CompressedFileInfo) Name() string { return f.name } +func (f *vfsgen۰CompressedFileInfo) Size() int64 { return f.uncompressedSize } +func (f *vfsgen۰CompressedFileInfo) Mode() os.FileMode { return 0444 } +func (f *vfsgen۰CompressedFileInfo) ModTime() time.Time { return f.modTime } +func (f *vfsgen۰CompressedFileInfo) IsDir() bool { return false } +func (f *vfsgen۰CompressedFileInfo) Sys() interface{} { return nil } + +// vfsgen۰CompressedFile is an opened compressedFile instance. +type vfsgen۰CompressedFile struct { + *vfsgen۰CompressedFileInfo + gr *gzip.Reader + grPos int64 // Actual gr uncompressed position. + seekPos int64 // Seek uncompressed position. +} + +func (f *vfsgen۰CompressedFile) Read(p []byte) (n int, err error) { + if f.grPos > f.seekPos { + // Rewind to beginning. + err = f.gr.Reset(bytes.NewReader(f.compressedContent)) + if err != nil { + return 0, err + } + f.grPos = 0 + } + if f.grPos < f.seekPos { + // Fast-forward. + _, err = io.CopyN(ioutil.Discard, f.gr, f.seekPos-f.grPos) + if err != nil { + return 0, err + } + f.grPos = f.seekPos + } + n, err = f.gr.Read(p) + f.grPos += int64(n) + f.seekPos = f.grPos + return n, err +} +func (f *vfsgen۰CompressedFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + f.seekPos = 0 + offset + case io.SeekCurrent: + f.seekPos += offset + case io.SeekEnd: + f.seekPos = f.uncompressedSize + offset + default: + panic(fmt.Errorf("invalid whence value: %v", whence)) + } + return f.seekPos, nil +} +func (f *vfsgen۰CompressedFile) Close() error { + return f.gr.Close() +} + +// vfsgen۰DirInfo is a static definition of a directory. +type vfsgen۰DirInfo struct { + name string + modTime time.Time + entries []os.FileInfo +} + +func (d *vfsgen۰DirInfo) Read([]byte) (int, error) { + return 0, fmt.Errorf("cannot Read from directory %s", d.name) +} +func (d *vfsgen۰DirInfo) Close() error { return nil } +func (d *vfsgen۰DirInfo) Stat() (os.FileInfo, error) { return d, nil } + +func (d *vfsgen۰DirInfo) Name() string { return d.name } +func (d *vfsgen۰DirInfo) Size() int64 { return 0 } +func (d *vfsgen۰DirInfo) Mode() os.FileMode { return 0755 | os.ModeDir } +func (d *vfsgen۰DirInfo) ModTime() time.Time { return d.modTime } +func (d *vfsgen۰DirInfo) IsDir() bool { return true } +func (d *vfsgen۰DirInfo) Sys() interface{} { return nil } + +// vfsgen۰Dir is an opened dir instance. +type vfsgen۰Dir struct { + *vfsgen۰DirInfo + pos int // Position within entries for Seek and Readdir. +} + +func (d *vfsgen۰Dir) Seek(offset int64, whence int) (int64, error) { + if offset == 0 && whence == io.SeekStart { + d.pos = 0 + return 0, nil + } + return 0, fmt.Errorf("unsupported Seek in directory %s", d.name) +} + +func (d *vfsgen۰Dir) Readdir(count int) ([]os.FileInfo, error) { + if d.pos >= len(d.entries) && count > 0 { + return nil, io.EOF + } + if count <= 0 || count > len(d.entries)-d.pos { + count = len(d.entries) - d.pos + } + e := d.entries[d.pos : d.pos+count] + d.pos += count + return e, nil +} diff --git a/admindb/sqlite/models/aliases.go b/admindb/sqlite/models/aliases.go deleted file mode 100644 index b6ef574..0000000 --- a/admindb/sqlite/models/aliases.go +++ /dev/null @@ -1,819 +0,0 @@ -// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. -// This file is meant to be re-generated in place and/or deleted at any time. - -package models - -import ( - "context" - "database/sql" - "fmt" - "reflect" - "strings" - "sync" - "time" - - "github.com/friendsofgo/errors" - "github.com/volatiletech/sqlboiler/v4/boil" - "github.com/volatiletech/sqlboiler/v4/queries" - "github.com/volatiletech/sqlboiler/v4/queries/qm" - "github.com/volatiletech/sqlboiler/v4/queries/qmhelper" - "github.com/volatiletech/strmangle" -) - -// Alias is an object representing the database table. -type Alias struct { - ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"` - Name string `boil:"name" json:"name" toml:"name" yaml:"name"` - PubKey string `boil:"pub_key" json:"pub_key" toml:"pub_key" yaml:"pub_key"` - - R *aliasR `boil:"-" json:"-" toml:"-" yaml:"-"` - L aliasL `boil:"-" json:"-" toml:"-" yaml:"-"` -} - -var AliasColumns = struct { - ID string - Name string - PubKey string -}{ - ID: "id", - Name: "name", - PubKey: "pub_key", -} - -// Generated where - -type whereHelperint64 struct{ field string } - -func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } -func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } -func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } -func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } -func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } -func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } -func (w whereHelperint64) IN(slice []int64) qm.QueryMod { - values := make([]interface{}, 0, len(slice)) - for _, value := range slice { - values = append(values, value) - } - return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...) -} -func (w whereHelperint64) NIN(slice []int64) qm.QueryMod { - values := make([]interface{}, 0, len(slice)) - for _, value := range slice { - values = append(values, value) - } - return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...) -} - -type whereHelperstring struct{ field string } - -func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } -func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } -func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } -func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } -func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } -func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } -func (w whereHelperstring) IN(slice []string) qm.QueryMod { - values := make([]interface{}, 0, len(slice)) - for _, value := range slice { - values = append(values, value) - } - return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...) -} -func (w whereHelperstring) NIN(slice []string) qm.QueryMod { - values := make([]interface{}, 0, len(slice)) - for _, value := range slice { - values = append(values, value) - } - return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...) -} - -var AliasWhere = struct { - ID whereHelperint64 - Name whereHelperstring - PubKey whereHelperstring -}{ - ID: whereHelperint64{field: "\"aliases\".\"id\""}, - Name: whereHelperstring{field: "\"aliases\".\"name\""}, - PubKey: whereHelperstring{field: "\"aliases\".\"pub_key\""}, -} - -// AliasRels is where relationship names are stored. -var AliasRels = struct { -}{} - -// aliasR is where relationships are stored. -type aliasR struct { -} - -// NewStruct creates a new relationship struct -func (*aliasR) NewStruct() *aliasR { - return &aliasR{} -} - -// aliasL is where Load methods for each relationship are stored. -type aliasL struct{} - -var ( - aliasAllColumns = []string{"id", "name", "pub_key"} - aliasColumnsWithoutDefault = []string{"id", "name", "pub_key"} - aliasColumnsWithDefault = []string{} - aliasPrimaryKeyColumns = []string{"id"} -) - -type ( - // AliasSlice is an alias for a slice of pointers to Alias. - // This should generally be used opposed to []Alias. - AliasSlice []*Alias - // AliasHook is the signature for custom Alias hook methods - AliasHook func(context.Context, boil.ContextExecutor, *Alias) error - - aliasQuery struct { - *queries.Query - } -) - -// Cache for insert, update and upsert -var ( - aliasType = reflect.TypeOf(&Alias{}) - aliasMapping = queries.MakeStructMapping(aliasType) - aliasPrimaryKeyMapping, _ = queries.BindMapping(aliasType, aliasMapping, aliasPrimaryKeyColumns) - aliasInsertCacheMut sync.RWMutex - aliasInsertCache = make(map[string]insertCache) - aliasUpdateCacheMut sync.RWMutex - aliasUpdateCache = make(map[string]updateCache) - aliasUpsertCacheMut sync.RWMutex - aliasUpsertCache = make(map[string]insertCache) -) - -var ( - // Force time package dependency for automated UpdatedAt/CreatedAt. - _ = time.Second - // Force qmhelper dependency for where clause generation (which doesn't - // always happen) - _ = qmhelper.Where -) - -var aliasBeforeInsertHooks []AliasHook -var aliasBeforeUpdateHooks []AliasHook -var aliasBeforeDeleteHooks []AliasHook -var aliasBeforeUpsertHooks []AliasHook - -var aliasAfterInsertHooks []AliasHook -var aliasAfterSelectHooks []AliasHook -var aliasAfterUpdateHooks []AliasHook -var aliasAfterDeleteHooks []AliasHook -var aliasAfterUpsertHooks []AliasHook - -// doBeforeInsertHooks executes all "before insert" hooks. -func (o *Alias) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasBeforeInsertHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doBeforeUpdateHooks executes all "before Update" hooks. -func (o *Alias) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasBeforeUpdateHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doBeforeDeleteHooks executes all "before Delete" hooks. -func (o *Alias) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasBeforeDeleteHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doBeforeUpsertHooks executes all "before Upsert" hooks. -func (o *Alias) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasBeforeUpsertHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doAfterInsertHooks executes all "after Insert" hooks. -func (o *Alias) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasAfterInsertHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doAfterSelectHooks executes all "after Select" hooks. -func (o *Alias) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasAfterSelectHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doAfterUpdateHooks executes all "after Update" hooks. -func (o *Alias) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasAfterUpdateHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doAfterDeleteHooks executes all "after Delete" hooks. -func (o *Alias) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasAfterDeleteHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// doAfterUpsertHooks executes all "after Upsert" hooks. -func (o *Alias) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { - if boil.HooksAreSkipped(ctx) { - return nil - } - - for _, hook := range aliasAfterUpsertHooks { - if err := hook(ctx, exec, o); err != nil { - return err - } - } - - return nil -} - -// AddAliasHook registers your hook function for all future operations. -func AddAliasHook(hookPoint boil.HookPoint, aliasHook AliasHook) { - switch hookPoint { - case boil.BeforeInsertHook: - aliasBeforeInsertHooks = append(aliasBeforeInsertHooks, aliasHook) - case boil.BeforeUpdateHook: - aliasBeforeUpdateHooks = append(aliasBeforeUpdateHooks, aliasHook) - case boil.BeforeDeleteHook: - aliasBeforeDeleteHooks = append(aliasBeforeDeleteHooks, aliasHook) - case boil.BeforeUpsertHook: - aliasBeforeUpsertHooks = append(aliasBeforeUpsertHooks, aliasHook) - case boil.AfterInsertHook: - aliasAfterInsertHooks = append(aliasAfterInsertHooks, aliasHook) - case boil.AfterSelectHook: - aliasAfterSelectHooks = append(aliasAfterSelectHooks, aliasHook) - case boil.AfterUpdateHook: - aliasAfterUpdateHooks = append(aliasAfterUpdateHooks, aliasHook) - case boil.AfterDeleteHook: - aliasAfterDeleteHooks = append(aliasAfterDeleteHooks, aliasHook) - case boil.AfterUpsertHook: - aliasAfterUpsertHooks = append(aliasAfterUpsertHooks, aliasHook) - } -} - -// One returns a single alias record from the query. -func (q aliasQuery) One(ctx context.Context, exec boil.ContextExecutor) (*Alias, error) { - o := &Alias{} - - queries.SetLimit(q.Query, 1) - - err := q.Bind(ctx, exec, o) - if err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return nil, sql.ErrNoRows - } - return nil, errors.Wrap(err, "models: failed to execute a one query for aliases") - } - - if err := o.doAfterSelectHooks(ctx, exec); err != nil { - return o, err - } - - return o, nil -} - -// All returns all Alias records from the query. -func (q aliasQuery) All(ctx context.Context, exec boil.ContextExecutor) (AliasSlice, error) { - var o []*Alias - - err := q.Bind(ctx, exec, &o) - if err != nil { - return nil, errors.Wrap(err, "models: failed to assign all query results to Alias slice") - } - - if len(aliasAfterSelectHooks) != 0 { - for _, obj := range o { - if err := obj.doAfterSelectHooks(ctx, exec); err != nil { - return o, err - } - } - } - - return o, nil -} - -// Count returns the count of all Alias records in the query. -func (q aliasQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) { - var count int64 - - queries.SetSelect(q.Query, nil) - queries.SetCount(q.Query) - - err := q.Query.QueryRowContext(ctx, exec).Scan(&count) - if err != nil { - return 0, errors.Wrap(err, "models: failed to count aliases rows") - } - - return count, nil -} - -// Exists checks if the row exists in the table. -func (q aliasQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { - var count int64 - - queries.SetSelect(q.Query, nil) - queries.SetCount(q.Query) - queries.SetLimit(q.Query, 1) - - err := q.Query.QueryRowContext(ctx, exec).Scan(&count) - if err != nil { - return false, errors.Wrap(err, "models: failed to check if aliases exists") - } - - return count > 0, nil -} - -// Aliases retrieves all the records using an executor. -func Aliases(mods ...qm.QueryMod) aliasQuery { - mods = append(mods, qm.From("\"aliases\"")) - return aliasQuery{NewQuery(mods...)} -} - -// FindAlias retrieves a single record by ID with an executor. -// If selectCols is empty Find will return all columns. -func FindAlias(ctx context.Context, exec boil.ContextExecutor, iD int64, selectCols ...string) (*Alias, error) { - aliasObj := &Alias{} - - sel := "*" - if len(selectCols) > 0 { - sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") - } - query := fmt.Sprintf( - "select %s from \"aliases\" where \"id\"=?", sel, - ) - - q := queries.Raw(query, iD) - - err := q.Bind(ctx, exec, aliasObj) - if err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return nil, sql.ErrNoRows - } - return nil, errors.Wrap(err, "models: unable to select from aliases") - } - - return aliasObj, nil -} - -// Insert a single record using an executor. -// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. -func (o *Alias) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { - if o == nil { - return errors.New("models: no aliases provided for insertion") - } - - var err error - - if err := o.doBeforeInsertHooks(ctx, exec); err != nil { - return err - } - - nzDefaults := queries.NonZeroDefaultSet(aliasColumnsWithDefault, o) - - key := makeCacheKey(columns, nzDefaults) - aliasInsertCacheMut.RLock() - cache, cached := aliasInsertCache[key] - aliasInsertCacheMut.RUnlock() - - if !cached { - wl, returnColumns := columns.InsertColumnSet( - aliasAllColumns, - aliasColumnsWithDefault, - aliasColumnsWithoutDefault, - nzDefaults, - ) - - cache.valueMapping, err = queries.BindMapping(aliasType, aliasMapping, wl) - if err != nil { - return err - } - cache.retMapping, err = queries.BindMapping(aliasType, aliasMapping, returnColumns) - if err != nil { - return err - } - if len(wl) != 0 { - cache.query = fmt.Sprintf("INSERT INTO \"aliases\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) - } else { - cache.query = "INSERT INTO \"aliases\" %sDEFAULT VALUES%s" - } - - var queryOutput, queryReturning string - - if len(cache.retMapping) != 0 { - cache.retQuery = fmt.Sprintf("SELECT \"%s\" FROM \"aliases\" WHERE %s", strings.Join(returnColumns, "\",\""), strmangle.WhereClause("\"", "\"", 0, aliasPrimaryKeyColumns)) - } - - cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning) - } - - value := reflect.Indirect(reflect.ValueOf(o)) - vals := queries.ValuesFromMapping(value, cache.valueMapping) - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, vals) - } - _, err = exec.ExecContext(ctx, cache.query, vals...) - - if err != nil { - return errors.Wrap(err, "models: unable to insert into aliases") - } - - var identifierCols []interface{} - - if len(cache.retMapping) == 0 { - goto CacheNoHooks - } - - identifierCols = []interface{}{ - o.ID, - } - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.retQuery) - fmt.Fprintln(writer, identifierCols...) - } - err = exec.QueryRowContext(ctx, cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) - if err != nil { - return errors.Wrap(err, "models: unable to populate default values for aliases") - } - -CacheNoHooks: - if !cached { - aliasInsertCacheMut.Lock() - aliasInsertCache[key] = cache - aliasInsertCacheMut.Unlock() - } - - return o.doAfterInsertHooks(ctx, exec) -} - -// Update uses an executor to update the Alias. -// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates. -// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records. -func (o *Alias) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { - var err error - if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { - return 0, err - } - key := makeCacheKey(columns, nil) - aliasUpdateCacheMut.RLock() - cache, cached := aliasUpdateCache[key] - aliasUpdateCacheMut.RUnlock() - - if !cached { - wl := columns.UpdateColumnSet( - aliasAllColumns, - aliasPrimaryKeyColumns, - ) - - if !columns.IsWhitelist() { - wl = strmangle.SetComplement(wl, []string{"created_at"}) - } - if len(wl) == 0 { - return 0, errors.New("models: unable to update aliases, could not build whitelist") - } - - cache.query = fmt.Sprintf("UPDATE \"aliases\" SET %s WHERE %s", - strmangle.SetParamNames("\"", "\"", 0, wl), - strmangle.WhereClause("\"", "\"", 0, aliasPrimaryKeyColumns), - ) - cache.valueMapping, err = queries.BindMapping(aliasType, aliasMapping, append(wl, aliasPrimaryKeyColumns...)) - if err != nil { - return 0, err - } - } - - values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, cache.query) - fmt.Fprintln(writer, values) - } - var result sql.Result - result, err = exec.ExecContext(ctx, cache.query, values...) - if err != nil { - return 0, errors.Wrap(err, "models: unable to update aliases row") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: failed to get rows affected by update for aliases") - } - - if !cached { - aliasUpdateCacheMut.Lock() - aliasUpdateCache[key] = cache - aliasUpdateCacheMut.Unlock() - } - - return rowsAff, o.doAfterUpdateHooks(ctx, exec) -} - -// UpdateAll updates all rows with the specified column values. -func (q aliasQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { - queries.SetUpdate(q.Query, cols) - - result, err := q.Query.ExecContext(ctx, exec) - if err != nil { - return 0, errors.Wrap(err, "models: unable to update all for aliases") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: unable to retrieve rows affected for aliases") - } - - return rowsAff, nil -} - -// UpdateAll updates all rows with the specified column values, using an executor. -func (o AliasSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { - ln := int64(len(o)) - if ln == 0 { - return 0, nil - } - - if len(cols) == 0 { - return 0, errors.New("models: update all requires at least one column argument") - } - - colNames := make([]string, len(cols)) - args := make([]interface{}, len(cols)) - - i := 0 - for name, value := range cols { - colNames[i] = name - args[i] = value - i++ - } - - // Append all of the primary key values for each column - for _, obj := range o { - pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) - args = append(args, pkeyArgs...) - } - - sql := fmt.Sprintf("UPDATE \"aliases\" SET %s WHERE %s", - strmangle.SetParamNames("\"", "\"", 0, colNames), - strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(o))) - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, sql) - fmt.Fprintln(writer, args...) - } - result, err := exec.ExecContext(ctx, sql, args...) - if err != nil { - return 0, errors.Wrap(err, "models: unable to update all in alias slice") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all alias") - } - return rowsAff, nil -} - -// Delete deletes a single Alias record with an executor. -// Delete will match against the primary key column to find the record to delete. -func (o *Alias) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { - if o == nil { - return 0, errors.New("models: no Alias provided for delete") - } - - if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { - return 0, err - } - - args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), aliasPrimaryKeyMapping) - sql := "DELETE FROM \"aliases\" WHERE \"id\"=?" - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, sql) - fmt.Fprintln(writer, args...) - } - result, err := exec.ExecContext(ctx, sql, args...) - if err != nil { - return 0, errors.Wrap(err, "models: unable to delete from aliases") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: failed to get rows affected by delete for aliases") - } - - if err := o.doAfterDeleteHooks(ctx, exec); err != nil { - return 0, err - } - - return rowsAff, nil -} - -// DeleteAll deletes all matching rows. -func (q aliasQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { - if q.Query == nil { - return 0, errors.New("models: no aliasQuery provided for delete all") - } - - queries.SetDelete(q.Query) - - result, err := q.Query.ExecContext(ctx, exec) - if err != nil { - return 0, errors.Wrap(err, "models: unable to delete all from aliases") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for aliases") - } - - return rowsAff, nil -} - -// DeleteAll deletes all rows in the slice, using an executor. -func (o AliasSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { - if len(o) == 0 { - return 0, nil - } - - if len(aliasBeforeDeleteHooks) != 0 { - for _, obj := range o { - if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil { - return 0, err - } - } - } - - var args []interface{} - for _, obj := range o { - pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) - args = append(args, pkeyArgs...) - } - - sql := "DELETE FROM \"aliases\" WHERE " + - strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(o)) - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, sql) - fmt.Fprintln(writer, args) - } - result, err := exec.ExecContext(ctx, sql, args...) - if err != nil { - return 0, errors.Wrap(err, "models: unable to delete all from alias slice") - } - - rowsAff, err := result.RowsAffected() - if err != nil { - return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for aliases") - } - - if len(aliasAfterDeleteHooks) != 0 { - for _, obj := range o { - if err := obj.doAfterDeleteHooks(ctx, exec); err != nil { - return 0, err - } - } - } - - return rowsAff, nil -} - -// Reload refetches the object from the database -// using the primary keys with an executor. -func (o *Alias) Reload(ctx context.Context, exec boil.ContextExecutor) error { - ret, err := FindAlias(ctx, exec, o.ID) - if err != nil { - return err - } - - *o = *ret - return nil -} - -// ReloadAll refetches every row with matching primary key column values -// and overwrites the original object slice with the newly updated slice. -func (o *AliasSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { - if o == nil || len(*o) == 0 { - return nil - } - - slice := AliasSlice{} - var args []interface{} - for _, obj := range *o { - pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) - args = append(args, pkeyArgs...) - } - - sql := "SELECT \"aliases\".* FROM \"aliases\" WHERE " + - strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(*o)) - - q := queries.Raw(sql, args...) - - err := q.Bind(ctx, exec, &slice) - if err != nil { - return errors.Wrap(err, "models: unable to reload all in AliasSlice") - } - - *o = slice - - return nil -} - -// AliasExists checks if the Alias row exists. -func AliasExists(ctx context.Context, exec boil.ContextExecutor, iD int64) (bool, error) { - var exists bool - sql := "select exists(select 1 from \"aliases\" where \"id\"=? limit 1)" - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, sql) - fmt.Fprintln(writer, iD) - } - row := exec.QueryRowContext(ctx, sql, iD) - - err := row.Scan(&exists) - if err != nil { - return false, errors.Wrap(err, "models: unable to check if aliases exists") - } - - return exists, nil -} diff --git a/admindb/sqlite/models/aliases_test.go b/admindb/sqlite/models/aliases_test.go deleted file mode 100644 index 06344d2..0000000 --- a/admindb/sqlite/models/aliases_test.go +++ /dev/null @@ -1,684 +0,0 @@ -// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. -// This file is meant to be re-generated in place and/or deleted at any time. - -package models - -import ( - "bytes" - "context" - "reflect" - "testing" - - "github.com/volatiletech/randomize" - "github.com/volatiletech/sqlboiler/v4/boil" - "github.com/volatiletech/sqlboiler/v4/queries" - "github.com/volatiletech/strmangle" -) - -var ( - // Relationships sometimes use the reflection helper queries.Equal/queries.Assign - // so force a package dependency in case they don't. - _ = queries.Equal -) - -func testAliases(t *testing.T) { - t.Parallel() - - query := Aliases() - - if query.Query == nil { - t.Error("expected a query, got nothing") - } -} - -func testAliasesDelete(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - if rowsAff, err := o.Delete(ctx, tx); err != nil { - t.Error(err) - } else if rowsAff != 1 { - t.Error("should only have deleted one row, but affected:", rowsAff) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 0 { - t.Error("want zero records, got:", count) - } -} - -func testAliasesQueryDeleteAll(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - if rowsAff, err := Aliases().DeleteAll(ctx, tx); err != nil { - t.Error(err) - } else if rowsAff != 1 { - t.Error("should only have deleted one row, but affected:", rowsAff) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 0 { - t.Error("want zero records, got:", count) - } -} - -func testAliasesSliceDeleteAll(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - slice := AliasSlice{o} - - if rowsAff, err := slice.DeleteAll(ctx, tx); err != nil { - t.Error(err) - } else if rowsAff != 1 { - t.Error("should only have deleted one row, but affected:", rowsAff) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 0 { - t.Error("want zero records, got:", count) - } -} - -func testAliasesExists(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - e, err := AliasExists(ctx, tx, o.ID) - if err != nil { - t.Errorf("Unable to check if Alias exists: %s", err) - } - if !e { - t.Errorf("Expected AliasExists to return true, but got false.") - } -} - -func testAliasesFind(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - aliasFound, err := FindAlias(ctx, tx, o.ID) - if err != nil { - t.Error(err) - } - - if aliasFound == nil { - t.Error("want a record, got nil") - } -} - -func testAliasesBind(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - if err = Aliases().Bind(ctx, tx, o); err != nil { - t.Error(err) - } -} - -func testAliasesOne(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - if x, err := Aliases().One(ctx, tx); err != nil { - t.Error(err) - } else if x == nil { - t.Error("expected to get a non nil record") - } -} - -func testAliasesAll(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - aliasOne := &Alias{} - aliasTwo := &Alias{} - if err = randomize.Struct(seed, aliasOne, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - if err = randomize.Struct(seed, aliasTwo, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = aliasOne.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - if err = aliasTwo.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - slice, err := Aliases().All(ctx, tx) - if err != nil { - t.Error(err) - } - - if len(slice) != 2 { - t.Error("want 2 records, got:", len(slice)) - } -} - -func testAliasesCount(t *testing.T) { - t.Parallel() - - var err error - seed := randomize.NewSeed() - aliasOne := &Alias{} - aliasTwo := &Alias{} - if err = randomize.Struct(seed, aliasOne, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - if err = randomize.Struct(seed, aliasTwo, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = aliasOne.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - if err = aliasTwo.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 2 { - t.Error("want 2 records, got:", count) - } -} - -func aliasBeforeInsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasAfterInsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasAfterSelectHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasBeforeUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasAfterUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasBeforeDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasAfterDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasBeforeUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func aliasAfterUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { - *o = Alias{} - return nil -} - -func testAliasesHooks(t *testing.T) { - t.Parallel() - - var err error - - ctx := context.Background() - empty := &Alias{} - o := &Alias{} - - seed := randomize.NewSeed() - if err = randomize.Struct(seed, o, aliasDBTypes, false); err != nil { - t.Errorf("Unable to randomize Alias object: %s", err) - } - - AddAliasHook(boil.BeforeInsertHook, aliasBeforeInsertHook) - if err = o.doBeforeInsertHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doBeforeInsertHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected BeforeInsertHook function to empty object, but got: %#v", o) - } - aliasBeforeInsertHooks = []AliasHook{} - - AddAliasHook(boil.AfterInsertHook, aliasAfterInsertHook) - if err = o.doAfterInsertHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doAfterInsertHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected AfterInsertHook function to empty object, but got: %#v", o) - } - aliasAfterInsertHooks = []AliasHook{} - - AddAliasHook(boil.AfterSelectHook, aliasAfterSelectHook) - if err = o.doAfterSelectHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doAfterSelectHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected AfterSelectHook function to empty object, but got: %#v", o) - } - aliasAfterSelectHooks = []AliasHook{} - - AddAliasHook(boil.BeforeUpdateHook, aliasBeforeUpdateHook) - if err = o.doBeforeUpdateHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doBeforeUpdateHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected BeforeUpdateHook function to empty object, but got: %#v", o) - } - aliasBeforeUpdateHooks = []AliasHook{} - - AddAliasHook(boil.AfterUpdateHook, aliasAfterUpdateHook) - if err = o.doAfterUpdateHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doAfterUpdateHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected AfterUpdateHook function to empty object, but got: %#v", o) - } - aliasAfterUpdateHooks = []AliasHook{} - - AddAliasHook(boil.BeforeDeleteHook, aliasBeforeDeleteHook) - if err = o.doBeforeDeleteHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doBeforeDeleteHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected BeforeDeleteHook function to empty object, but got: %#v", o) - } - aliasBeforeDeleteHooks = []AliasHook{} - - AddAliasHook(boil.AfterDeleteHook, aliasAfterDeleteHook) - if err = o.doAfterDeleteHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doAfterDeleteHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected AfterDeleteHook function to empty object, but got: %#v", o) - } - aliasAfterDeleteHooks = []AliasHook{} - - AddAliasHook(boil.BeforeUpsertHook, aliasBeforeUpsertHook) - if err = o.doBeforeUpsertHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected BeforeUpsertHook function to empty object, but got: %#v", o) - } - aliasBeforeUpsertHooks = []AliasHook{} - - AddAliasHook(boil.AfterUpsertHook, aliasAfterUpsertHook) - if err = o.doAfterUpsertHooks(ctx, nil); err != nil { - t.Errorf("Unable to execute doAfterUpsertHooks: %s", err) - } - if !reflect.DeepEqual(o, empty) { - t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o) - } - aliasAfterUpsertHooks = []AliasHook{} -} - -func testAliasesInsert(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 1 { - t.Error("want one record, got:", count) - } -} - -func testAliasesInsertWhitelist(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Whitelist(aliasColumnsWithoutDefault...)); err != nil { - t.Error(err) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 1 { - t.Error("want one record, got:", count) - } -} - -func testAliasesReload(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - if err = o.Reload(ctx, tx); err != nil { - t.Error(err) - } -} - -func testAliasesReloadAll(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - slice := AliasSlice{o} - - if err = slice.ReloadAll(ctx, tx); err != nil { - t.Error(err) - } -} - -func testAliasesSelect(t *testing.T) { - t.Parallel() - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - slice, err := Aliases().All(ctx, tx) - if err != nil { - t.Error(err) - } - - if len(slice) != 1 { - t.Error("want one record, got:", len(slice)) - } -} - -var ( - aliasDBTypes = map[string]string{`ID`: `INT`, `Name`: `TEXT`, `PubKey`: `TEXT`} - _ = bytes.MinRead -) - -func testAliasesUpdate(t *testing.T) { - t.Parallel() - - if 0 == len(aliasPrimaryKeyColumns) { - t.Skip("Skipping table with no primary key columns") - } - if len(aliasAllColumns) == len(aliasPrimaryKeyColumns) { - t.Skip("Skipping table with only primary key columns") - } - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 1 { - t.Error("want one record, got:", count) - } - - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasPrimaryKeyColumns...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - if rowsAff, err := o.Update(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } else if rowsAff != 1 { - t.Error("should only affect one row but affected", rowsAff) - } -} - -func testAliasesSliceUpdateAll(t *testing.T) { - t.Parallel() - - if len(aliasAllColumns) == len(aliasPrimaryKeyColumns) { - t.Skip("Skipping table with only primary key columns") - } - - seed := randomize.NewSeed() - var err error - o := &Alias{} - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - ctx := context.Background() - tx := MustTx(boil.BeginTx(ctx, nil)) - defer func() { _ = tx.Rollback() }() - if err = o.Insert(ctx, tx, boil.Infer()); err != nil { - t.Error(err) - } - - count, err := Aliases().Count(ctx, tx) - if err != nil { - t.Error(err) - } - - if count != 1 { - t.Error("want one record, got:", count) - } - - if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasPrimaryKeyColumns...); err != nil { - t.Errorf("Unable to randomize Alias struct: %s", err) - } - - // Remove Primary keys and unique columns from what we plan to update - var fields []string - if strmangle.StringSliceMatch(aliasAllColumns, aliasPrimaryKeyColumns) { - fields = aliasAllColumns - } else { - fields = strmangle.SetComplement( - aliasAllColumns, - aliasPrimaryKeyColumns, - ) - } - - value := reflect.Indirect(reflect.ValueOf(o)) - typ := reflect.TypeOf(o).Elem() - n := typ.NumField() - - updateMap := M{} - for _, col := range fields { - for i := 0; i < n; i++ { - f := typ.Field(i) - if f.Tag.Get("boil") == col { - updateMap[col] = value.Field(i).Interface() - } - } - } - - slice := AliasSlice{o} - if rowsAff, err := slice.UpdateAll(ctx, tx, updateMap); err != nil { - t.Error(err) - } else if rowsAff != 1 { - t.Error("wanted one record updated but got", rowsAff) - } -} diff --git a/admindb/sqlite/models/auth_fallback.go b/admindb/sqlite/models/auth_fallback.go index a9db88d..e46753e 100644 --- a/admindb/sqlite/models/auth_fallback.go +++ b/admindb/sqlite/models/auth_fallback.go @@ -42,6 +42,52 @@ var AuthFallbackColumns = struct { // Generated where +type whereHelperint64 struct{ field string } + +func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } +func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } +func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } +func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } +func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } +func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } +func (w whereHelperint64) IN(slice []int64) qm.QueryMod { + values := make([]interface{}, 0, len(slice)) + for _, value := range slice { + values = append(values, value) + } + return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...) +} +func (w whereHelperint64) NIN(slice []int64) qm.QueryMod { + values := make([]interface{}, 0, len(slice)) + for _, value := range slice { + values = append(values, value) + } + return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...) +} + +type whereHelperstring struct{ field string } + +func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } +func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } +func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } +func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } +func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } +func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } +func (w whereHelperstring) IN(slice []string) qm.QueryMod { + values := make([]interface{}, 0, len(slice)) + for _, value := range slice { + values = append(values, value) + } + return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...) +} +func (w whereHelperstring) NIN(slice []string) qm.QueryMod { + values := make([]interface{}, 0, len(slice)) + for _, value := range slice { + values = append(values, value) + } + return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...) +} + type whereHelper__byte struct{ field string } func (w whereHelper__byte) EQ(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } diff --git a/admindb/sqlite/models/boil_suites_test.go b/admindb/sqlite/models/boil_suites_test.go index 086d8cc..3d4cdbf 100644 --- a/admindb/sqlite/models/boil_suites_test.go +++ b/admindb/sqlite/models/boil_suites_test.go @@ -12,63 +12,50 @@ import "testing" // It does NOT run each operation group in parallel. // Separating the tests thusly grants avoidance of Postgres deadlocks. func TestParent(t *testing.T) { - t.Run("Aliases", testAliases) t.Run("AuthFallbacks", testAuthFallbacks) } func TestDelete(t *testing.T) { - t.Run("Aliases", testAliasesDelete) t.Run("AuthFallbacks", testAuthFallbacksDelete) } func TestQueryDeleteAll(t *testing.T) { - t.Run("Aliases", testAliasesQueryDeleteAll) t.Run("AuthFallbacks", testAuthFallbacksQueryDeleteAll) } func TestSliceDeleteAll(t *testing.T) { - t.Run("Aliases", testAliasesSliceDeleteAll) t.Run("AuthFallbacks", testAuthFallbacksSliceDeleteAll) } func TestExists(t *testing.T) { - t.Run("Aliases", testAliasesExists) t.Run("AuthFallbacks", testAuthFallbacksExists) } func TestFind(t *testing.T) { - t.Run("Aliases", testAliasesFind) t.Run("AuthFallbacks", testAuthFallbacksFind) } func TestBind(t *testing.T) { - t.Run("Aliases", testAliasesBind) t.Run("AuthFallbacks", testAuthFallbacksBind) } func TestOne(t *testing.T) { - t.Run("Aliases", testAliasesOne) t.Run("AuthFallbacks", testAuthFallbacksOne) } func TestAll(t *testing.T) { - t.Run("Aliases", testAliasesAll) t.Run("AuthFallbacks", testAuthFallbacksAll) } func TestCount(t *testing.T) { - t.Run("Aliases", testAliasesCount) t.Run("AuthFallbacks", testAuthFallbacksCount) } func TestHooks(t *testing.T) { - t.Run("Aliases", testAliasesHooks) t.Run("AuthFallbacks", testAuthFallbacksHooks) } func TestInsert(t *testing.T) { - t.Run("Aliases", testAliasesInsert) - t.Run("Aliases", testAliasesInsertWhitelist) t.Run("AuthFallbacks", testAuthFallbacksInsert) t.Run("AuthFallbacks", testAuthFallbacksInsertWhitelist) } @@ -114,26 +101,21 @@ func TestToManySet(t *testing.T) {} func TestToManyRemove(t *testing.T) {} func TestReload(t *testing.T) { - t.Run("Aliases", testAliasesReload) t.Run("AuthFallbacks", testAuthFallbacksReload) } func TestReloadAll(t *testing.T) { - t.Run("Aliases", testAliasesReloadAll) t.Run("AuthFallbacks", testAuthFallbacksReloadAll) } func TestSelect(t *testing.T) { - t.Run("Aliases", testAliasesSelect) t.Run("AuthFallbacks", testAuthFallbacksSelect) } func TestUpdate(t *testing.T) { - t.Run("Aliases", testAliasesUpdate) t.Run("AuthFallbacks", testAuthFallbacksUpdate) } func TestSliceUpdateAll(t *testing.T) { - t.Run("Aliases", testAliasesSliceUpdateAll) t.Run("AuthFallbacks", testAuthFallbacksSliceUpdateAll) } diff --git a/admindb/sqlite/models/boil_table_names.go b/admindb/sqlite/models/boil_table_names.go index 66b3358..c33a3f1 100644 --- a/admindb/sqlite/models/boil_table_names.go +++ b/admindb/sqlite/models/boil_table_names.go @@ -4,9 +4,7 @@ package models var TableNames = struct { - Aliases string AuthFallback string }{ - Aliases: "aliases", AuthFallback: "auth_fallback", } diff --git a/admindb/sqlite/new.go b/admindb/sqlite/new.go index 9757fe4..85d4e66 100644 --- a/admindb/sqlite/new.go +++ b/admindb/sqlite/new.go @@ -5,8 +5,14 @@ package sqlite import ( "database/sql" "fmt" + "log" + "os" + "path/filepath" + + migrate "github.com/rubenv/sql-migrate" "github.com/ssb-ngi-pointer/gossb-rooms/admindb" + "github.com/ssb-ngi-pointer/gossb-rooms/internal/repo" ) type Database struct { @@ -20,14 +26,32 @@ type Database struct { } // Open looks for a database file 'fname' -func Open(fname string) (*Database, error) { +func Open(r repo.Interface) (*Database, error) { + fname := r.GetPath("roomdb") + + if dir := filepath.Dir(fname); dir != "" { + err := os.MkdirAll(dir, 0700) + if err != nil && !os.IsExist(err) { + return nil, fmt.Errorf("admindb: failed to create folder for database (%q): %w", dir, err) + } + } + db, err := sql.Open("sqlite3", fname) if err != nil { - return nil, fmt.Errorf("sqlite/open failed: %w", err) + return nil, fmt.Errorf("admindb: failed to open sqlite database: %w", err) } if err := db.Ping(); err != nil { - return nil, fmt.Errorf("sqlite/open: ping failed: %w", err) + return nil, fmt.Errorf("admindb: sqlite ping failed: %w", err) + } + + n, err := migrate.Exec(db, "sqlite3", migrationSource, migrate.Up) + if err != nil { + return nil, fmt.Errorf("admindb: failed to apply database mirations: %w", err) + } + if n > 0 { + // TODO: hook up logging + log.Printf("admindb: applied %d migrations", n) } admindb := &Database{ diff --git a/admindb/sqlite/new_test.go b/admindb/sqlite/new_test.go new file mode 100644 index 0000000..ef6becf --- /dev/null +++ b/admindb/sqlite/new_test.go @@ -0,0 +1,30 @@ +package sqlite + +import ( + "context" + "os" + "path/filepath" + "testing" + + _ "github.com/mattn/go-sqlite3" + "github.com/ssb-ngi-pointer/gossb-rooms/internal/repo" + "github.com/stretchr/testify/require" +) + +// verify the database opens and migrates successfully from zero state +func TestSimple(t *testing.T) { + testRepo := filepath.Join("testrun", t.Name()) + os.RemoveAll(testRepo) + + tr := repo.New(testRepo) + + db, err := Open(tr) + require.NoError(t, err) + + ctx := context.Background() + err = db.AuthFallback.Create(ctx, "testUser", []byte("super-cheesy-password-12345")) + require.NoError(t, err) + + err = db.Close() + require.NoError(t, err) +} diff --git a/admindb/sqlite/schema-v1.sql b/admindb/sqlite/schema-v1.sql index b29a05c..baebe4a 100644 --- a/admindb/sqlite/schema-v1.sql +++ b/admindb/sqlite/schema-v1.sql @@ -1,12 +1,5 @@ -- TODO: unify user table of auth_fallback and auth_signin_with_ssb -DROP TABLE IF EXISTS auth_fallback; -CREATE TABLE auth_fallback ( - id int PRIMARY KEY NOT NULL, - name text NOT NULL UNIQUE, - password_hash blob not null - -- pub_key text NOT NULL UNIQUE ???? -); DROP TABLE IF EXISTS aliases; CREATE TABLE aliases ( diff --git a/admindb/sqlite/sqlboiler.toml b/admindb/sqlite/sqlboiler.toml index 672bc51..063d305 100644 --- a/admindb/sqlite/sqlboiler.toml +++ b/admindb/sqlite/sqlboiler.toml @@ -1,6 +1,7 @@ [sqlite3] -dbname = "generated.db" - +# go test in the admindb/sqlite package will create this +dbname = "testrun/TestSimple/roomdb" +blacklist = ["gorp_migrations"] # TODO: fix unsupported type error # need to add https://pkg.go.dev/database/sql/driver#Valuer diff --git a/cmd/server/main.go b/cmd/server/main.go index ca4979d..30de7d5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -176,7 +176,8 @@ func runroomsrv() error { r := repo.New(repoDir) - db, err := sqlite.Open(r.GetPath("roomdb")) + // open the sqlite version of the admindb + db, err := sqlite.Open(r) if err != nil { return fmt.Errorf("failed to initiate database: %w", err) } diff --git a/go.mod b/go.mod index a82c0d6..a4eed3d 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/nicksnyder/go-i18n/v2 v2.1.2 github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 + github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 // indirect github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect github.com/spf13/afero v1.5.1 // indirect @@ -26,6 +27,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 + github.com/volatiletech/null/v8 v8.1.0 // indirect github.com/volatiletech/randomize v0.0.1 github.com/volatiletech/sqlboiler/v4 v4.4.0 github.com/volatiletech/strmangle v0.0.1 diff --git a/go.sum b/go.sum index 9ea6528..dd8f227 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ github.com/apmckinlay/gsuneido v0.0.0-20180907175622-1f10244968e3/go.mod h1:hJna github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -47,6 +48,7 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -63,12 +65,14 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -82,6 +86,8 @@ github.com/cryptix/golang_x_crypto v0.0.0-20200924101112-886946aabeb8/go.mod h1: github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE= github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.3.0/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.5.3/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= @@ -102,6 +108,7 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5/go.mod h1:1yj25TwtUlJ+pfOu9apAVaM1RWfZGg+aFpd4hPQZekQ= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= @@ -122,10 +129,19 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.7.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= +github.com/godror/godror v0.13.3 h1:4A5GLGAJTSuELw1NThqY5bINYB+mqrln+kF5C2vuyCs= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -133,6 +149,7 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -151,6 +168,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -213,6 +231,7 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -236,6 +255,7 @@ github.com/kevinburke/go-bindata v3.21.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -244,6 +264,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481 h1:r9fnMM01mkhtfe6QfLrr/90mBVLnJHge2jGeBvApOjk= github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -252,15 +274,23 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-oci8 v0.0.7 h1:BBXYpvzPO43QNTLDEivPFteeFZ9nKA6JQ6eifpxOmio= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miolini/datacounter v0.0.0-20171104152933-fd4e42a1d5e0/go.mod h1:P6fDJzlxN+cWYR09KbE9/ta+Y6JofX9tAUhJpWkWPaM= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -289,6 +319,9 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2 h1:sq53g+DWf0J6/ceFUHpQ0nAEb6WgM++fq16MZ91cS6o= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -320,6 +353,7 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -344,7 +378,13 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -376,6 +416,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -384,6 +425,7 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= @@ -406,6 +448,7 @@ github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJ github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20190126102652-8fd0f8d918c8/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -422,6 +465,7 @@ github.com/volatiletech/strmangle v0.0.1 h1:UKQoHmY6be/R3tSvD2nQYrH41k43OJkidwEi github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.cryptoscope.co/librarian v0.1.0/go.mod h1:dbua5pc7Vq/M0W5CJa/AJYdwlDRlgo2FKrB5tEm2NLc= go.cryptoscope.co/librarian v0.1.1/go.mod h1:cL2xGx4N+lZe6nbBS7vKPyy/rGn0uY2+hP/TwQf6+IM= go.cryptoscope.co/librarian v0.1.2/go.mod h1:U15yqN7eap9RDGqd/wlFUWoGWplXWn3VI3MGStrI3tA= @@ -525,6 +569,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -533,6 +578,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507053917-2953c62de483/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -570,6 +616,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -578,6 +625,7 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= @@ -591,6 +639,7 @@ google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -619,6 +668,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= @@ -630,6 +681,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=