diff --git a/app/http/posts.go b/app/http/posts.go new file mode 100644 index 0000000..177e39b --- /dev/null +++ b/app/http/posts.go @@ -0,0 +1,28 @@ +package http + +import ( + "quyun/app/models" + "quyun/app/requests" + "quyun/database/schemas/public/model" + + "github.com/gofiber/fiber/v3" +) + +// @provider +type posts struct{} + +// List posts +// @Router /v1/medias [get] +// @Bind pagination query +// @bind key query +func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, key *string) (*requests.Pager, error) { + cond := models.Posts.BuildConditionWithKey(key) + return models.Posts.List(ctx.Context(), pagination, cond) +} + +// Show +// @Router /v1/medias/:id [get] +// @Bind id path +func (ctl *posts) Show(ctx fiber.Ctx, id int64) (*model.Posts, error) { + return models.Posts.GetByID(ctx.Context(), id) +} diff --git a/app/models/models.gen.go b/app/models/models.gen.go index 688ba4d..f317c78 100644 --- a/app/models/models.gen.go +++ b/app/models/models.gen.go @@ -10,17 +10,20 @@ import ( var db *sql.DB var Medias *mediasModel var Posts *postsModel +var Users *usersModel // @provider(model) type models struct { db *sql.DB medias *mediasModel posts *postsModel + users *usersModel } func (m *models) Prepare() error { db = m.db Medias = m.medias Posts = m.posts + Users = m.users return nil } diff --git a/app/models/posts.go b/app/models/posts.go index c7117cc..11ee502 100644 --- a/app/models/posts.go +++ b/app/models/posts.go @@ -1,8 +1,149 @@ package models +import ( + "context" + + "quyun/app/requests" + "quyun/database/fields" + "quyun/database/schemas/public/model" + "quyun/database/schemas/public/table" + + . "github.com/go-jet/jet/v2/postgres" + "github.com/sirupsen/logrus" +) + // @provider -type postsModel struct{} +type postsModel struct { + log *logrus.Entry `inject:"false"` +} func (m *postsModel) Prepare() error { + m.log = logrus.WithField("model", "postsModel") return nil } + +// BuildConditionWithKey +func (m *postsModel) BuildConditionWithKey(key *string) BoolExpression { + tbl := table.Posts + + cond := tbl.DeletedAt.IS_NULL().AND( + tbl.Status.EQ(Int32(int32(fields.PostStatusPublished))), + ) + + if key == nil || *key == "" { + return cond + } + + cond = tbl.Title.LIKE(String("%" + *key + "%")). + OR( + tbl.Content.LIKE(String("%" + *key + "%")), + ). + OR( + tbl.Description.LIKE(String("%" + *key + "%")), + ) + + return cond +} + +// GetByID +func (m *postsModel) GetByID(ctx context.Context, id int64) (*model.Posts, error) { + tbl := table.Posts + stmt := tbl. + SELECT(tbl.AllColumns). + WHERE( + tbl.ID.EQ(Int64(id)).AND( + tbl.DeletedAt.IS_NULL(), + ).AND( + tbl.Status.EQ(Int32(int32(fields.PostStatusPublished))), + ), + ) + m.log.Infof("sql: %s", stmt.DebugSql()) + + var post model.Posts + err := stmt.QueryContext(ctx, db, &post) + if err != nil { + m.log.Errorf("error getting post: %v", err) + return nil, err + } + return &post, nil +} + +// Create +func (m *postsModel) Create(ctx context.Context, model *model.Posts) error { + tbl := table.Posts + stmt := tbl.INSERT(tbl.MutableColumns).MODEL(model) + m.log.Infof("sql: %s", stmt.DebugSql()) + + _, err := stmt.ExecContext(ctx, db) + if err != nil { + m.log.Errorf("error creating post: %v", err) + return err + } + return nil +} + +// Update +func (m *postsModel) Update(ctx context.Context, id int64, model *model.Posts) error { + tbl := table.Posts + stmt := tbl.UPDATE(tbl.MutableColumns).SET(model).WHERE(tbl.ID.EQ(Int64(id))) + m.log.Infof("sql: %s", stmt.DebugSql()) + + _, err := stmt.ExecContext(ctx, db) + if err != nil { + m.log.Errorf("error updating post: %v", err) + return err + } + return nil +} + +// countByCond +func (m *postsModel) countByCondition(ctx context.Context, expr BoolExpression) (int64, error) { + var cnt struct { + Cnt int64 + } + + tbl := table.Posts + stmt := SELECT(COUNT(tbl.ID).AS("cnt")).FROM(tbl).WHERE(expr) + m.log.Infof("sql: %s", stmt.DebugSql()) + + err := stmt.QueryContext(ctx, db, &cnt) + if err != nil { + m.log.Errorf("error counting post items: %v", err) + return 0, err + } + + return cnt.Cnt, nil +} + +func (m *postsModel) List(ctx context.Context, pagination *requests.Pagination, cond BoolExpression) (*requests.Pager, error) { + limit := pagination.Limit + offset := pagination.Offset() + + tbl := table.Posts + stmt := tbl. + SELECT(tbl.AllColumns). + WHERE(cond). + ORDER_BY(tbl.ID.DESC()). + LIMIT(limit). + OFFSET(offset) + m.log.Infof("sql: %s", stmt.DebugSql()) + + var posts []model.Posts + err := stmt.QueryContext(ctx, db, &posts) + if err != nil { + m.log.Errorf("error querying post items: %v", err) + return nil, err + } + + count, err := m.countByCondition(ctx, cond) + if err != nil { + m.log.Errorf("error getting post count: %v", err) + return nil, err + } + + return &requests.Pager{ + Items: posts, + Total: count, + Pagination: *pagination, + }, nil +} diff --git a/app/models/posts_test.go b/app/models/posts_test.go new file mode 100644 index 0000000..331efee --- /dev/null +++ b/app/models/posts_test.go @@ -0,0 +1,43 @@ +package models + +import ( + "context" + "testing" + + "quyun/app/service/testx" + "quyun/database" + "quyun/database/schemas/public/table" + + . "github.com/smartystreets/goconvey/convey" + "go.ipao.vip/atom/contracts" + + // . "github.com/go-jet/jet/v2/postgres" + "github.com/stretchr/testify/suite" + "go.uber.org/dig" +) + +type PostsInjectParams struct { + dig.In + Initials []contracts.Initial `group:"initials"` +} + +type PostsTestSuite struct { + suite.Suite + + PostsInjectParams +} + +func Test_Posts(t *testing.T) { + providers := testx.Default().With(Provide) + testx.Serve(providers, t, func(params PostsInjectParams) { + suite.Run(t, &PostsTestSuite{ + PostsInjectParams: params, + }) + }) +} + +func (s *PostsTestSuite) Test_Demo() { + Convey("Test_Demo", s.T(), func() { + database.Truncate(context.Background(), db, table.Posts.TableName()) + }) +} diff --git a/app/models/users.go b/app/models/users.go new file mode 100644 index 0000000..4f5d6d4 --- /dev/null +++ b/app/models/users.go @@ -0,0 +1,15 @@ +package models + +import ( + "github.com/sirupsen/logrus" +) + +// @provider +type usersModel struct { + log *logrus.Entry `inject:"false"` +} + +func (m *usersModel) Prepare() error { + m.log = logrus.WithField("model", "usersModel") + return nil +} diff --git a/app/models/users_test.go b/app/models/users_test.go new file mode 100644 index 0000000..5dcf488 --- /dev/null +++ b/app/models/users_test.go @@ -0,0 +1,43 @@ +package models + +import ( + "context" + "testing" + + "quyun/app/service/testx" + "quyun/database" + "quyun/database/schemas/public/table" + + . "github.com/smartystreets/goconvey/convey" + "go.ipao.vip/atom/contracts" + + // . "github.com/go-jet/jet/v2/postgres" + "github.com/stretchr/testify/suite" + "go.uber.org/dig" +) + +type UsersInjectParams struct { + dig.In + Initials []contracts.Initial `group:"initials"` +} + +type UsersTestSuite struct { + suite.Suite + + UsersInjectParams +} + +func Test_Users(t *testing.T) { + providers := testx.Default().With(Provide) + testx.Serve(providers, t, func(params UsersInjectParams) { + suite.Run(t, &UsersTestSuite{ + UsersInjectParams: params, + }) + }) +} + +func (s *UsersTestSuite) Test_Demo() { + Convey("Test_Demo", s.T(), func() { + database.Truncate(context.Background(), db, table.Users.TableName()) + }) +} diff --git a/database/migrations/20250322103119_create_users.sql b/database/migrations/20250322103119_create_users.sql new file mode 100644 index 0000000..c22e30c --- /dev/null +++ b/database/migrations/20250322103119_create_users.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE users( + id SERIAL8 PRIMARY KEY, + created_at timestamp NOT NULL DEFAULT now(), + updated_at timestamp NOT NULL DEFAULT now(), + deleted_at timestamp, + status int2 NOT NULL DEFAULT 0, + open_id varchar(128) NOT NULL UNIQUE, + username varchar(128) NOT NULL, + avatar varchar(128) +); + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +DROP TABLE users; + +-- +goose StatementEnd diff --git a/database/migrations/20250322103243_create_user_posts.sql b/database/migrations/20250322103243_create_user_posts.sql new file mode 100644 index 0000000..550df00 --- /dev/null +++ b/database/migrations/20250322103243_create_user_posts.sql @@ -0,0 +1,18 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE user_posts( + id SERIAL8 PRIMARY KEY, + created_at timestamp NOT NULL DEFAULT now(), + updated_at timestamp NOT NULL DEFAULT now(), + -- + user_id int8 NOT NULL, + post_id int8 NOT NULL, + price int8 NOT NULL +); + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +DROP TABLE user_posts; + +-- +goose StatementEnd diff --git a/database/schemas/public/model/user_posts.go b/database/schemas/public/model/user_posts.go new file mode 100644 index 0000000..4014648 --- /dev/null +++ b/database/schemas/public/model/user_posts.go @@ -0,0 +1,21 @@ +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package model + +import ( + "time" +) + +type UserPosts struct { + ID int64 `sql:"primary_key" json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + UserID int64 `json:"user_id"` + PostID int64 `json:"post_id"` + Price int64 `json:"price"` +} diff --git a/database/schemas/public/model/users.go b/database/schemas/public/model/users.go new file mode 100644 index 0000000..ef4f2c0 --- /dev/null +++ b/database/schemas/public/model/users.go @@ -0,0 +1,23 @@ +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package model + +import ( + "time" +) + +type Users struct { + ID int64 `sql:"primary_key" json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt *time.Time `json:"deleted_at"` + Status int16 `json:"status"` + OpenID string `json:"open_id"` + Username string `json:"username"` + Avatar *string `json:"avatar"` +} diff --git a/database/schemas/public/table/table_use_schema.go b/database/schemas/public/table/table_use_schema.go index ff5c9d5..ab5c81a 100644 --- a/database/schemas/public/table/table_use_schema.go +++ b/database/schemas/public/table/table_use_schema.go @@ -13,4 +13,6 @@ func UseSchema(schema string) { Medias = Medias.FromSchema(schema) Migrations = Migrations.FromSchema(schema) Posts = Posts.FromSchema(schema) + UserPosts = UserPosts.FromSchema(schema) + Users = Users.FromSchema(schema) } diff --git a/database/schemas/public/table/user_posts.go b/database/schemas/public/table/user_posts.go new file mode 100644 index 0000000..baa79ec --- /dev/null +++ b/database/schemas/public/table/user_posts.go @@ -0,0 +1,90 @@ +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package table + +import ( + "github.com/go-jet/jet/v2/postgres" +) + +var UserPosts = newUserPostsTable("public", "user_posts", "") + +type userPostsTable struct { + postgres.Table + + // Columns + ID postgres.ColumnInteger + CreatedAt postgres.ColumnTimestamp + UpdatedAt postgres.ColumnTimestamp + UserID postgres.ColumnInteger + PostID postgres.ColumnInteger + Price postgres.ColumnInteger + + AllColumns postgres.ColumnList + MutableColumns postgres.ColumnList +} + +type UserPostsTable struct { + userPostsTable + + EXCLUDED userPostsTable +} + +// AS creates new UserPostsTable with assigned alias +func (a UserPostsTable) AS(alias string) *UserPostsTable { + return newUserPostsTable(a.SchemaName(), a.TableName(), alias) +} + +// Schema creates new UserPostsTable with assigned schema name +func (a UserPostsTable) FromSchema(schemaName string) *UserPostsTable { + return newUserPostsTable(schemaName, a.TableName(), a.Alias()) +} + +// WithPrefix creates new UserPostsTable with assigned table prefix +func (a UserPostsTable) WithPrefix(prefix string) *UserPostsTable { + return newUserPostsTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) +} + +// WithSuffix creates new UserPostsTable with assigned table suffix +func (a UserPostsTable) WithSuffix(suffix string) *UserPostsTable { + return newUserPostsTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) +} + +func newUserPostsTable(schemaName, tableName, alias string) *UserPostsTable { + return &UserPostsTable{ + userPostsTable: newUserPostsTableImpl(schemaName, tableName, alias), + EXCLUDED: newUserPostsTableImpl("", "excluded", ""), + } +} + +func newUserPostsTableImpl(schemaName, tableName, alias string) userPostsTable { + var ( + IDColumn = postgres.IntegerColumn("id") + CreatedAtColumn = postgres.TimestampColumn("created_at") + UpdatedAtColumn = postgres.TimestampColumn("updated_at") + UserIDColumn = postgres.IntegerColumn("user_id") + PostIDColumn = postgres.IntegerColumn("post_id") + PriceColumn = postgres.IntegerColumn("price") + allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, UserIDColumn, PostIDColumn, PriceColumn} + mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, UserIDColumn, PostIDColumn, PriceColumn} + ) + + return userPostsTable{ + Table: postgres.NewTable(schemaName, tableName, alias, allColumns...), + + //Columns + ID: IDColumn, + CreatedAt: CreatedAtColumn, + UpdatedAt: UpdatedAtColumn, + UserID: UserIDColumn, + PostID: PostIDColumn, + Price: PriceColumn, + + AllColumns: allColumns, + MutableColumns: mutableColumns, + } +} diff --git a/database/schemas/public/table/users.go b/database/schemas/public/table/users.go new file mode 100644 index 0000000..974843c --- /dev/null +++ b/database/schemas/public/table/users.go @@ -0,0 +1,96 @@ +// +// Code generated by go-jet DO NOT EDIT. +// +// WARNING: Changes to this file may cause incorrect behavior +// and will be lost if the code is regenerated +// + +package table + +import ( + "github.com/go-jet/jet/v2/postgres" +) + +var Users = newUsersTable("public", "users", "") + +type usersTable struct { + postgres.Table + + // Columns + ID postgres.ColumnInteger + CreatedAt postgres.ColumnTimestamp + UpdatedAt postgres.ColumnTimestamp + DeletedAt postgres.ColumnTimestamp + Status postgres.ColumnInteger + OpenID postgres.ColumnString + Username postgres.ColumnString + Avatar postgres.ColumnString + + AllColumns postgres.ColumnList + MutableColumns postgres.ColumnList +} + +type UsersTable struct { + usersTable + + EXCLUDED usersTable +} + +// AS creates new UsersTable with assigned alias +func (a UsersTable) AS(alias string) *UsersTable { + return newUsersTable(a.SchemaName(), a.TableName(), alias) +} + +// Schema creates new UsersTable with assigned schema name +func (a UsersTable) FromSchema(schemaName string) *UsersTable { + return newUsersTable(schemaName, a.TableName(), a.Alias()) +} + +// WithPrefix creates new UsersTable with assigned table prefix +func (a UsersTable) WithPrefix(prefix string) *UsersTable { + return newUsersTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) +} + +// WithSuffix creates new UsersTable with assigned table suffix +func (a UsersTable) WithSuffix(suffix string) *UsersTable { + return newUsersTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) +} + +func newUsersTable(schemaName, tableName, alias string) *UsersTable { + return &UsersTable{ + usersTable: newUsersTableImpl(schemaName, tableName, alias), + EXCLUDED: newUsersTableImpl("", "excluded", ""), + } +} + +func newUsersTableImpl(schemaName, tableName, alias string) usersTable { + var ( + IDColumn = postgres.IntegerColumn("id") + CreatedAtColumn = postgres.TimestampColumn("created_at") + UpdatedAtColumn = postgres.TimestampColumn("updated_at") + DeletedAtColumn = postgres.TimestampColumn("deleted_at") + StatusColumn = postgres.IntegerColumn("status") + OpenIDColumn = postgres.StringColumn("open_id") + UsernameColumn = postgres.StringColumn("username") + AvatarColumn = postgres.StringColumn("avatar") + allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn} + mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn} + ) + + return usersTable{ + Table: postgres.NewTable(schemaName, tableName, alias, allColumns...), + + //Columns + ID: IDColumn, + CreatedAt: CreatedAtColumn, + UpdatedAt: UpdatedAtColumn, + DeletedAt: DeletedAtColumn, + Status: StatusColumn, + OpenID: OpenIDColumn, + Username: UsernameColumn, + Avatar: AvatarColumn, + + AllColumns: allColumns, + MutableColumns: mutableColumns, + } +} diff --git a/database/transform.yaml b/database/transform.yaml index 13cb9a2..3b93dbd 100644 --- a/database/transform.yaml +++ b/database/transform.yaml @@ -7,6 +7,7 @@ ignores: - river_queue model: - migrations + - user_posts types: # users: # table name # meta: UserMeta