aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Kavon <me+git@alexkavon.com>2024-01-22 21:30:19 -0500
committerAlexander Kavon <me+git@alexkavon.com>2024-01-22 21:30:19 -0500
commit0cdc7a2e84ac5c460569a26a1dd8e3070cea487e (patch)
treedd1f1f67e9dad99b21fd4d2f817beb846e1fe611
parent481b799f9eced5432fdc0c66d2bf04226cdc723b (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.mod11
-rw-r--r--go.sum14
-rw-r--r--migrations/003_create_posts_table.sql.sql17
-rw-r--r--src/models/boil_suites_test.go18
-rw-r--r--src/models/boil_table_names.go2
-rw-r--r--src/models/posts.go1102
-rw-r--r--src/models/posts_test.go732
-rw-r--r--src/models/psql_suites_test.go2
-rw-r--r--src/models/users.go92
-rw-r--r--src/post/routes.go29
-rw-r--r--src/user/routes.go1
-rw-r--r--ui/pages/post/create.tmpl.html20
12 files changed, 1935 insertions, 105 deletions
diff --git a/go.mod b/go.mod
index df22072..f23933d 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 1d3fb6a..82d2afc 100644
--- a/go.sum
+++ b/go.sum
@@ -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}}