feat: Update project structure and configuration files

This commit is contained in:
rogeecn
2025-03-24 09:29:38 +08:00
parent ea15a51556
commit 8de43c2861
159 changed files with 498 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
package database
import (
"context"
"database/sql"
"embed"
"fmt"
"github.com/go-jet/jet/v2/qrm"
)
//go:embed migrations/*
var MigrationFS embed.FS
type CtxDB struct{}
func FromContext(ctx context.Context, db *sql.DB) qrm.DB {
if tx, ok := ctx.Value(CtxDB{}).(*sql.Tx); ok {
return tx
}
return db
}
func Truncate(ctx context.Context, db *sql.DB, tableName ...string) error {
for _, name := range tableName {
sql := fmt.Sprintf("TRUNCATE TABLE %s RESTART IDENTITY", name)
if _, err := db.ExecContext(ctx, sql); err != nil {
return err
}
}
return nil
}
func WrapLike(v string) string {
return "%" + v + "%"
}
func WrapLikeLeft(v string) string {
return "%" + v
}
func WrapLikeRight(v string) string {
return "%" + v
}

View File

@@ -0,0 +1,45 @@
package fields
import (
"database/sql/driver"
"encoding/json"
"errors"
)
// implement sql.Scanner interface
type Json[T any] struct {
Data T `json:",inline"`
}
func ToJson[T any](data T) Json[T] {
return Json[T]{Data: data}
}
func (x *Json[T]) Scan(value interface{}) (err error) {
switch v := value.(type) {
case string:
return json.Unmarshal([]byte(v), &x)
case []byte:
return json.Unmarshal(v, &x)
case *string:
return json.Unmarshal([]byte(*v), &x)
}
return errors.New("Unknown type for ")
}
func (x Json[T]) Value() (driver.Value, error) {
return json.Marshal(x.Data)
}
func (x Json[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(x.Data)
}
func (x *Json[T]) UnmarshalJSON(data []byte) error {
var value T
if err := json.Unmarshal(data, &value); err != nil {
return err
}
x.Data = value
return nil
}

View File

@@ -0,0 +1,652 @@
// Code generated by go-enum DO NOT EDIT.
// Version: -
// Revision: -
// Build Date: -
// Built By: -
package fields
import (
"database/sql/driver"
"errors"
"fmt"
"strconv"
"strings"
)
const (
// MediaAssetTypeUnknown is a MediaAssetType of type Unknown.
MediaAssetTypeUnknown MediaAssetType = "unknown"
// MediaAssetTypePoster is a MediaAssetType of type Poster.
MediaAssetTypePoster MediaAssetType = "poster"
// MediaAssetTypeImage is a MediaAssetType of type Image.
MediaAssetTypeImage MediaAssetType = "image"
// MediaAssetTypeVideo is a MediaAssetType of type Video.
MediaAssetTypeVideo MediaAssetType = "video"
// MediaAssetTypeAudio is a MediaAssetType of type Audio.
MediaAssetTypeAudio MediaAssetType = "audio"
// MediaAssetTypeDocument is a MediaAssetType of type Document.
MediaAssetTypeDocument MediaAssetType = "document"
// MediaAssetTypeOther is a MediaAssetType of type Other.
MediaAssetTypeOther MediaAssetType = "other"
)
var ErrInvalidMediaAssetType = fmt.Errorf("not a valid MediaAssetType, try [%s]", strings.Join(_MediaAssetTypeNames, ", "))
var _MediaAssetTypeNames = []string{
string(MediaAssetTypeUnknown),
string(MediaAssetTypePoster),
string(MediaAssetTypeImage),
string(MediaAssetTypeVideo),
string(MediaAssetTypeAudio),
string(MediaAssetTypeDocument),
string(MediaAssetTypeOther),
}
// MediaAssetTypeNames returns a list of possible string values of MediaAssetType.
func MediaAssetTypeNames() []string {
tmp := make([]string, len(_MediaAssetTypeNames))
copy(tmp, _MediaAssetTypeNames)
return tmp
}
// MediaAssetTypeValues returns a list of the values for MediaAssetType
func MediaAssetTypeValues() []MediaAssetType {
return []MediaAssetType{
MediaAssetTypeUnknown,
MediaAssetTypePoster,
MediaAssetTypeImage,
MediaAssetTypeVideo,
MediaAssetTypeAudio,
MediaAssetTypeDocument,
MediaAssetTypeOther,
}
}
// String implements the Stringer interface.
func (x MediaAssetType) String() string {
return string(x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x MediaAssetType) IsValid() bool {
_, err := ParseMediaAssetType(string(x))
return err == nil
}
var _MediaAssetTypeValue = map[string]MediaAssetType{
"unknown": MediaAssetTypeUnknown,
"poster": MediaAssetTypePoster,
"image": MediaAssetTypeImage,
"video": MediaAssetTypeVideo,
"audio": MediaAssetTypeAudio,
"document": MediaAssetTypeDocument,
"other": MediaAssetTypeOther,
}
// ParseMediaAssetType attempts to convert a string to a MediaAssetType.
func ParseMediaAssetType(name string) (MediaAssetType, error) {
if x, ok := _MediaAssetTypeValue[name]; ok {
return x, nil
}
return MediaAssetType(""), fmt.Errorf("%s is %w", name, ErrInvalidMediaAssetType)
}
var errMediaAssetTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *MediaAssetType) Scan(value interface{}) (err error) {
if value == nil {
*x = MediaAssetType("")
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case string:
*x, err = ParseMediaAssetType(v)
case []byte:
*x, err = ParseMediaAssetType(string(v))
case MediaAssetType:
*x = v
case *MediaAssetType:
if v == nil {
return errMediaAssetTypeNilPtr
}
*x = *v
case *string:
if v == nil {
return errMediaAssetTypeNilPtr
}
*x, err = ParseMediaAssetType(*v)
default:
return errors.New("invalid type for MediaAssetType")
}
return
}
// Value implements the driver Valuer interface.
func (x MediaAssetType) Value() (driver.Value, error) {
return x.String(), nil
}
// Set implements the Golang flag.Value interface func.
func (x *MediaAssetType) Set(val string) error {
v, err := ParseMediaAssetType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *MediaAssetType) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *MediaAssetType) Type() string {
return "MediaAssetType"
}
type NullMediaAssetType struct {
MediaAssetType MediaAssetType
Valid bool
}
func NewNullMediaAssetType(val interface{}) (x NullMediaAssetType) {
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
_ = err // make any errcheck linters happy
return
}
// Scan implements the Scanner interface.
func (x *NullMediaAssetType) Scan(value interface{}) (err error) {
if value == nil {
x.MediaAssetType, x.Valid = MediaAssetType(""), false
return
}
err = x.MediaAssetType.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullMediaAssetType) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return string(x.MediaAssetType), nil
}
type NullMediaAssetTypeStr struct {
NullMediaAssetType
}
func NewNullMediaAssetTypeStr(val interface{}) (x NullMediaAssetTypeStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullMediaAssetTypeStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.MediaAssetType.String(), nil
}
const (
// PostStatusDraft is a PostStatus of type Draft.
PostStatusDraft PostStatus = iota
// PostStatusPublished is a PostStatus of type Published.
PostStatusPublished
)
var ErrInvalidPostStatus = fmt.Errorf("not a valid PostStatus, try [%s]", strings.Join(_PostStatusNames, ", "))
const _PostStatusName = "draftpublished"
var _PostStatusNames = []string{
_PostStatusName[0:5],
_PostStatusName[5:14],
}
// PostStatusNames returns a list of possible string values of PostStatus.
func PostStatusNames() []string {
tmp := make([]string, len(_PostStatusNames))
copy(tmp, _PostStatusNames)
return tmp
}
// PostStatusValues returns a list of the values for PostStatus
func PostStatusValues() []PostStatus {
return []PostStatus{
PostStatusDraft,
PostStatusPublished,
}
}
var _PostStatusMap = map[PostStatus]string{
PostStatusDraft: _PostStatusName[0:5],
PostStatusPublished: _PostStatusName[5:14],
}
// String implements the Stringer interface.
func (x PostStatus) String() string {
if str, ok := _PostStatusMap[x]; ok {
return str
}
return fmt.Sprintf("PostStatus(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x PostStatus) IsValid() bool {
_, ok := _PostStatusMap[x]
return ok
}
var _PostStatusValue = map[string]PostStatus{
_PostStatusName[0:5]: PostStatusDraft,
_PostStatusName[5:14]: PostStatusPublished,
}
// ParsePostStatus attempts to convert a string to a PostStatus.
func ParsePostStatus(name string) (PostStatus, error) {
if x, ok := _PostStatusValue[name]; ok {
return x, nil
}
return PostStatus(0), fmt.Errorf("%s is %w", name, ErrInvalidPostStatus)
}
var errPostStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *PostStatus) Scan(value interface{}) (err error) {
if value == nil {
*x = PostStatus(0)
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = PostStatus(v)
case string:
*x, err = ParsePostStatus(v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil {
*x, err = PostStatus(val), nil
}
}
case []byte:
*x, err = ParsePostStatus(string(v))
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = PostStatus(val), nil
}
}
case PostStatus:
*x = v
case int:
*x = PostStatus(v)
case *PostStatus:
if v == nil {
return errPostStatusNilPtr
}
*x = *v
case uint:
*x = PostStatus(v)
case uint64:
*x = PostStatus(v)
case *int:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *int64:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case float64: // json marshals everything as a float64 if it's a number
*x = PostStatus(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *uint:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *uint64:
if v == nil {
return errPostStatusNilPtr
}
*x = PostStatus(*v)
case *string:
if v == nil {
return errPostStatusNilPtr
}
*x, err = ParsePostStatus(*v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = PostStatus(val), nil
}
}
}
return
}
// Value implements the driver Valuer interface.
func (x PostStatus) Value() (driver.Value, error) {
return int64(x), nil
}
// Set implements the Golang flag.Value interface func.
func (x *PostStatus) Set(val string) error {
v, err := ParsePostStatus(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *PostStatus) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *PostStatus) Type() string {
return "PostStatus"
}
type NullPostStatus struct {
PostStatus PostStatus
Valid bool
}
func NewNullPostStatus(val interface{}) (x NullPostStatus) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Scan implements the Scanner interface.
func (x *NullPostStatus) Scan(value interface{}) (err error) {
if value == nil {
x.PostStatus, x.Valid = PostStatus(0), false
return
}
err = x.PostStatus.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullPostStatus) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.PostStatus), nil
}
type NullPostStatusStr struct {
NullPostStatus
}
func NewNullPostStatusStr(val interface{}) (x NullPostStatusStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullPostStatusStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.PostStatus.String(), nil
}
const (
// PostTypeArticle is a PostType of type Article.
PostTypeArticle PostType = iota
// PostTypePicture is a PostType of type Picture.
PostTypePicture
// PostTypeVideo is a PostType of type Video.
PostTypeVideo
// PostTypeAudio is a PostType of type Audio.
PostTypeAudio
)
var ErrInvalidPostType = fmt.Errorf("not a valid PostType, try [%s]", strings.Join(_PostTypeNames, ", "))
const _PostTypeName = "ArticlePictureVideoAudio"
var _PostTypeNames = []string{
_PostTypeName[0:7],
_PostTypeName[7:14],
_PostTypeName[14:19],
_PostTypeName[19:24],
}
// PostTypeNames returns a list of possible string values of PostType.
func PostTypeNames() []string {
tmp := make([]string, len(_PostTypeNames))
copy(tmp, _PostTypeNames)
return tmp
}
// PostTypeValues returns a list of the values for PostType
func PostTypeValues() []PostType {
return []PostType{
PostTypeArticle,
PostTypePicture,
PostTypeVideo,
PostTypeAudio,
}
}
var _PostTypeMap = map[PostType]string{
PostTypeArticle: _PostTypeName[0:7],
PostTypePicture: _PostTypeName[7:14],
PostTypeVideo: _PostTypeName[14:19],
PostTypeAudio: _PostTypeName[19:24],
}
// String implements the Stringer interface.
func (x PostType) String() string {
if str, ok := _PostTypeMap[x]; ok {
return str
}
return fmt.Sprintf("PostType(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x PostType) IsValid() bool {
_, ok := _PostTypeMap[x]
return ok
}
var _PostTypeValue = map[string]PostType{
_PostTypeName[0:7]: PostTypeArticle,
_PostTypeName[7:14]: PostTypePicture,
_PostTypeName[14:19]: PostTypeVideo,
_PostTypeName[19:24]: PostTypeAudio,
}
// ParsePostType attempts to convert a string to a PostType.
func ParsePostType(name string) (PostType, error) {
if x, ok := _PostTypeValue[name]; ok {
return x, nil
}
return PostType(0), fmt.Errorf("%s is %w", name, ErrInvalidPostType)
}
var errPostTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
// Scan implements the Scanner interface.
func (x *PostType) Scan(value interface{}) (err error) {
if value == nil {
*x = PostType(0)
return
}
// A wider range of scannable types.
// driver.Value values at the top of the list for expediency
switch v := value.(type) {
case int64:
*x = PostType(v)
case string:
*x, err = ParsePostType(v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(v); verr == nil {
*x, err = PostType(val), nil
}
}
case []byte:
*x, err = ParsePostType(string(v))
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(string(v)); verr == nil {
*x, err = PostType(val), nil
}
}
case PostType:
*x = v
case int:
*x = PostType(v)
case *PostType:
if v == nil {
return errPostTypeNilPtr
}
*x = *v
case uint:
*x = PostType(v)
case uint64:
*x = PostType(v)
case *int:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *int64:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case float64: // json marshals everything as a float64 if it's a number
*x = PostType(v)
case *float64: // json marshals everything as a float64 if it's a number
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *uint:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *uint64:
if v == nil {
return errPostTypeNilPtr
}
*x = PostType(*v)
case *string:
if v == nil {
return errPostTypeNilPtr
}
*x, err = ParsePostType(*v)
if err != nil {
// try parsing the integer value as a string
if val, verr := strconv.Atoi(*v); verr == nil {
*x, err = PostType(val), nil
}
}
}
return
}
// Value implements the driver Valuer interface.
func (x PostType) Value() (driver.Value, error) {
return int64(x), nil
}
// Set implements the Golang flag.Value interface func.
func (x *PostType) Set(val string) error {
v, err := ParsePostType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *PostType) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *PostType) Type() string {
return "PostType"
}
type NullPostType struct {
PostType PostType
Valid bool
}
func NewNullPostType(val interface{}) (x NullPostType) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Scan implements the Scanner interface.
func (x *NullPostType) Scan(value interface{}) (err error) {
if value == nil {
x.PostType, x.Valid = PostType(0), false
return
}
err = x.PostType.Scan(value)
x.Valid = (err == nil)
return
}
// Value implements the driver Valuer interface.
func (x NullPostType) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
// driver.Value accepts int64 for int values.
return int64(x.PostType), nil
}
type NullPostTypeStr struct {
NullPostType
}
func NewNullPostTypeStr(val interface{}) (x NullPostTypeStr) {
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
return
}
// Value implements the driver Valuer interface.
func (x NullPostTypeStr) Value() (driver.Value, error) {
if !x.Valid {
return nil, nil
}
return x.PostType.String(), nil
}

View File

@@ -0,0 +1,27 @@
package fields
type MediaAsset struct {
Type MediaAssetType `json:"type"`
Media int64 `json:"media"`
Mark *string `json:"mark,omitempty"`
}
// swagger:enum MediaAssetType
// ENUM(
// Unknown = "unknown",
// Poster = "poster",
// Image = "image",
// Video = "video",
// Audio = "audio",
// Document = "document",
// Other = "other"
// )
type MediaAssetType string
// swagger:enum PostStatus
// ENUM( draft, published )
type PostStatus int16
// swagger:enum PostType
// ENUM( Article, Picture, Video, Audio)
type PostType int16

View File

@@ -0,0 +1,408 @@
-- +goose Up
-- +goose StatementBegin
-- River migration 002 [up]
CREATE TYPE river_job_state AS ENUM(
'available',
'cancelled',
'completed',
'discarded',
'pending',
'retryable',
'running',
'scheduled'
);
CREATE TABLE river_job(
-- 8 bytes
id bigserial PRIMARY KEY,
-- 8 bytes (4 bytes + 2 bytes + 2 bytes)
--
-- `state` is kept near the top of the table for operator convenience -- when
-- looking at jobs with `SELECT *` it'll appear first after ID. The other two
-- fields aren't as important but are kept adjacent to `state` for alignment
-- to get an 8-byte block.
state river_job_state NOT NULL DEFAULT 'available',
attempt smallint NOT NULL DEFAULT 0,
max_attempts smallint NOT NULL,
-- 8 bytes each (no alignment needed)
attempted_at timestamptz,
created_at timestamptz NOT NULL DEFAULT NOW(),
finalized_at timestamptz,
scheduled_at timestamptz NOT NULL DEFAULT NOW(),
-- 2 bytes (some wasted padding probably)
priority smallint NOT NULL DEFAULT 1,
-- types stored out-of-band
args jsonb,
attempted_by text[],
errors jsonb[],
kind text NOT NULL,
metadata jsonb NOT NULL DEFAULT '{}',
queue text NOT NULL DEFAULT 'default',
tags varchar(255)[],
CONSTRAINT finalized_or_finalized_at_null CHECK ((state IN ('cancelled', 'completed', 'discarded') AND finalized_at IS NOT NULL) OR finalized_at IS NULL),
CONSTRAINT max_attempts_is_positive CHECK (max_attempts > 0),
CONSTRAINT priority_in_range CHECK (priority >= 1 AND priority <= 4),
CONSTRAINT queue_length CHECK (char_length(queue) > 0 AND char_length(queue) < 128),
CONSTRAINT kind_length CHECK (char_length(kind) > 0 AND char_length(kind) < 128)
);
-- We may want to consider adding another property here after `kind` if it seems
-- like it'd be useful for something.
CREATE INDEX river_job_kind ON river_job USING btree(kind);
CREATE INDEX river_job_state_and_finalized_at_index ON river_job USING btree(state, finalized_at) WHERE finalized_at IS NOT NULL;
CREATE INDEX river_job_prioritized_fetching_index ON river_job USING btree(state, queue, priority, scheduled_at, id);
CREATE INDEX river_job_args_index ON river_job USING GIN(args);
CREATE INDEX river_job_metadata_index ON river_job USING GIN(metadata);
CREATE OR REPLACE FUNCTION river_job_notify()
RETURNS TRIGGER
AS $$
DECLARE
payload json;
BEGIN
IF NEW.state = 'available' THEN
-- Notify will coalesce duplicate notifications within a transaction, so
-- keep these payloads generalized:
payload = json_build_object('queue', NEW.queue);
PERFORM
pg_notify('river_insert', payload::text);
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER river_notify
AFTER INSERT ON river_job
FOR EACH ROW
EXECUTE PROCEDURE river_job_notify();
CREATE UNLOGGED TABLE river_leader(
-- 8 bytes each (no alignment needed)
elected_at timestamptz NOT NULL,
expires_at timestamptz NOT NULL,
-- types stored out-of-band
leader_id text NOT NULL,
name text PRIMARY KEY,
CONSTRAINT name_length CHECK (char_length(name) > 0 AND char_length(name) < 128),
CONSTRAINT leader_id_length CHECK (char_length(leader_id) > 0 AND char_length(leader_id) < 128)
);
-- River migration 003 [up]
ALTER TABLE river_job ALTER COLUMN tags SET DEFAULT '{}';
UPDATE river_job SET tags = '{}' WHERE tags IS NULL;
ALTER TABLE river_job ALTER COLUMN tags SET NOT NULL;
-- River migration 004 [up]
-- The args column never had a NOT NULL constraint or default value at the
-- database level, though we tried to ensure one at the application level.
ALTER TABLE river_job ALTER COLUMN args SET DEFAULT '{}';
UPDATE river_job SET args = '{}' WHERE args IS NULL;
ALTER TABLE river_job ALTER COLUMN args SET NOT NULL;
ALTER TABLE river_job ALTER COLUMN args DROP DEFAULT;
-- The metadata column never had a NOT NULL constraint or default value at the
-- database level, though we tried to ensure one at the application level.
ALTER TABLE river_job ALTER COLUMN metadata SET DEFAULT '{}';
UPDATE river_job SET metadata = '{}' WHERE metadata IS NULL;
ALTER TABLE river_job ALTER COLUMN metadata SET NOT NULL;
-- The 'pending' job state will be used for upcoming functionality:
-- ALTER TYPE river_job_state ADD VALUE IF NOT EXISTS 'pending' AFTER 'discarded';
ALTER TABLE river_job DROP CONSTRAINT finalized_or_finalized_at_null;
ALTER TABLE river_job ADD CONSTRAINT finalized_or_finalized_at_null CHECK (
(finalized_at IS NULL AND state NOT IN ('cancelled', 'completed', 'discarded')) OR
(finalized_at IS NOT NULL AND state IN ('cancelled', 'completed', 'discarded'))
);
DROP TRIGGER river_notify ON river_job;
DROP FUNCTION river_job_notify;
CREATE TABLE river_queue(
name text PRIMARY KEY NOT NULL,
created_at timestamptz NOT NULL DEFAULT NOW(),
metadata jsonb NOT NULL DEFAULT '{}' ::jsonb,
paused_at timestamptz,
updated_at timestamptz NOT NULL
);
ALTER TABLE river_leader
ALTER COLUMN name SET DEFAULT 'default',
DROP CONSTRAINT name_length,
ADD CONSTRAINT name_length CHECK (name = 'default');
-- River migration 005 [up]
--
-- Rebuild the migration table so it's based on `(line, version)`.
--
DO
$body$
BEGIN
-- Tolerate users who may be using their own migration system rather than
-- River's. If they are, they will have skipped version 001 containing
-- `CREATE TABLE river_migration`, so this table won't exist.
IF (SELECT to_regclass('river_migration') IS NOT NULL) THEN
ALTER TABLE river_migration
RENAME TO river_migration_old;
CREATE TABLE river_migration(
line TEXT NOT NULL,
version bigint NOT NULL,
created_at timestamptz NOT NULL DEFAULT NOW(),
CONSTRAINT line_length CHECK (char_length(line) > 0 AND char_length(line) < 128),
CONSTRAINT version_gte_1 CHECK (version >= 1),
PRIMARY KEY (line, version)
);
INSERT INTO river_migration
(created_at, line, version)
SELECT created_at, 'main', version
FROM river_migration_old;
DROP TABLE river_migration_old;
END IF;
END;
$body$
LANGUAGE 'plpgsql';
--
-- Add `river_job.unique_key` and bring up an index on it.
--
-- These statements use `IF NOT EXISTS` to allow users with a `river_job` table
-- of non-trivial size to build the index `CONCURRENTLY` out of band of this
-- migration, then follow by completing the migration.
ALTER TABLE river_job
ADD COLUMN IF NOT EXISTS unique_key bytea;
CREATE UNIQUE INDEX IF NOT EXISTS river_job_kind_unique_key_idx ON river_job (kind, unique_key) WHERE unique_key IS NOT NULL;
--
-- Create `river_client` and derivative.
--
-- This feature hasn't quite yet been implemented, but we're taking advantage of
-- the migration to add the schema early so that we can add it later without an
-- additional migration.
--
CREATE UNLOGGED TABLE river_client (
id text PRIMARY KEY NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
metadata jsonb NOT NULL DEFAULT '{}',
paused_at timestamptz,
updated_at timestamptz NOT NULL,
CONSTRAINT name_length CHECK (char_length(id) > 0 AND char_length(id) < 128)
);
-- Differs from `river_queue` in that it tracks the queue state for a particular
-- active client.
CREATE UNLOGGED TABLE river_client_queue (
river_client_id text NOT NULL REFERENCES river_client (id) ON DELETE CASCADE,
name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
max_workers bigint NOT NULL DEFAULT 0,
metadata jsonb NOT NULL DEFAULT '{}',
num_jobs_completed bigint NOT NULL DEFAULT 0,
num_jobs_running bigint NOT NULL DEFAULT 0,
updated_at timestamptz NOT NULL,
PRIMARY KEY (river_client_id, name),
CONSTRAINT name_length CHECK (char_length(name) > 0 AND char_length(name) < 128),
CONSTRAINT num_jobs_completed_zero_or_positive CHECK (num_jobs_completed >= 0),
CONSTRAINT num_jobs_running_zero_or_positive CHECK (num_jobs_running >= 0)
);
-- River migration 006 [up]
CREATE OR REPLACE FUNCTION river_job_state_in_bitmask(bitmask BIT(8), state river_job_state)
RETURNS boolean
LANGUAGE SQL
IMMUTABLE
AS $$
SELECT CASE state
WHEN 'available' THEN get_bit(bitmask, 7)
WHEN 'cancelled' THEN get_bit(bitmask, 6)
WHEN 'completed' THEN get_bit(bitmask, 5)
WHEN 'discarded' THEN get_bit(bitmask, 4)
WHEN 'pending' THEN get_bit(bitmask, 3)
WHEN 'retryable' THEN get_bit(bitmask, 2)
WHEN 'running' THEN get_bit(bitmask, 1)
WHEN 'scheduled' THEN get_bit(bitmask, 0)
ELSE 0
END = 1;
$$;
--
-- Add `river_job.unique_states` and bring up an index on it.
--
-- This column may exist already if users manually created the column and index
-- as instructed in the changelog so the index could be created `CONCURRENTLY`.
--
ALTER TABLE river_job ADD COLUMN IF NOT EXISTS unique_states BIT(8);
-- This statement uses `IF NOT EXISTS` to allow users with a `river_job` table
-- of non-trivial size to build the index `CONCURRENTLY` out of band of this
-- migration, then follow by completing the migration.
CREATE UNIQUE INDEX IF NOT EXISTS river_job_unique_idx ON river_job (unique_key)
WHERE unique_key IS NOT NULL
AND unique_states IS NOT NULL
AND river_job_state_in_bitmask(unique_states, state);
-- Remove the old unique index. Users who are actively using the unique jobs
-- feature and who wish to avoid deploy downtime may want od drop this in a
-- subsequent migration once all jobs using the old unique system have been
-- completed (i.e. no more rows with non-null unique_key and null
-- unique_states).
DROP INDEX river_job_kind_unique_key_idx;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
-- Drop Users Table
-- River migration 006 [down]
--
-- Drop `river_job.unique_states` and its index.
--
DROP INDEX river_job_unique_idx;
ALTER TABLE river_job
DROP COLUMN unique_states;
CREATE UNIQUE INDEX IF NOT EXISTS river_job_kind_unique_key_idx ON river_job (kind, unique_key) WHERE unique_key IS NOT NULL;
--
-- Drop `river_job_state_in_bitmask` function.
--
DROP FUNCTION river_job_state_in_bitmask;
-- River migration 005 [down]
--
-- Revert to migration table based only on `(version)`.
--
-- If any non-main migrations are present, 005 is considered irreversible.
--
DO
$body$
BEGIN
-- Tolerate users who may be using their own migration system rather than
-- River's. If they are, they will have skipped version 001 containing
-- `CREATE TABLE river_migration`, so this table won't exist.
IF (SELECT to_regclass('river_migration') IS NOT NULL) THEN
IF EXISTS (
SELECT *
FROM river_migration
WHERE line <> 'main'
) THEN
RAISE EXCEPTION 'Found non-main migration lines in the database; version 005 migration is irreversible because it would result in loss of migration information.';
END IF;
ALTER TABLE river_migration
RENAME TO river_migration_old;
CREATE TABLE river_migration(
id bigserial PRIMARY KEY,
created_at timestamptz NOT NULL DEFAULT NOW(),
version bigint NOT NULL,
CONSTRAINT version CHECK (version >= 1)
);
CREATE UNIQUE INDEX ON river_migration USING btree(version);
INSERT INTO river_migration
(created_at, version)
SELECT created_at, version
FROM river_migration_old;
DROP TABLE river_migration_old;
END IF;
END;
$body$
LANGUAGE 'plpgsql';
--
-- Drop `river_job.unique_key`.
--
ALTER TABLE river_job
DROP COLUMN unique_key;
--
-- Drop `river_client` and derivative.
--
DROP TABLE river_client_queue;
DROP TABLE river_client;
-- River migration 004 [down]
ALTER TABLE river_job ALTER COLUMN args DROP NOT NULL;
ALTER TABLE river_job ALTER COLUMN metadata DROP NOT NULL;
ALTER TABLE river_job ALTER COLUMN metadata DROP DEFAULT;
-- It is not possible to safely remove 'pending' from the river_job_state enum,
-- so leave it in place.
ALTER TABLE river_job DROP CONSTRAINT finalized_or_finalized_at_null;
ALTER TABLE river_job ADD CONSTRAINT finalized_or_finalized_at_null CHECK (
(state IN ('cancelled', 'completed', 'discarded') AND finalized_at IS NOT NULL) OR finalized_at IS NULL
);
CREATE OR REPLACE FUNCTION river_job_notify()
RETURNS TRIGGER
AS $$
DECLARE
payload json;
BEGIN
IF NEW.state = 'available' THEN
-- Notify will coalesce duplicate notifications within a transaction, so
-- keep these payloads generalized:
payload = json_build_object('queue', NEW.queue);
PERFORM
pg_notify('river_insert', payload::text);
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER river_notify
AFTER INSERT ON river_job
FOR EACH ROW
EXECUTE PROCEDURE river_job_notify();
DROP TABLE river_queue;
ALTER TABLE river_leader
ALTER COLUMN name DROP DEFAULT,
DROP CONSTRAINT name_length,
ADD CONSTRAINT name_length CHECK (char_length(name) > 0 AND char_length(name) < 128);
-- River migration 003 [down]
ALTER TABLE river_job ALTER COLUMN tags DROP NOT NULL,
ALTER COLUMN tags DROP DEFAULT;
-- River migration 002 [down]
DROP TABLE river_job;
DROP FUNCTION river_job_notify;
DROP TYPE river_job_state;
DROP TABLE river_leader;
-- +goose StatementEnd

View File

@@ -0,0 +1,17 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE medias(
id SERIAL8 PRIMARY KEY,
created_at timestamp NOT NULL DEFAULT now(),
name varchar(255) NOT NULL DEFAULT '',
mime_type varchar(128) NOT NULL DEFAULT '',
size int8 NOT NULL DEFAULT 0,
path varchar(255) NOT NULL DEFAULT ''
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE medias;
-- +goose StatementEnd

View File

@@ -0,0 +1,25 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE posts(
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,
title varchar(128) NOT NULL,
description varchar(256) NOT NULL,
content text NOT NULL,
price int8 NOT NULL DEFAULT 0,
discount int2 NOT NULL DEFAULT 100,
views int8 NOT NULL DEFAULT 0,
likes int8 NOT NULL DEFAULT 0,
tags jsonb DEFAULT '{}' ::jsonb,
assets jsonb DEFAULT '{}' ::jsonb
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE posts;
-- +goose StatementEnd

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,30 @@
//
// 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 enum
import "github.com/go-jet/jet/v2/postgres"
var RiverJobState = &struct {
Available postgres.StringExpression
Cancelled postgres.StringExpression
Completed postgres.StringExpression
Discarded postgres.StringExpression
Pending postgres.StringExpression
Retryable postgres.StringExpression
Running postgres.StringExpression
Scheduled postgres.StringExpression
}{
Available: postgres.NewEnumValue("available"),
Cancelled: postgres.NewEnumValue("cancelled"),
Completed: postgres.NewEnumValue("completed"),
Discarded: postgres.NewEnumValue("discarded"),
Pending: postgres.NewEnumValue("pending"),
Retryable: postgres.NewEnumValue("retryable"),
Running: postgres.NewEnumValue("running"),
Scheduled: postgres.NewEnumValue("scheduled"),
}

View File

@@ -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 Medias struct {
ID int64 `sql:"primary_key" json:"id"`
CreatedAt time.Time `json:"created_at"`
Name string `json:"name"`
MimeType string `json:"mime_type"`
Size int64 `json:"size"`
Path string `json:"path"`
}

View File

@@ -0,0 +1,19 @@
//
// 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 Migrations struct {
ID int32 `sql:"primary_key" json:"id"`
VersionID int64 `json:"version_id"`
IsApplied bool `json:"is_applied"`
Tstamp time.Time `json:"tstamp"`
}

View File

@@ -0,0 +1,30 @@
//
// 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 (
"quyun/database/fields"
"time"
)
type Posts 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 fields.PostStatus `json:"status"`
Title string `json:"title"`
Description string `json:"description"`
Content string `json:"content"`
Price int64 `json:"price"`
Discount int16 `json:"discount"`
Views int64 `json:"views"`
Likes int64 `json:"likes"`
Tags fields.Json[[]string] `json:"tags"`
Assets fields.Json[[]fields.MediaAsset] `json:"assets"`
}

View File

@@ -0,0 +1,73 @@
//
// 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 "errors"
type RiverJobState string
const (
RiverJobState_Available RiverJobState = "available"
RiverJobState_Cancelled RiverJobState = "cancelled"
RiverJobState_Completed RiverJobState = "completed"
RiverJobState_Discarded RiverJobState = "discarded"
RiverJobState_Pending RiverJobState = "pending"
RiverJobState_Retryable RiverJobState = "retryable"
RiverJobState_Running RiverJobState = "running"
RiverJobState_Scheduled RiverJobState = "scheduled"
)
var RiverJobStateAllValues = []RiverJobState{
RiverJobState_Available,
RiverJobState_Cancelled,
RiverJobState_Completed,
RiverJobState_Discarded,
RiverJobState_Pending,
RiverJobState_Retryable,
RiverJobState_Running,
RiverJobState_Scheduled,
}
func (e *RiverJobState) Scan(value interface{}) error {
var enumValue string
switch val := value.(type) {
case string:
enumValue = val
case []byte:
enumValue = string(val)
default:
return errors.New("jet: Invalid scan value for AllTypesEnum enum. Enum value has to be of type string or []byte")
}
switch enumValue {
case "available":
*e = RiverJobState_Available
case "cancelled":
*e = RiverJobState_Cancelled
case "completed":
*e = RiverJobState_Completed
case "discarded":
*e = RiverJobState_Discarded
case "pending":
*e = RiverJobState_Pending
case "retryable":
*e = RiverJobState_Retryable
case "running":
*e = RiverJobState_Running
case "scheduled":
*e = RiverJobState_Scheduled
default:
return errors.New("jet: Invalid scan value '" + enumValue + "' for RiverJobState enum")
}
return nil
}
func (e RiverJobState) String() string {
return string(e)
}

View File

@@ -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"`
}

View File

@@ -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"`
}

View File

@@ -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 Medias = newMediasTable("public", "medias", "")
type mediasTable struct {
postgres.Table
// Columns
ID postgres.ColumnInteger
CreatedAt postgres.ColumnTimestamp
Name postgres.ColumnString
MimeType postgres.ColumnString
Size postgres.ColumnInteger
Path postgres.ColumnString
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
}
type MediasTable struct {
mediasTable
EXCLUDED mediasTable
}
// AS creates new MediasTable with assigned alias
func (a MediasTable) AS(alias string) *MediasTable {
return newMediasTable(a.SchemaName(), a.TableName(), alias)
}
// Schema creates new MediasTable with assigned schema name
func (a MediasTable) FromSchema(schemaName string) *MediasTable {
return newMediasTable(schemaName, a.TableName(), a.Alias())
}
// WithPrefix creates new MediasTable with assigned table prefix
func (a MediasTable) WithPrefix(prefix string) *MediasTable {
return newMediasTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
}
// WithSuffix creates new MediasTable with assigned table suffix
func (a MediasTable) WithSuffix(suffix string) *MediasTable {
return newMediasTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
}
func newMediasTable(schemaName, tableName, alias string) *MediasTable {
return &MediasTable{
mediasTable: newMediasTableImpl(schemaName, tableName, alias),
EXCLUDED: newMediasTableImpl("", "excluded", ""),
}
}
func newMediasTableImpl(schemaName, tableName, alias string) mediasTable {
var (
IDColumn = postgres.IntegerColumn("id")
CreatedAtColumn = postgres.TimestampColumn("created_at")
NameColumn = postgres.StringColumn("name")
MimeTypeColumn = postgres.StringColumn("mime_type")
SizeColumn = postgres.IntegerColumn("size")
PathColumn = postgres.StringColumn("path")
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn}
mutableColumns = postgres.ColumnList{CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn}
)
return mediasTable{
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,
CreatedAt: CreatedAtColumn,
Name: NameColumn,
MimeType: MimeTypeColumn,
Size: SizeColumn,
Path: PathColumn,
AllColumns: allColumns,
MutableColumns: mutableColumns,
}
}

View File

@@ -0,0 +1,84 @@
//
// 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 Migrations = newMigrationsTable("public", "migrations", "")
type migrationsTable struct {
postgres.Table
// Columns
ID postgres.ColumnInteger
VersionID postgres.ColumnInteger
IsApplied postgres.ColumnBool
Tstamp postgres.ColumnTimestamp
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
}
type MigrationsTable struct {
migrationsTable
EXCLUDED migrationsTable
}
// AS creates new MigrationsTable with assigned alias
func (a MigrationsTable) AS(alias string) *MigrationsTable {
return newMigrationsTable(a.SchemaName(), a.TableName(), alias)
}
// Schema creates new MigrationsTable with assigned schema name
func (a MigrationsTable) FromSchema(schemaName string) *MigrationsTable {
return newMigrationsTable(schemaName, a.TableName(), a.Alias())
}
// WithPrefix creates new MigrationsTable with assigned table prefix
func (a MigrationsTable) WithPrefix(prefix string) *MigrationsTable {
return newMigrationsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
}
// WithSuffix creates new MigrationsTable with assigned table suffix
func (a MigrationsTable) WithSuffix(suffix string) *MigrationsTable {
return newMigrationsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
}
func newMigrationsTable(schemaName, tableName, alias string) *MigrationsTable {
return &MigrationsTable{
migrationsTable: newMigrationsTableImpl(schemaName, tableName, alias),
EXCLUDED: newMigrationsTableImpl("", "excluded", ""),
}
}
func newMigrationsTableImpl(schemaName, tableName, alias string) migrationsTable {
var (
IDColumn = postgres.IntegerColumn("id")
VersionIDColumn = postgres.IntegerColumn("version_id")
IsAppliedColumn = postgres.BoolColumn("is_applied")
TstampColumn = postgres.TimestampColumn("tstamp")
allColumns = postgres.ColumnList{IDColumn, VersionIDColumn, IsAppliedColumn, TstampColumn}
mutableColumns = postgres.ColumnList{VersionIDColumn, IsAppliedColumn, TstampColumn}
)
return migrationsTable{
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,
VersionID: VersionIDColumn,
IsApplied: IsAppliedColumn,
Tstamp: TstampColumn,
AllColumns: allColumns,
MutableColumns: mutableColumns,
}
}

View File

@@ -0,0 +1,114 @@
//
// 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 Posts = newPostsTable("public", "posts", "")
type postsTable struct {
postgres.Table
// Columns
ID postgres.ColumnInteger
CreatedAt postgres.ColumnTimestamp
UpdatedAt postgres.ColumnTimestamp
DeletedAt postgres.ColumnTimestamp
Status postgres.ColumnInteger
Title postgres.ColumnString
Description postgres.ColumnString
Content postgres.ColumnString
Price postgres.ColumnInteger
Discount postgres.ColumnInteger
Views postgres.ColumnInteger
Likes postgres.ColumnInteger
Tags postgres.ColumnString
Assets postgres.ColumnString
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
}
type PostsTable struct {
postsTable
EXCLUDED postsTable
}
// AS creates new PostsTable with assigned alias
func (a PostsTable) AS(alias string) *PostsTable {
return newPostsTable(a.SchemaName(), a.TableName(), alias)
}
// Schema creates new PostsTable with assigned schema name
func (a PostsTable) FromSchema(schemaName string) *PostsTable {
return newPostsTable(schemaName, a.TableName(), a.Alias())
}
// WithPrefix creates new PostsTable with assigned table prefix
func (a PostsTable) WithPrefix(prefix string) *PostsTable {
return newPostsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
}
// WithSuffix creates new PostsTable with assigned table suffix
func (a PostsTable) WithSuffix(suffix string) *PostsTable {
return newPostsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
}
func newPostsTable(schemaName, tableName, alias string) *PostsTable {
return &PostsTable{
postsTable: newPostsTableImpl(schemaName, tableName, alias),
EXCLUDED: newPostsTableImpl("", "excluded", ""),
}
}
func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
var (
IDColumn = postgres.IntegerColumn("id")
CreatedAtColumn = postgres.TimestampColumn("created_at")
UpdatedAtColumn = postgres.TimestampColumn("updated_at")
DeletedAtColumn = postgres.TimestampColumn("deleted_at")
StatusColumn = postgres.IntegerColumn("status")
TitleColumn = postgres.StringColumn("title")
DescriptionColumn = postgres.StringColumn("description")
ContentColumn = postgres.StringColumn("content")
PriceColumn = postgres.IntegerColumn("price")
DiscountColumn = postgres.IntegerColumn("discount")
ViewsColumn = postgres.IntegerColumn("views")
LikesColumn = postgres.IntegerColumn("likes")
TagsColumn = postgres.StringColumn("tags")
AssetsColumn = postgres.StringColumn("assets")
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn}
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn}
)
return postsTable{
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,
CreatedAt: CreatedAtColumn,
UpdatedAt: UpdatedAtColumn,
DeletedAt: DeletedAtColumn,
Status: StatusColumn,
Title: TitleColumn,
Description: DescriptionColumn,
Content: ContentColumn,
Price: PriceColumn,
Discount: DiscountColumn,
Views: ViewsColumn,
Likes: LikesColumn,
Tags: TagsColumn,
Assets: AssetsColumn,
AllColumns: allColumns,
MutableColumns: mutableColumns,
}
}

View File

@@ -0,0 +1,18 @@
//
// 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
// UseSchema sets a new schema name for all generated table SQL builder types. It is recommended to invoke
// this method only once at the beginning of the program.
func UseSchema(schema string) {
Medias = Medias.FromSchema(schema)
Migrations = Migrations.FromSchema(schema)
Posts = Posts.FromSchema(schema)
UserPosts = UserPosts.FromSchema(schema)
Users = Users.FromSchema(schema)
}

View File

@@ -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,
}
}

View File

@@ -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,
}
}

View File

@@ -0,0 +1,19 @@
ignores:
jet:
- river_leader
- river_job
- river_client
- river_client_queue
- river_queue
model:
- migrations
- user_posts
types:
# users: # table name
# meta: UserMeta
# meta: Json[UserMeta]
posts:
status: PostStatus
assets: Json[[]MediaAsset]
tags: Json[[]string]
meta: PostMeta