diff options
| author | Alexander Kavon <me+git@alexkavon.com> | 2024-01-22 21:30:19 -0500 |
|---|---|---|
| committer | Alexander Kavon <me+git@alexkavon.com> | 2024-01-22 21:30:19 -0500 |
| commit | 0cdc7a2e84ac5c460569a26a1dd8e3070cea487e (patch) | |
| tree | dd1f1f67e9dad99b21fd4d2f817beb846e1fe611 | |
| parent | 481b799f9eced5432fdc0c66d2bf04226cdc723b (diff) | |
add posts table migration, add sqlboiler post model, post routes: create, store, get, post create ui template, remove email from user create route
| -rw-r--r-- | go.mod | 11 | ||||
| -rw-r--r-- | go.sum | 14 | ||||
| -rw-r--r-- | migrations/003_create_posts_table.sql.sql | 17 | ||||
| -rw-r--r-- | src/models/boil_suites_test.go | 18 | ||||
| -rw-r--r-- | src/models/boil_table_names.go | 2 | ||||
| -rw-r--r-- | src/models/posts.go | 1102 | ||||
| -rw-r--r-- | src/models/posts_test.go | 732 | ||||
| -rw-r--r-- | src/models/psql_suites_test.go | 2 | ||||
| -rw-r--r-- | src/models/users.go | 92 | ||||
| -rw-r--r-- | src/post/routes.go | 29 | ||||
| -rw-r--r-- | src/user/routes.go | 1 | ||||
| -rw-r--r-- | ui/pages/post/create.tmpl.html | 20 |
12 files changed, 1935 insertions, 105 deletions
@@ -6,12 +6,13 @@ require ( github.com/BurntSushi/toml v1.3.2 github.com/friendsofgo/errors v0.9.2 github.com/go-chi/chi/v5 v5.0.10 - github.com/go-playground/validator/v10 v10.16.0 + github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/google/uuid v1.4.0 github.com/jackc/pgx/v5 v5.5.0 github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12 github.com/lib/pq v1.10.6 github.com/spf13/viper v1.12.0 + github.com/volatiletech/null/v8 v8.1.2 github.com/volatiletech/randomize v0.0.1 github.com/volatiletech/sqlboiler/v4 v4.16.1 github.com/volatiletech/strmangle v0.0.6 @@ -19,18 +20,12 @@ require ( ) require ( - github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect - github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -39,9 +34,9 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.8.2 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/volatiletech/inflect v0.0.1 // indirect - golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -136,8 +136,6 @@ github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzj github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= -github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= @@ -152,14 +150,6 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= -github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -332,8 +322,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -593,8 +581,6 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/migrations/003_create_posts_table.sql.sql b/migrations/003_create_posts_table.sql.sql new file mode 100644 index 0000000..81dab8f --- /dev/null +++ b/migrations/003_create_posts_table.sql.sql @@ -0,0 +1,17 @@ +CREATE TABLE posts( + id SERIAL NOT NULL PRIMARY KEY, + title VARCHAR(100) NOT NULL, + description TEXT NOT NULL, + url VARCHAR(255) UNIQUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TRIGGER set_timestamp +BEFORE UPDATE ON posts +FOR EACH ROW +EXECUTE PROCEDURE trigger_set_timestamp(); + +---- create above / drop below ---- + +DROP TABLE posts; diff --git a/src/models/boil_suites_test.go b/src/models/boil_suites_test.go index a817084..d1e1758 100644 --- a/src/models/boil_suites_test.go +++ b/src/models/boil_suites_test.go @@ -12,70 +12,88 @@ 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("Posts", testPosts) t.Run("Users", testUsers) } func TestDelete(t *testing.T) { + t.Run("Posts", testPostsDelete) t.Run("Users", testUsersDelete) } func TestQueryDeleteAll(t *testing.T) { + t.Run("Posts", testPostsQueryDeleteAll) t.Run("Users", testUsersQueryDeleteAll) } func TestSliceDeleteAll(t *testing.T) { + t.Run("Posts", testPostsSliceDeleteAll) t.Run("Users", testUsersSliceDeleteAll) } func TestExists(t *testing.T) { + t.Run("Posts", testPostsExists) t.Run("Users", testUsersExists) } func TestFind(t *testing.T) { + t.Run("Posts", testPostsFind) t.Run("Users", testUsersFind) } func TestBind(t *testing.T) { + t.Run("Posts", testPostsBind) t.Run("Users", testUsersBind) } func TestOne(t *testing.T) { + t.Run("Posts", testPostsOne) t.Run("Users", testUsersOne) } func TestAll(t *testing.T) { + t.Run("Posts", testPostsAll) t.Run("Users", testUsersAll) } func TestCount(t *testing.T) { + t.Run("Posts", testPostsCount) t.Run("Users", testUsersCount) } func TestHooks(t *testing.T) { + t.Run("Posts", testPostsHooks) t.Run("Users", testUsersHooks) } func TestInsert(t *testing.T) { + t.Run("Posts", testPostsInsert) + t.Run("Posts", testPostsInsertWhitelist) t.Run("Users", testUsersInsert) t.Run("Users", testUsersInsertWhitelist) } func TestReload(t *testing.T) { + t.Run("Posts", testPostsReload) t.Run("Users", testUsersReload) } func TestReloadAll(t *testing.T) { + t.Run("Posts", testPostsReloadAll) t.Run("Users", testUsersReloadAll) } func TestSelect(t *testing.T) { + t.Run("Posts", testPostsSelect) t.Run("Users", testUsersSelect) } func TestUpdate(t *testing.T) { + t.Run("Posts", testPostsUpdate) t.Run("Users", testUsersUpdate) } func TestSliceUpdateAll(t *testing.T) { + t.Run("Posts", testPostsSliceUpdateAll) t.Run("Users", testUsersSliceUpdateAll) } diff --git a/src/models/boil_table_names.go b/src/models/boil_table_names.go index b98dc13..c88a449 100644 --- a/src/models/boil_table_names.go +++ b/src/models/boil_table_names.go @@ -4,7 +4,9 @@ package models var TableNames = struct { + Posts string Users string }{ + Posts: "posts", Users: "users", } diff --git a/src/models/posts.go b/src/models/posts.go new file mode 100644 index 0000000..d644268 --- /dev/null +++ b/src/models/posts.go @@ -0,0 +1,1102 @@ +// Code generated by SQLBoiler 4.16.1 (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" + "strconv" + "strings" + "sync" + "time" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/null/v8" + "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" +) + +// Post is an object representing the database table. +type Post struct { + ID int `boil:"id" json:"id" toml:"id" yaml:"id"` + Title string `boil:"title" json:"title" toml:"title" yaml:"title"` + URL null.String `boil:"url" json:"url,omitempty" toml:"url" yaml:"url,omitempty"` + Description string `boil:"description" json:"description" toml:"description" yaml:"description"` + 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 *postR `boil:"-" json:"-" toml:"-" yaml:"-"` + L postL `boil:"-" json:"-" toml:"-" yaml:"-"` +} + +var PostColumns = struct { + ID string + Title string + URL string + Description string + CreatedAt string + UpdatedAt string +}{ + ID: "id", + Title: "title", + URL: "url", + Description: "description", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +var PostTableColumns = struct { + ID string + Title string + URL string + Description string + CreatedAt string + UpdatedAt string +}{ + ID: "posts.id", + Title: "posts.title", + URL: "posts.url", + Description: "posts.description", + CreatedAt: "posts.created_at", + UpdatedAt: "posts.updated_at", +} + +// Generated where + +type whereHelperint struct{ field string } + +func (w whereHelperint) EQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } +func (w whereHelperint) NEQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } +func (w whereHelperint) LT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } +func (w whereHelperint) LTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } +func (w whereHelperint) GT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } +func (w whereHelperint) GTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } +func (w whereHelperint) IN(slice []int) 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 whereHelperint) NIN(slice []int) 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) LIKE(x string) qm.QueryMod { return qm.Where(w.field+" LIKE ?", x) } +func (w whereHelperstring) NLIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT LIKE ?", x) } +func (w whereHelperstring) ILIKE(x string) qm.QueryMod { return qm.Where(w.field+" ILIKE ?", x) } +func (w whereHelperstring) NILIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT ILIKE ?", 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 whereHelpernull_String struct{ field string } + +func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, false, x) +} +func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod { + return qmhelper.WhereNullEQ(w.field, true, x) +} +func (w whereHelpernull_String) LT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpernull_String) GT(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} +func (w whereHelpernull_String) LIKE(x null.String) qm.QueryMod { + return qm.Where(w.field+" LIKE ?", x) +} +func (w whereHelpernull_String) NLIKE(x null.String) qm.QueryMod { + return qm.Where(w.field+" NOT LIKE ?", x) +} +func (w whereHelpernull_String) ILIKE(x null.String) qm.QueryMod { + return qm.Where(w.field+" ILIKE ?", x) +} +func (w whereHelpernull_String) NILIKE(x null.String) qm.QueryMod { + return qm.Where(w.field+" NOT ILIKE ?", x) +} +func (w whereHelpernull_String) 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 whereHelpernull_String) 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...) +} + +func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) } +func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) } + +type whereHelpertime_Time struct{ field string } + +func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.EQ, x) +} +func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.NEQ, x) +} +func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + +var PostWhere = struct { + ID whereHelperint + Title whereHelperstring + URL whereHelpernull_String + Description whereHelperstring + CreatedAt whereHelpertime_Time + UpdatedAt whereHelpertime_Time +}{ + ID: whereHelperint{field: "\"posts\".\"id\""}, + Title: whereHelperstring{field: "\"posts\".\"title\""}, + URL: whereHelpernull_String{field: "\"posts\".\"url\""}, + Description: whereHelperstring{field: "\"posts\".\"description\""}, + CreatedAt: whereHelpertime_Time{field: "\"posts\".\"created_at\""}, + UpdatedAt: whereHelpertime_Time{field: "\"posts\".\"updated_at\""}, +} + +// PostRels is where relationship names are stored. +var PostRels = struct { +}{} + +// postR is where relationships are stored. +type postR struct { +} + +// NewStruct creates a new relationship struct +func (*postR) NewStruct() *postR { + return &postR{} +} + +// postL is where Load methods for each relationship are stored. +type postL struct{} + +var ( + postAllColumns = []string{"id", "title", "url", "description", "created_at", "updated_at"} + postColumnsWithoutDefault = []string{"title", "description"} + postColumnsWithDefault = []string{"id", "url", "created_at", "updated_at"} + postPrimaryKeyColumns = []string{"id"} + postGeneratedColumns = []string{} +) + +type ( + // PostSlice is an alias for a slice of pointers to Post. + // This should almost always be used instead of []Post. + PostSlice []*Post + // PostHook is the signature for custom Post hook methods + PostHook func(context.Context, boil.ContextExecutor, *Post) error + + postQuery struct { + *queries.Query + } +) + +// Cache for insert, update and upsert +var ( + postType = reflect.TypeOf(&Post{}) + postMapping = queries.MakeStructMapping(postType) + postPrimaryKeyMapping, _ = queries.BindMapping(postType, postMapping, postPrimaryKeyColumns) + postInsertCacheMut sync.RWMutex + postInsertCache = make(map[string]insertCache) + postUpdateCacheMut sync.RWMutex + postUpdateCache = make(map[string]updateCache) + postUpsertCacheMut sync.RWMutex + postUpsertCache = 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 postAfterSelectMu sync.Mutex +var postAfterSelectHooks []PostHook + +var postBeforeInsertMu sync.Mutex +var postBeforeInsertHooks []PostHook +var postAfterInsertMu sync.Mutex +var postAfterInsertHooks []PostHook + +var postBeforeUpdateMu sync.Mutex +var postBeforeUpdateHooks []PostHook +var postAfterUpdateMu sync.Mutex +var postAfterUpdateHooks []PostHook + +var postBeforeDeleteMu sync.Mutex +var postBeforeDeleteHooks []PostHook +var postAfterDeleteMu sync.Mutex +var postAfterDeleteHooks []PostHook + +var postBeforeUpsertMu sync.Mutex +var postBeforeUpsertHooks []PostHook +var postAfterUpsertMu sync.Mutex +var postAfterUpsertHooks []PostHook + +// doAfterSelectHooks executes all "after Select" hooks. +func (o *Post) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postAfterSelectHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeInsertHooks executes all "before insert" hooks. +func (o *Post) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postBeforeInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterInsertHooks executes all "after Insert" hooks. +func (o *Post) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postAfterInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpdateHooks executes all "before Update" hooks. +func (o *Post) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postBeforeUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpdateHooks executes all "after Update" hooks. +func (o *Post) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postAfterUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeDeleteHooks executes all "before Delete" hooks. +func (o *Post) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postBeforeDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterDeleteHooks executes all "after Delete" hooks. +func (o *Post) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postAfterDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpsertHooks executes all "before Upsert" hooks. +func (o *Post) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postBeforeUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpsertHooks executes all "after Upsert" hooks. +func (o *Post) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range postAfterUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// AddPostHook registers your hook function for all future operations. +func AddPostHook(hookPoint boil.HookPoint, postHook PostHook) { + switch hookPoint { + case boil.AfterSelectHook: + postAfterSelectMu.Lock() + postAfterSelectHooks = append(postAfterSelectHooks, postHook) + postAfterSelectMu.Unlock() + case boil.BeforeInsertHook: + postBeforeInsertMu.Lock() + postBeforeInsertHooks = append(postBeforeInsertHooks, postHook) + postBeforeInsertMu.Unlock() + case boil.AfterInsertHook: + postAfterInsertMu.Lock() + postAfterInsertHooks = append(postAfterInsertHooks, postHook) + postAfterInsertMu.Unlock() + case boil.BeforeUpdateHook: + postBeforeUpdateMu.Lock() + postBeforeUpdateHooks = append(postBeforeUpdateHooks, postHook) + postBeforeUpdateMu.Unlock() + case boil.AfterUpdateHook: + postAfterUpdateMu.Lock() + postAfterUpdateHooks = append(postAfterUpdateHooks, postHook) + postAfterUpdateMu.Unlock() + case boil.BeforeDeleteHook: + postBeforeDeleteMu.Lock() + postBeforeDeleteHooks = append(postBeforeDeleteHooks, postHook) + postBeforeDeleteMu.Unlock() + case boil.AfterDeleteHook: + postAfterDeleteMu.Lock() + postAfterDeleteHooks = append(postAfterDeleteHooks, postHook) + postAfterDeleteMu.Unlock() + case boil.BeforeUpsertHook: + postBeforeUpsertMu.Lock() + postBeforeUpsertHooks = append(postBeforeUpsertHooks, postHook) + postBeforeUpsertMu.Unlock() + case boil.AfterUpsertHook: + postAfterUpsertMu.Lock() + postAfterUpsertHooks = append(postAfterUpsertHooks, postHook) + postAfterUpsertMu.Unlock() + } +} + +// One returns a single post record from the query. +func (q postQuery) One(ctx context.Context, exec boil.ContextExecutor) (*Post, error) { + o := &Post{} + + queries.SetLimit(q.Query, 1) + + err := q.Bind(ctx, exec, o) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: failed to execute a one query for posts") + } + + if err := o.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + + return o, nil +} + +// All returns all Post records from the query. +func (q postQuery) All(ctx context.Context, exec boil.ContextExecutor) (PostSlice, error) { + var o []*Post + + err := q.Bind(ctx, exec, &o) + if err != nil { + return nil, errors.Wrap(err, "models: failed to assign all query results to Post slice") + } + + if len(postAfterSelectHooks) != 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 Post records in the query. +func (q postQuery) 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 posts rows") + } + + return count, nil +} + +// Exists checks if the row exists in the table. +func (q postQuery) 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 posts exists") + } + + return count > 0, nil +} + +// Posts retrieves all the records using an executor. +func Posts(mods ...qm.QueryMod) postQuery { + mods = append(mods, qm.From("\"posts\"")) + q := NewQuery(mods...) + if len(queries.GetSelect(q)) == 0 { + queries.SetSelect(q, []string{"\"posts\".*"}) + } + + return postQuery{q} +} + +// FindPost retrieves a single record by ID with an executor. +// If selectCols is empty Find will return all columns. +func FindPost(ctx context.Context, exec boil.ContextExecutor, iD int, selectCols ...string) (*Post, error) { + postObj := &Post{} + + sel := "*" + if len(selectCols) > 0 { + sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") + } + query := fmt.Sprintf( + "select %s from \"posts\" where \"id\"=$1", sel, + ) + + q := queries.Raw(query, iD) + + err := q.Bind(ctx, exec, postObj) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: unable to select from posts") + } + + if err = postObj.doAfterSelectHooks(ctx, exec); err != nil { + return postObj, err + } + + return postObj, nil +} + +// Insert a single record using an executor. +// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. +func (o *Post) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { + if o == nil { + return errors.New("models: no posts provided for insertion") + } + + var err error + if !boil.TimestampsAreSkipped(ctx) { + currTime := time.Now().In(boil.GetLocation()) + + if o.CreatedAt.IsZero() { + o.CreatedAt = currTime + } + if o.UpdatedAt.IsZero() { + o.UpdatedAt = currTime + } + } + + if err := o.doBeforeInsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(postColumnsWithDefault, o) + + key := makeCacheKey(columns, nzDefaults) + postInsertCacheMut.RLock() + cache, cached := postInsertCache[key] + postInsertCacheMut.RUnlock() + + if !cached { + wl, returnColumns := columns.InsertColumnSet( + postAllColumns, + postColumnsWithDefault, + postColumnsWithoutDefault, + nzDefaults, + ) + + cache.valueMapping, err = queries.BindMapping(postType, postMapping, wl) + if err != nil { + return err + } + cache.retMapping, err = queries.BindMapping(postType, postMapping, returnColumns) + if err != nil { + return err + } + if len(wl) != 0 { + cache.query = fmt.Sprintf("INSERT INTO \"posts\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) + } else { + cache.query = "INSERT INTO \"posts\" %sDEFAULT VALUES%s" + } + + var queryOutput, queryReturning string + + if len(cache.retMapping) != 0 { + queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\"")) + } + + 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) + } + + if len(cache.retMapping) != 0 { + err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) + } else { + _, err = exec.ExecContext(ctx, cache.query, vals...) + } + + if err != nil { + return errors.Wrap(err, "models: unable to insert into posts") + } + + if !cached { + postInsertCacheMut.Lock() + postInsertCache[key] = cache + postInsertCacheMut.Unlock() + } + + return o.doAfterInsertHooks(ctx, exec) +} + +// Update uses an executor to update the Post. +// 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 *Post) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { + if !boil.TimestampsAreSkipped(ctx) { + currTime := time.Now().In(boil.GetLocation()) + + o.UpdatedAt = currTime + } + + var err error + if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { + return 0, err + } + key := makeCacheKey(columns, nil) + postUpdateCacheMut.RLock() + cache, cached := postUpdateCache[key] + postUpdateCacheMut.RUnlock() + + if !cached { + wl := columns.UpdateColumnSet( + postAllColumns, + postPrimaryKeyColumns, + ) + + if !columns.IsWhitelist() { + wl = strmangle.SetComplement(wl, []string{"created_at"}) + } + if len(wl) == 0 { + return 0, errors.New("models: unable to update posts, could not build whitelist") + } + + cache.query = fmt.Sprintf("UPDATE \"posts\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, wl), + strmangle.WhereClause("\"", "\"", len(wl)+1, postPrimaryKeyColumns), + ) + cache.valueMapping, err = queries.BindMapping(postType, postMapping, append(wl, postPrimaryKeyColumns...)) + 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 posts row") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by update for posts") + } + + if !cached { + postUpdateCacheMut.Lock() + postUpdateCache[key] = cache + postUpdateCacheMut.Unlock() + } + + return rowsAff, o.doAfterUpdateHooks(ctx, exec) +} + +// UpdateAll updates all rows with the specified column values. +func (q postQuery) 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 posts") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected for posts") + } + + return rowsAff, nil +} + +// UpdateAll updates all rows with the specified column values, using an executor. +func (o PostSlice) 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)), postPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := fmt.Sprintf("UPDATE \"posts\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, colNames), + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, postPrimaryKeyColumns, 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 post slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all post") + } + return rowsAff, nil +} + +// Upsert attempts an insert using an executor, and does an update or ignore on conflict. +// See boil.Columns documentation for how to properly use updateColumns and insertColumns. +func (o *Post) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error { + if o == nil { + return errors.New("models: no posts provided for upsert") + } + if !boil.TimestampsAreSkipped(ctx) { + currTime := time.Now().In(boil.GetLocation()) + + if o.CreatedAt.IsZero() { + o.CreatedAt = currTime + } + o.UpdatedAt = currTime + } + + if err := o.doBeforeUpsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(postColumnsWithDefault, o) + + // Build cache key in-line uglily - mysql vs psql problems + buf := strmangle.GetBuffer() + if updateOnConflict { + buf.WriteByte('t') + } else { + buf.WriteByte('f') + } + buf.WriteByte('.') + for _, c := range conflictColumns { + buf.WriteString(c) + } + buf.WriteByte('.') + buf.WriteString(strconv.Itoa(updateColumns.Kind)) + for _, c := range updateColumns.Cols { + buf.WriteString(c) + } + buf.WriteByte('.') + buf.WriteString(strconv.Itoa(insertColumns.Kind)) + for _, c := range insertColumns.Cols { + buf.WriteString(c) + } + buf.WriteByte('.') + for _, c := range nzDefaults { + buf.WriteString(c) + } + key := buf.String() + strmangle.PutBuffer(buf) + + postUpsertCacheMut.RLock() + cache, cached := postUpsertCache[key] + postUpsertCacheMut.RUnlock() + + var err error + + if !cached { + insert, _ := insertColumns.InsertColumnSet( + postAllColumns, + postColumnsWithDefault, + postColumnsWithoutDefault, + nzDefaults, + ) + + update := updateColumns.UpdateColumnSet( + postAllColumns, + postPrimaryKeyColumns, + ) + + if updateOnConflict && len(update) == 0 { + return errors.New("models: unable to upsert posts, could not build update column list") + } + + ret := strmangle.SetComplement(postAllColumns, strmangle.SetIntersect(insert, update)) + + conflict := conflictColumns + if len(conflict) == 0 && updateOnConflict && len(update) != 0 { + if len(postPrimaryKeyColumns) == 0 { + return errors.New("models: unable to upsert posts, could not build conflict column list") + } + + conflict = make([]string, len(postPrimaryKeyColumns)) + copy(conflict, postPrimaryKeyColumns) + } + cache.query = buildUpsertQueryPostgres(dialect, "\"posts\"", updateOnConflict, ret, update, conflict, insert, opts...) + + cache.valueMapping, err = queries.BindMapping(postType, postMapping, insert) + if err != nil { + return err + } + if len(ret) != 0 { + cache.retMapping, err = queries.BindMapping(postType, postMapping, ret) + if err != nil { + return err + } + } + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + var returns []interface{} + if len(cache.retMapping) != 0 { + returns = queries.PtrsFromMapping(value, cache.retMapping) + } + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, vals) + } + if len(cache.retMapping) != 0 { + err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...) + if errors.Is(err, sql.ErrNoRows) { + err = nil // Postgres doesn't return anything when there's no update + } + } else { + _, err = exec.ExecContext(ctx, cache.query, vals...) + } + if err != nil { + return errors.Wrap(err, "models: unable to upsert posts") + } + + if !cached { + postUpsertCacheMut.Lock() + postUpsertCache[key] = cache + postUpsertCacheMut.Unlock() + } + + return o.doAfterUpsertHooks(ctx, exec) +} + +// Delete deletes a single Post record with an executor. +// Delete will match against the primary key column to find the record to delete. +func (o *Post) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if o == nil { + return 0, errors.New("models: no Post provided for delete") + } + + if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), postPrimaryKeyMapping) + sql := "DELETE FROM \"posts\" WHERE \"id\"=$1" + + 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 posts") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by delete for posts") + } + + if err := o.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + return rowsAff, nil +} + +// DeleteAll deletes all matching rows. +func (q postQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if q.Query == nil { + return 0, errors.New("models: no postQuery 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 posts") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for posts") + } + + return rowsAff, nil +} + +// DeleteAll deletes all rows in the slice, using an executor. +func (o PostSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if len(o) == 0 { + return 0, nil + } + + if len(postBeforeDeleteHooks) != 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)), postPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "DELETE FROM \"posts\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, postPrimaryKeyColumns, 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 post slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for posts") + } + + if len(postAfterDeleteHooks) != 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 *Post) Reload(ctx context.Context, exec boil.ContextExecutor) error { + ret, err := FindPost(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 *PostSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { + if o == nil || len(*o) == 0 { + return nil + } + + slice := PostSlice{} + var args []interface{} + for _, obj := range *o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), postPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "SELECT \"posts\".* FROM \"posts\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, postPrimaryKeyColumns, 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 PostSlice") + } + + *o = slice + + return nil +} + +// PostExists checks if the Post row exists. +func PostExists(ctx context.Context, exec boil.ContextExecutor, iD int) (bool, error) { + var exists bool + sql := "select exists(select 1 from \"posts\" where \"id\"=$1 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 posts exists") + } + + return exists, nil +} + +// Exists checks if the Post row exists. +func (o *Post) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { + return PostExists(ctx, exec, o.ID) +} diff --git a/src/models/posts_test.go b/src/models/posts_test.go new file mode 100644 index 0000000..0df4258 --- /dev/null +++ b/src/models/posts_test.go @@ -0,0 +1,732 @@ +// Code generated by SQLBoiler 4.16.1 (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 testPosts(t *testing.T) { + t.Parallel() + + query := Posts() + + if query.Query == nil { + t.Error("expected a query, got nothing") + } +} + +func testPostsDelete(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testPostsQueryDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().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 := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testPostsSliceDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := PostSlice{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 := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testPostsExists(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := PostExists(ctx, tx, o.ID) + if err != nil { + t.Errorf("Unable to check if Post exists: %s", err) + } + if !e { + t.Errorf("Expected PostExists to return true, but got false.") + } +} + +func testPostsFind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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) + } + + postFound, err := FindPost(ctx, tx, o.ID) + if err != nil { + t.Error(err) + } + + if postFound == nil { + t.Error("want a record, got nil") + } +} + +func testPostsBind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 = Posts().Bind(ctx, tx, o); err != nil { + t.Error(err) + } +} + +func testPostsOne(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().One(ctx, tx); err != nil { + t.Error(err) + } else if x == nil { + t.Error("expected to get a non nil record") + } +} + +func testPostsAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + postOne := &Post{} + postTwo := &Post{} + if err = randomize.Struct(seed, postOne, postDBTypes, false, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + if err = randomize.Struct(seed, postTwo, postDBTypes, false, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = postOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = postTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := Posts().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 2 { + t.Error("want 2 records, got:", len(slice)) + } +} + +func testPostsCount(t *testing.T) { + t.Parallel() + + var err error + seed := randomize.NewSeed() + postOne := &Post{} + postTwo := &Post{} + if err = randomize.Struct(seed, postOne, postDBTypes, false, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + if err = randomize.Struct(seed, postTwo, postDBTypes, false, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = postOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = postTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 2 { + t.Error("want 2 records, got:", count) + } +} + +func postBeforeInsertHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postAfterInsertHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postAfterSelectHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postBeforeUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postAfterUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postBeforeDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postAfterDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postBeforeUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func postAfterUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Post) error { + *o = Post{} + return nil +} + +func testPostsHooks(t *testing.T) { + t.Parallel() + + var err error + + ctx := context.Background() + empty := &Post{} + o := &Post{} + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, o, postDBTypes, false); err != nil { + t.Errorf("Unable to randomize Post object: %s", err) + } + + AddPostHook(boil.BeforeInsertHook, postBeforeInsertHook) + 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) + } + postBeforeInsertHooks = []PostHook{} + + AddPostHook(boil.AfterInsertHook, postAfterInsertHook) + 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) + } + postAfterInsertHooks = []PostHook{} + + AddPostHook(boil.AfterSelectHook, postAfterSelectHook) + 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) + } + postAfterSelectHooks = []PostHook{} + + AddPostHook(boil.BeforeUpdateHook, postBeforeUpdateHook) + 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) + } + postBeforeUpdateHooks = []PostHook{} + + AddPostHook(boil.AfterUpdateHook, postAfterUpdateHook) + 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) + } + postAfterUpdateHooks = []PostHook{} + + AddPostHook(boil.BeforeDeleteHook, postBeforeDeleteHook) + 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) + } + postBeforeDeleteHooks = []PostHook{} + + AddPostHook(boil.AfterDeleteHook, postAfterDeleteHook) + 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) + } + postAfterDeleteHooks = []PostHook{} + + AddPostHook(boil.BeforeUpsertHook, postBeforeUpsertHook) + 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) + } + postBeforeUpsertHooks = []PostHook{} + + AddPostHook(boil.AfterUpsertHook, postAfterUpsertHook) + 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) + } + postAfterUpsertHooks = []PostHook{} +} + +func testPostsInsert(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testPostsInsertWhitelist(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Whitelist(postColumnsWithoutDefault...)); err != nil { + t.Error(err) + } + + count, err := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testPostsReload(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 testPostsReloadAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := PostSlice{o} + + if err = slice.ReloadAll(ctx, tx); err != nil { + t.Error(err) + } +} + +func testPostsSelect(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 1 { + t.Error("want one record, got:", len(slice)) + } +} + +var ( + postDBTypes = map[string]string{`ID`: `integer`, `Title`: `character varying`, `URL`: `character varying`, `Description`: `text`, `CreatedAt`: `timestamp with time zone`, `UpdatedAt`: `timestamp with time zone`} + _ = bytes.MinRead +) + +func testPostsUpdate(t *testing.T) { + t.Parallel() + + if 0 == len(postPrimaryKeyColumns) { + t.Skip("Skipping table with no primary key columns") + } + if len(postAllColumns) == len(postPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().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, postDBTypes, true, postPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize Post 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 testPostsSliceUpdateAll(t *testing.T) { + t.Parallel() + + if len(postAllColumns) == len(postPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &Post{} + if err = randomize.Struct(seed, o, postDBTypes, true, postColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Post 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 := Posts().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, postDBTypes, true, postPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + // Remove Primary keys and unique columns from what we plan to update + var fields []string + if strmangle.StringSliceMatch(postAllColumns, postPrimaryKeyColumns) { + fields = postAllColumns + } else { + fields = strmangle.SetComplement( + postAllColumns, + postPrimaryKeyColumns, + ) + } + + 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 := PostSlice{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) + } +} + +func testPostsUpsert(t *testing.T) { + t.Parallel() + + if len(postAllColumns) == len(postPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + // Attempt the INSERT side of an UPSERT + o := Post{} + if err = randomize.Struct(seed, &o, postDBTypes, true); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Upsert(ctx, tx, false, nil, boil.Infer(), boil.Infer()); err != nil { + t.Errorf("Unable to upsert Post: %s", err) + } + + count, err := Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 1 { + t.Error("want one record, got:", count) + } + + // Attempt the UPDATE side of an UPSERT + if err = randomize.Struct(seed, &o, postDBTypes, false, postPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize Post struct: %s", err) + } + + if err = o.Upsert(ctx, tx, true, nil, boil.Infer(), boil.Infer()); err != nil { + t.Errorf("Unable to upsert Post: %s", err) + } + + count, err = Posts().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 1 { + t.Error("want one record, got:", count) + } +} diff --git a/src/models/psql_suites_test.go b/src/models/psql_suites_test.go index 9b30f06..c552b41 100644 --- a/src/models/psql_suites_test.go +++ b/src/models/psql_suites_test.go @@ -6,5 +6,7 @@ package models import "testing" func TestUpsert(t *testing.T) { + t.Run("Posts", testPostsUpsert) + t.Run("Users", testUsersUpsert) } diff --git a/src/models/users.go b/src/models/users.go index 666247a..ca9bcf8 100644 --- a/src/models/users.go +++ b/src/models/users.go @@ -14,6 +14,7 @@ import ( "time" "github.com/friendsofgo/errors" + "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/queries" "github.com/volatiletech/sqlboiler/v4/queries/qm" @@ -23,12 +24,12 @@ import ( // User is an object representing the database table. type User struct { - ID int `boil:"id" json:"id" toml:"id" yaml:"id"` - Username string `boil:"username" json:"username" toml:"username" yaml:"username"` - Secret string `boil:"secret" json:"secret" toml:"secret" yaml:"secret"` - Email string `boil:"email" json:"email" toml:"email" yaml:"email"` - 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"` + ID int `boil:"id" json:"id" toml:"id" yaml:"id"` + Username string `boil:"username" json:"username" toml:"username" yaml:"username"` + Secret string `boil:"secret" json:"secret" toml:"secret" yaml:"secret"` + Email null.String `boil:"email" json:"email,omitempty" toml:"email" yaml:"email,omitempty"` + 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:"-"` @@ -68,89 +69,18 @@ var UserTableColumns = struct { // Generated where -type whereHelperint struct{ field string } - -func (w whereHelperint) EQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } -func (w whereHelperint) NEQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } -func (w whereHelperint) LT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } -func (w whereHelperint) LTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } -func (w whereHelperint) GT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } -func (w whereHelperint) GTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } -func (w whereHelperint) IN(slice []int) 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 whereHelperint) NIN(slice []int) 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) LIKE(x string) qm.QueryMod { return qm.Where(w.field+" LIKE ?", x) } -func (w whereHelperstring) NLIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT LIKE ?", x) } -func (w whereHelperstring) ILIKE(x string) qm.QueryMod { return qm.Where(w.field+" ILIKE ?", x) } -func (w whereHelperstring) NILIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT ILIKE ?", 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 whereHelpertime_Time struct{ field string } - -func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.EQ, x) -} -func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.NEQ, x) -} -func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LT, x) -} -func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LTE, x) -} -func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GT, x) -} -func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GTE, x) -} - var UserWhere = struct { ID whereHelperint Username whereHelperstring Secret whereHelperstring - Email whereHelperstring + Email whereHelpernull_String CreatedAt whereHelpertime_Time UpdatedAt whereHelpertime_Time }{ ID: whereHelperint{field: "\"users\".\"id\""}, Username: whereHelperstring{field: "\"users\".\"username\""}, Secret: whereHelperstring{field: "\"users\".\"secret\""}, - Email: whereHelperstring{field: "\"users\".\"email\""}, + Email: whereHelpernull_String{field: "\"users\".\"email\""}, CreatedAt: whereHelpertime_Time{field: "\"users\".\"created_at\""}, UpdatedAt: whereHelpertime_Time{field: "\"users\".\"updated_at\""}, } @@ -173,8 +103,8 @@ type userL struct{} var ( userAllColumns = []string{"id", "username", "secret", "email", "created_at", "updated_at"} - userColumnsWithoutDefault = []string{"username", "secret", "email"} - userColumnsWithDefault = []string{"id", "created_at", "updated_at"} + userColumnsWithoutDefault = []string{"username", "secret"} + userColumnsWithDefault = []string{"id", "email", "created_at", "updated_at"} userPrimaryKeyColumns = []string{"id"} userGeneratedColumns = []string{} ) diff --git a/src/post/routes.go b/src/post/routes.go index 9932004..09457d3 100644 --- a/src/post/routes.go +++ b/src/post/routes.go @@ -1,10 +1,13 @@ package post import ( + "fmt" "log" "net/http" - "github.com/volatiletech/sqlboiler/boil" + "github.com/go-chi/chi/v5" + "github.com/volatiletech/sqlboiler/v4/boil" + "gitlab.com/alexkavon/newsstand/src/models" "gitlab.com/alexkavon/newsstand/src/server" "gitlab.com/alexkavon/newsstand/src/sessions" ) @@ -17,6 +20,19 @@ var Routes = server.Routes{ HandlerFunc: Create, Middlewares: server.NewMiddlewares(sessions.AuthSession), }, + server.Route{ + Name: "Store", + Method: "POST", + Path: "/p", + HandlerFunc: Store, + Middlewares: server.NewMiddlewares(sessions.AuthSession), + }, + server.Route{ + Name: "Get", + Method: "GET", + Path: "/p/{:id}", + HandlerFunc: Get, + }, } func Create(s *server.Server) http.HandlerFunc { @@ -32,12 +48,23 @@ func Store(s *server.Server) http.HandlerFunc { post.Url = r.PostFormValue("url") post.Description = r.PostFormValue("description") + // validate post + // process post, look for spamminess, bad url + // match post title with url title if provided + // check title for tags: Ask NY, subway, crime, culture err := post.Insert(r.Context(), s.Db.ToSqlDb(), boil.Infer()) if err != nil { log.Fatal("Insert Error", err) } // increment user points maybe + // redirect to new post + http.Redirect(w, r, fmt.Sprintf("p/%d", post.ID), http.StatusSeeOther) + } +} +func Get(s *server.Server) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + post := models.FindPost(r.Context(), s.Db.ToSqlDb(), chi.URLParam(r, "id")) } } diff --git a/src/user/routes.go b/src/user/routes.go index 0ac3e54..862545a 100644 --- a/src/user/routes.go +++ b/src/user/routes.go @@ -66,7 +66,6 @@ func Store(s *server.Server) http.HandlerFunc { var user models.User user.Username = r.PostFormValue("username") user.Secret = r.PostFormValue("secret") - user.Email = r.PostFormValue("email") // Store user, this package (user) will init // a validation hook to check values and hash secret diff --git a/ui/pages/post/create.tmpl.html b/ui/pages/post/create.tmpl.html new file mode 100644 index 0000000..385ed22 --- /dev/null +++ b/ui/pages/post/create.tmpl.html @@ -0,0 +1,20 @@ +{{define "title"}}Create Post{{end}} + +{{define "main"}} + <h1>Whatcha Got?</h1> + <form action="/p" method="POST"> + <label> + Title + <input type="text" placeholder="NYC Voted Best Place to Live By NYers" name="title" /> + <span>Title will be automatically pulled from URL if not provided.</span> + </label> + <label> + Description + <textarea placeholder="Spit it out already." name="description"></textarea> + </label> + <label> + URL + <input type="url" placeholder="https://cheesy.pizza/01/01/1970/first-post" name="url" /> + <button type="submit">Yup</button> + </form> +{{end}} |
