Compare commits
No commits in common. "f798869ef5fcb9722d5b210b4c09a437e7a47c06" and "c2ab455d3e653b8d7cab9e2df812a45d6e033116" have entirely different histories.
f798869ef5
...
c2ab455d3e
@ -1,68 +0,0 @@
|
|||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"embed"
|
|
||||||
"fmt"
|
|
||||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
|
||||||
migrate "github.com/rubenv/sql-migrate"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"gorm.io/driver/postgres"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed migrations/*.sql
|
|
||||||
var embedMigrations embed.FS
|
|
||||||
var client *gorm.DB
|
|
||||||
|
|
||||||
func Connect(_ context.Context, config models.DatabaseConfig) error {
|
|
||||||
var localSSL string
|
|
||||||
|
|
||||||
if config.SSL {
|
|
||||||
localSSL = "require"
|
|
||||||
} else {
|
|
||||||
localSSL = "disable"
|
|
||||||
}
|
|
||||||
|
|
||||||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=%s", config.Endpoint, config.Username, config.Password, config.Database, config.Port, localSSL, config.Timezone)
|
|
||||||
sqlDB, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
client = sqlDB
|
|
||||||
err = migrateDatabase(sqlDB, config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func migrateDatabase(dbPool *gorm.DB, config models.DatabaseConfig) error {
|
|
||||||
dialect := "postgres"
|
|
||||||
migrations := &migrate.EmbedFileSystemMigrationSource{FileSystem: embedMigrations, Root: "migrations"}
|
|
||||||
|
|
||||||
db, err := dbPool.DB()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("postgres migration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := migrate.Exec(db, dialect, migrations, migrate.Up)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("postgres migration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Debug {
|
|
||||||
if n != 0 {
|
|
||||||
log.Infof("postgres migration: applied %d migrations!", n)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.Info("postgres migration: nothing to migrate")
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
36
pkg/database/database.go
Normal file
36
pkg/database/database.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OtterSpace interface {
|
||||||
|
// Connect establishes a connection to the database.
|
||||||
|
Connect(ctx context.Context, config models.DatabaseConfig) error
|
||||||
|
|
||||||
|
// Post contains all function that are needed to manage Posts
|
||||||
|
Post
|
||||||
|
|
||||||
|
// User contains all function that are needed to manage the AnthroveUser
|
||||||
|
User
|
||||||
|
|
||||||
|
// Source contains all function that are needed to manage the Source
|
||||||
|
Source
|
||||||
|
|
||||||
|
// Tag contains all functions that are used to manage Tag
|
||||||
|
Tag
|
||||||
|
|
||||||
|
// TagAlias contains all function that are needed to manage the TagAlias
|
||||||
|
TagAlias
|
||||||
|
|
||||||
|
// TagGroup contains all function that are needed to manage the TagGroup
|
||||||
|
TagGroup
|
||||||
|
|
||||||
|
// ExecuteRawStatement run a custom query.
|
||||||
|
ExecuteRawStatement(ctx context.Context, query string, args ...any) error
|
||||||
|
|
||||||
|
// QueryRawStatement runs a custom query and returns the table
|
||||||
|
QueryRawStatement(ctx context.Context, query string, args ...any) (*sql.Rows, error)
|
||||||
|
}
|
@ -18,7 +18,7 @@ CREATE TYPE TagType AS ENUM (
|
|||||||
|
|
||||||
CREATE TABLE "Post"
|
CREATE TABLE "Post"
|
||||||
(
|
(
|
||||||
id CHAR(25) PRIMARY KEY,
|
id CHAR(25) PRIMARY KEY,
|
||||||
rating Rating,
|
rating Rating,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
@ -28,9 +28,9 @@ CREATE TABLE "Post"
|
|||||||
CREATE TABLE "Source"
|
CREATE TABLE "Source"
|
||||||
(
|
(
|
||||||
id CHAR(25) PRIMARY KEY,
|
id CHAR(25) PRIMARY KEY,
|
||||||
display_name TEXT NULL,
|
display_name TEXT NULL,
|
||||||
icon TEXT NULL,
|
icon TEXT NULL,
|
||||||
domain TEXT NOT NULL UNIQUE,
|
domain TEXT NOT NULL UNIQUE,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
deleted_at TIMESTAMP NULL
|
deleted_at TIMESTAMP NULL
|
||||||
@ -47,7 +47,7 @@ CREATE TABLE "Tag"
|
|||||||
|
|
||||||
CREATE TABLE "User"
|
CREATE TABLE "User"
|
||||||
(
|
(
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
deleted_at TIMESTAMP NULL
|
deleted_at TIMESTAMP NULL
|
||||||
@ -57,7 +57,7 @@ CREATE TABLE "PostReference"
|
|||||||
(
|
(
|
||||||
post_id TEXT REFERENCES "Post" (id),
|
post_id TEXT REFERENCES "Post" (id),
|
||||||
source_id TEXT REFERENCES "Source" (id),
|
source_id TEXT REFERENCES "Source" (id),
|
||||||
url TEXT NOT NULL,
|
url TEXT NOT NULL,
|
||||||
full_file_url TEXT,
|
full_file_url TEXT,
|
||||||
preview_file_url TEXT,
|
preview_file_url TEXT,
|
||||||
sample_file_url TEXT,
|
sample_file_url TEXT,
|
||||||
@ -79,12 +79,16 @@ CREATE TABLE "TagGroup"
|
|||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "UserFavorites"
|
||||||
|
(
|
||||||
|
user_id TEXT REFERENCES "User" (id),
|
||||||
|
post_id TEXT REFERENCES "Post" (id),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (user_id, post_id)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE "UserSource"
|
CREATE TABLE "UserSource"
|
||||||
(
|
(
|
||||||
id CHAR(25) PRIMARY KEY,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
deleted_at TIMESTAMP NULL NULL,
|
|
||||||
user_id TEXT REFERENCES "User" (id),
|
user_id TEXT REFERENCES "User" (id),
|
||||||
source_id TEXT REFERENCES "Source" (id),
|
source_id TEXT REFERENCES "Source" (id),
|
||||||
scrape_time_interval INT,
|
scrape_time_interval INT,
|
||||||
@ -93,20 +97,10 @@ CREATE TABLE "UserSource"
|
|||||||
last_scrape_time TIMESTAMP,
|
last_scrape_time TIMESTAMP,
|
||||||
account_validate BOOL DEFAULT FALSE,
|
account_validate BOOL DEFAULT FALSE,
|
||||||
account_validation_key CHAR(25),
|
account_validation_key CHAR(25),
|
||||||
|
PRIMARY KEY (user_id, source_id),
|
||||||
UNIQUE (source_id, account_username, account_id)
|
UNIQUE (source_id, account_username, account_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE "UserFavorites"
|
|
||||||
(
|
|
||||||
id CHAR(25) PRIMARY KEY,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
deleted_at TIMESTAMP NULL NULL,
|
|
||||||
user_id TEXT REFERENCES "User" (id),
|
|
||||||
post_id TEXT REFERENCES "Post" (id),
|
|
||||||
user_source_id CHAR(25) REFERENCES "UserSource" (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE "post_tags"
|
CREATE TABLE "post_tags"
|
||||||
(
|
(
|
||||||
post_id TEXT REFERENCES "Post" (id),
|
post_id TEXT REFERENCES "Post" (id),
|
||||||
|
31
pkg/database/post.go
Normal file
31
pkg/database/post.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Post interface {
|
||||||
|
|
||||||
|
// CreatePost adds a new post to the database.
|
||||||
|
CreatePost(ctx context.Context, anthrovePost *models.Post) error
|
||||||
|
|
||||||
|
// TODO: Everything
|
||||||
|
CreatePostInBatch(ctx context.Context, anthrovePost []models.Post, batchSize int) error
|
||||||
|
|
||||||
|
// GetPostByAnthroveID retrieves a post by its Anthrove ID.
|
||||||
|
GetPostByAnthroveID(ctx context.Context, anthrovePostID models.AnthrovePostID) (*models.Post, error)
|
||||||
|
|
||||||
|
// GetPostByURL retrieves a post by its source URL.
|
||||||
|
GetPostByURL(ctx context.Context, postURL string) (*models.Post, error)
|
||||||
|
|
||||||
|
// GetPostBySourceID retrieves a post by its source ID.
|
||||||
|
GetPostBySourceID(ctx context.Context, sourceID models.AnthroveSourceID) (*models.Post, error)
|
||||||
|
|
||||||
|
// CreatePostWithReferenceToTagAnd adds a tag with a relation to a post.
|
||||||
|
CreatePostWithReferenceToTagAnd(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error
|
||||||
|
|
||||||
|
// CreatePostReference links a post with a source.
|
||||||
|
CreatePostReference(ctx context.Context, anthrovePostID models.AnthrovePostID, sourceDomain models.AnthroveSourceDomain, postURL models.AnthrovePostURL, config models.PostReferenceConfig) error
|
||||||
|
}
|
268
pkg/database/postgres.go
Normal file
268
pkg/database/postgres.go
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
log2 "log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/internal/postgres"
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
migrate "github.com/rubenv/sql-migrate"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
gormPostgres "gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
gormLogger "gorm.io/gorm/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed migrations/*.sql
|
||||||
|
var embedMigrations embed.FS
|
||||||
|
|
||||||
|
type postgresqlConnection struct {
|
||||||
|
db *gorm.DB
|
||||||
|
debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPostgresqlConnection() OtterSpace {
|
||||||
|
return &postgresqlConnection{
|
||||||
|
db: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) Connect(_ context.Context, config models.DatabaseConfig) error {
|
||||||
|
var localSSL string
|
||||||
|
var logLevel gormLogger.LogLevel
|
||||||
|
|
||||||
|
if config.SSL {
|
||||||
|
localSSL = "require"
|
||||||
|
} else {
|
||||||
|
localSSL = "disable"
|
||||||
|
}
|
||||||
|
|
||||||
|
p.debug = config.Debug
|
||||||
|
|
||||||
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=%s", config.Endpoint, config.Username, config.Password, config.Database, config.Port, localSSL, config.Timezone)
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if p.debug {
|
||||||
|
logLevel = gormLogger.Info
|
||||||
|
} else {
|
||||||
|
logLevel = gormLogger.Silent
|
||||||
|
}
|
||||||
|
|
||||||
|
dbLogger := gormLogger.New(log2.New(os.Stdout, "\r\n", log2.LstdFlags), gormLogger.Config{
|
||||||
|
SlowThreshold: 200 * time.Millisecond,
|
||||||
|
LogLevel: logLevel,
|
||||||
|
IgnoreRecordNotFoundError: true,
|
||||||
|
Colorful: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
db, err := gorm.Open(gormPostgres.Open(dsn), &gorm.Config{
|
||||||
|
Logger: dbLogger,
|
||||||
|
})
|
||||||
|
p.db = db
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("OtterSpace: database connection established")
|
||||||
|
|
||||||
|
err = p.migrateDatabase(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("OtterSpace: migration compleate")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, accountId string, accountUsername string) error {
|
||||||
|
return postgres.CreateUserWithRelationToSource(ctx, p.db, anthroveUserID, sourceID, accountId, accountUsername)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateSource(ctx context.Context, anthroveSource *models.Source) error {
|
||||||
|
return postgres.CreateSource(ctx, p.db, anthroveSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreatePost(ctx context.Context, anthrovePost *models.Post) error {
|
||||||
|
return postgres.CreatePost(ctx, p.db, anthrovePost)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreatePostInBatch(ctx context.Context, anthrovePost []models.Post, batchSize int) error {
|
||||||
|
return postgres.CreatePostInBatch(ctx, p.db, anthrovePost, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreatePostWithReferenceToTagAnd(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error {
|
||||||
|
return postgres.CreateTagAndReferenceToPost(ctx, p.db, anthrovePostID, anthroveTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreatePostReference(ctx context.Context, anthrovePostID models.AnthrovePostID, sourceDomain models.AnthroveSourceDomain, postURL models.AnthrovePostURL, config models.PostReferenceConfig) error {
|
||||||
|
return postgres.CreateReferenceBetweenPostAndSource(ctx, p.db, anthrovePostID, sourceDomain, postURL, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateReferenceBetweenUserAndPost(ctx context.Context, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) error {
|
||||||
|
return postgres.CreateReferenceBetweenUserAndPost(ctx, p.db, anthroveUserID, anthrovePostID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CheckIfUserHasPostAsFavorite(ctx context.Context, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) (bool, error) {
|
||||||
|
return postgres.CheckReferenceBetweenUserAndPost(ctx, p.db, anthroveUserID, anthrovePostID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetPostByAnthroveID(ctx context.Context, anthrovePostID models.AnthrovePostID) (*models.Post, error) {
|
||||||
|
return postgres.GetPostByAnthroveID(ctx, p.db, anthrovePostID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetPostByURL(ctx context.Context, sourceUrl string) (*models.Post, error) {
|
||||||
|
return postgres.GetPostBySourceURL(ctx, p.db, sourceUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetPostBySourceID(ctx context.Context, sourceID models.AnthroveSourceID) (*models.Post, error) {
|
||||||
|
return postgres.GetPostBySourceID(ctx, p.db, sourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetUserFavoritesCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error) {
|
||||||
|
return postgres.GetUserFavoritesCount(ctx, p.db, anthroveUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllUserSources(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
|
||||||
|
return postgres.GetUserSourceLinks(ctx, p.db, anthroveUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetUserSourceBySourceID(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID) (*models.UserSource, error) {
|
||||||
|
return postgres.GetUserSourceBySourceID(ctx, p.db, anthroveUserID, sourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllUsers(ctx context.Context) ([]models.User, error) {
|
||||||
|
return postgres.GetAllUsers(ctx, p.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllUserFavoritesWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error) {
|
||||||
|
return postgres.GetUserFavoriteWithPagination(ctx, p.db, anthroveUserID, skip, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagsFromUser(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) {
|
||||||
|
return postgres.GetUserTagWitRelationToFavedPosts(ctx, p.db, anthroveUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTags(ctx context.Context) ([]models.Tag, error) {
|
||||||
|
return postgres.GetTags(ctx, p.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllSources(ctx context.Context) ([]models.Source, error) {
|
||||||
|
return postgres.GetAllSource(ctx, p.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetSourceByDomain(ctx context.Context, sourceDomain models.AnthroveSourceDomain) (*models.Source, error) {
|
||||||
|
return postgres.GetSourceByDomain(ctx, p.db, sourceDomain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) UpdateUserSourceScrapeTimeInterval(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, scrapeTime models.AnthroveScrapeTimeInterval) error {
|
||||||
|
return postgres.UpdateUserSourceScrapeTimeInterval(ctx, p.db, anthroveUserID, sourceID, scrapeTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) UpdateUserSourceLastScrapeTime(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, lastScrapeTime models.AnthroveUserLastScrapeTime) error {
|
||||||
|
return postgres.UpdateUserSourceLastScrapeTime(ctx, p.db, anthroveUserID, sourceID, lastScrapeTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) UpdateUserSourceValidation(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, valid bool) error {
|
||||||
|
return postgres.UpdateUserSourceValidation(ctx, p.db, anthroveUserID, sourceID, valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTagAlias(ctx context.Context, tagAliasName models.AnthroveTagAliasName, tagID models.AnthroveTagID) error {
|
||||||
|
return postgres.CreateTagAlias(ctx, p.db, tagAliasName, tagID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagAlias(ctx context.Context) ([]models.TagAlias, error) {
|
||||||
|
return postgres.GetAllTagAlias(ctx, p.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagAliasByTag(ctx context.Context, tagID models.AnthroveTagID) ([]models.TagAlias, error) {
|
||||||
|
return postgres.GetAllTagAliasByTag(ctx, p.db, tagID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) DeleteTagAlias(ctx context.Context, tagAliasName models.AnthroveTagAliasName) error {
|
||||||
|
return postgres.DeleteTagAlias(ctx, p.db, tagAliasName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTagGroup(ctx context.Context, tagGroupName models.AnthroveTagGroupName, tagID models.AnthroveTagID) error {
|
||||||
|
return postgres.CreateTagGroup(ctx, p.db, tagGroupName, tagID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagGroup(ctx context.Context) ([]models.TagGroup, error) {
|
||||||
|
return postgres.GetAllTagGroup(ctx, p.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagGroupByTag(ctx context.Context, tagID models.AnthroveTagID) ([]models.TagGroup, error) {
|
||||||
|
return postgres.GetAllTagGroupByTag(ctx, p.db, tagID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) DeleteTagGroup(ctx context.Context, tagGroupName models.AnthroveTagGroupName) error {
|
||||||
|
return postgres.DeleteTagGroup(ctx, p.db, tagGroupName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTag(ctx context.Context, tagName models.AnthroveTagName, tagType models.TagType) error {
|
||||||
|
return postgres.CreateTag(ctx, p.db, tagName, tagType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) GetAllTagsByTagType(ctx context.Context, tagType models.TagType) ([]models.Tag, error) {
|
||||||
|
return postgres.GetAllTagByTagsType(ctx, p.db, tagType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) DeleteTag(ctx context.Context, tagName models.AnthroveTagName) error {
|
||||||
|
return postgres.DeleteTag(ctx, p.db, tagName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTagInBatchAndUpdate(ctx context.Context, tags []models.Tag, batchSize int) error {
|
||||||
|
return postgres.CreateTagInBatchAndUpdate(ctx, p.db, tags, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTagAliasInBatch(ctx context.Context, tagAliases []models.TagAlias, batchSize int) error {
|
||||||
|
return postgres.CreateTagAliasInBatch(ctx, p.db, tagAliases, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) CreateTagGroupInBatch(ctx context.Context, tagGroups []models.TagGroup, batchSize int) error {
|
||||||
|
return postgres.CreateTagGroupInBatch(ctx, p.db, tagGroups, batchSize)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) ExecuteRawStatement(ctx context.Context, query string, args ...any) error {
|
||||||
|
return postgres.ExecuteRawStatement(ctx, p.db, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) QueryRawStatement(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
|
||||||
|
return postgres.QueryRawStatement(ctx, p.db, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HELPER
|
||||||
|
|
||||||
|
func (p *postgresqlConnection) migrateDatabase(dbPool *gorm.DB) error {
|
||||||
|
dialect := "postgres"
|
||||||
|
migrations := &migrate.EmbedFileSystemMigrationSource{FileSystem: embedMigrations, Root: "migrations"}
|
||||||
|
|
||||||
|
db, err := dbPool.DB()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("postgres migration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := migrate.Exec(db, dialect, migrations, migrate.Up)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("postgres migration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.debug {
|
||||||
|
if n != 0 {
|
||||||
|
log.Infof("postgres migration: applied %d migrations!", n)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.Info("postgres migration: nothing to migrate")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
3791
pkg/database/postgres_test.go
Normal file
3791
pkg/database/postgres_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,107 +2,18 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
|
||||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateUserSource(ctx context.Context, userSource models.UserSource) (models.UserSource, error) {
|
type Source interface {
|
||||||
if client == nil {
|
|
||||||
return models.UserSource{}, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := client.WithContext(ctx).Create(&userSource)
|
// CreateSource adds a new source to the database.
|
||||||
if result.Error != nil {
|
CreateSource(ctx context.Context, anthroveSource *models.Source) error
|
||||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
|
||||||
return models.UserSource{}, &otterError.Database{Reason: otterError.DuplicateKey}
|
|
||||||
}
|
|
||||||
return models.UserSource{}, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return userSource, nil
|
// GetAllSources retrieves all sources.
|
||||||
}
|
GetAllSources(ctx context.Context) ([]models.Source, error)
|
||||||
|
|
||||||
func UpdateUserSource(ctx context.Context, userSource models.UserSource) error {
|
// GetSourceByDomain retrieves a source by its URL.
|
||||||
if client == nil {
|
GetSourceByDomain(ctx context.Context, sourceDomain models.AnthroveSourceDomain) (*models.Source, error)
|
||||||
return &otterError.Database{Reason: otterError.DatabaseIsNotConnected}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(userSource.ID) == 0 {
|
|
||||||
return &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDEmpty}
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedUserSource := models.UserSource{
|
|
||||||
BaseModel: models.BaseModel[models.UserSourceID]{
|
|
||||||
ID: userSource.ID,
|
|
||||||
},
|
|
||||||
ScrapeTimeInterval: userSource.ScrapeTimeInterval,
|
|
||||||
AccountUsername: userSource.AccountUsername,
|
|
||||||
AccountID: userSource.AccountID,
|
|
||||||
LastScrapeTime: userSource.LastScrapeTime,
|
|
||||||
AccountValidate: userSource.AccountValidate,
|
|
||||||
}
|
|
||||||
|
|
||||||
result := client.WithContext(ctx).Updates(&updatedUserSource)
|
|
||||||
if result.Error != nil {
|
|
||||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
|
||||||
return &otterError.Database{Reason: otterError.DuplicateKey}
|
|
||||||
}
|
|
||||||
return result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserSourceByID(ctx context.Context, id models.UserSourceID) (models.UserSource, error) {
|
|
||||||
var user models.UserSource
|
|
||||||
|
|
||||||
if client == nil {
|
|
||||||
return models.UserSource{}, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(id) == 0 {
|
|
||||||
return models.UserSource{}, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDEmpty}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(id) != 25 {
|
|
||||||
return models.UserSource{}, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDToShort}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := client.WithContext(ctx).First(&user, id)
|
|
||||||
if result.Error != nil {
|
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
|
||||||
return models.UserSource{}, &otterError.Database{Reason: otterError.NoDataFound}
|
|
||||||
}
|
|
||||||
return models.UserSource{}, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteUserSource(ctx context.Context, id models.UserSourceID) error {
|
|
||||||
var user models.UserSource
|
|
||||||
|
|
||||||
if client == nil {
|
|
||||||
return &otterError.Database{Reason: otterError.DatabaseIsNotConnected}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(id) == 0 {
|
|
||||||
return &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDEmpty}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(id) != 25 {
|
|
||||||
return &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDToShort}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := client.WithContext(ctx).Delete(&user, id)
|
|
||||||
if result.Error != nil {
|
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
|
||||||
return &otterError.Database{Reason: otterError.NoDataFound}
|
|
||||||
}
|
|
||||||
return result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
20
pkg/database/tag.go
Normal file
20
pkg/database/tag.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tag interface {
|
||||||
|
CreateTag(ctx context.Context, tagName models.AnthroveTagName, tagType models.TagType) error
|
||||||
|
|
||||||
|
CreateTagInBatchAndUpdate(ctx context.Context, tags []models.Tag, batchSize int) error
|
||||||
|
|
||||||
|
// GetAllTags retrieves all tags.
|
||||||
|
GetAllTags(ctx context.Context) ([]models.Tag, error)
|
||||||
|
|
||||||
|
GetAllTagsByTagType(ctx context.Context, tagType models.TagType) ([]models.Tag, error)
|
||||||
|
|
||||||
|
DeleteTag(ctx context.Context, tagName models.AnthroveTagName) error
|
||||||
|
}
|
19
pkg/database/tagalias.go
Normal file
19
pkg/database/tagalias.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TagAlias interface {
|
||||||
|
CreateTagAlias(ctx context.Context, tagAliasName models.AnthroveTagAliasName, tagID models.AnthroveTagID) error
|
||||||
|
|
||||||
|
CreateTagAliasInBatch(ctx context.Context, tagsAliases []models.TagAlias, batchSize int) error
|
||||||
|
|
||||||
|
GetAllTagAlias(ctx context.Context) ([]models.TagAlias, error)
|
||||||
|
|
||||||
|
GetAllTagAliasByTag(ctx context.Context, tagID models.AnthroveTagID) ([]models.TagAlias, error)
|
||||||
|
|
||||||
|
DeleteTagAlias(ctx context.Context, tagAliasName models.AnthroveTagAliasName) error
|
||||||
|
}
|
19
pkg/database/taggroup.go
Normal file
19
pkg/database/taggroup.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TagGroup interface {
|
||||||
|
CreateTagGroup(ctx context.Context, tagGroupName models.AnthroveTagGroupName, tagID models.AnthroveTagID) error
|
||||||
|
|
||||||
|
CreateTagGroupInBatch(ctx context.Context, tagsGroups []models.TagGroup, batchSize int) error
|
||||||
|
|
||||||
|
GetAllTagGroup(ctx context.Context) ([]models.TagGroup, error)
|
||||||
|
|
||||||
|
GetAllTagGroupByTag(ctx context.Context, tagID models.AnthroveTagID) ([]models.TagGroup, error)
|
||||||
|
|
||||||
|
DeleteTagGroup(ctx context.Context, tagGroupName models.AnthroveTagGroupName) error
|
||||||
|
}
|
42
pkg/database/user.go
Normal file
42
pkg/database/user.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User interface {
|
||||||
|
|
||||||
|
// CreateUserWithRelationToSource adds a user with a relation to a source.
|
||||||
|
CreateUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, accountId string, accountUsername string) error
|
||||||
|
|
||||||
|
// CreateReferenceBetweenUserAndPost links a user with a post.
|
||||||
|
CreateReferenceBetweenUserAndPost(ctx context.Context, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) error
|
||||||
|
|
||||||
|
UpdateUserSourceScrapeTimeInterval(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, scrapeTime models.AnthroveScrapeTimeInterval) error
|
||||||
|
|
||||||
|
UpdateUserSourceLastScrapeTime(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, lastScrapeTime models.AnthroveUserLastScrapeTime) error
|
||||||
|
|
||||||
|
UpdateUserSourceValidation(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, valid bool) error
|
||||||
|
|
||||||
|
GetAllUsers(ctx context.Context) ([]models.User, error)
|
||||||
|
|
||||||
|
// GetUserFavoritesCount retrieves the count of a user's favorites.
|
||||||
|
GetUserFavoritesCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error)
|
||||||
|
|
||||||
|
// GetAllUserSources retrieves the source links of a user.
|
||||||
|
GetAllUserSources(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error)
|
||||||
|
|
||||||
|
// GetUserSourceBySourceID retrieves a specified source link of a user.
|
||||||
|
GetUserSourceBySourceID(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID) (*models.UserSource, error)
|
||||||
|
|
||||||
|
// GetAllUserFavoritesWithPagination retrieves a user's favorite posts with pagination.
|
||||||
|
GetAllUserFavoritesWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error)
|
||||||
|
|
||||||
|
// GetAllTagsFromUser retrieves a user's tags through their favorite posts.
|
||||||
|
GetAllTagsFromUser(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error)
|
||||||
|
|
||||||
|
// CheckIfUserHasPostAsFavorite checks if a user-post link exists.
|
||||||
|
CheckIfUserHasPostAsFavorite(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID models.AnthrovePostID) (bool, error)
|
||||||
|
}
|
@ -1,19 +1,25 @@
|
|||||||
package error
|
package error
|
||||||
|
|
||||||
import "fmt"
|
type EntityAlreadyExists struct{}
|
||||||
|
|
||||||
const (
|
func (e *EntityAlreadyExists) Error() string {
|
||||||
EntityAlreadyExists = "EntityAlreadyExists"
|
return "EntityAlreadyExists error"
|
||||||
NoDataWritten = "NoDataWritten"
|
|
||||||
NoDataFound = "NoDataFound"
|
|
||||||
DatabaseIsNotConnected = "database is not connected"
|
|
||||||
DuplicateKey = "DuplicateKey"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Database struct {
|
|
||||||
Reason string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Database) Error() string {
|
type NoDataWritten struct{}
|
||||||
return fmt.Sprintf("Database error: %s", e.Reason)
|
|
||||||
|
func (e *NoDataWritten) Error() string {
|
||||||
|
return "NoDataWritten error"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NoDataFound struct{}
|
||||||
|
|
||||||
|
func (e *NoDataFound) Error() string {
|
||||||
|
return "NoDataFound error"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NoRelationCreated struct{}
|
||||||
|
|
||||||
|
func (e *NoRelationCreated) Error() string {
|
||||||
|
return "relationship creation error"
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,11 @@ package error
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UserIDIsEmpty = "anthrovePostID cannot be empty"
|
AnthroveUserIDIsEmpty = "anthrovePostID cannot be empty"
|
||||||
UserIDToShort = "anthrovePostID needs to be 25 characters long"
|
AnthroveUserIDToShort = "anthrovePostID needs to be 25 characters long"
|
||||||
SourceIDEmpty = "anthroveSourceID cannot be empty"
|
AnthroveSourceIDEmpty = "anthroveSourceID cannot be empty"
|
||||||
SourceIDToShort = "anthroveSourceID needs to be 25 characters long"
|
AnthroveSourceIDToShort = "anthroveSourceID needs to be 25 characters long"
|
||||||
UserSourceIDEmpty = "anthroveUserSourceID cannot be empty"
|
AnthroveTagIDEmpty = "tagID cannot be empty"
|
||||||
UserSourceIDToShort = "anthroveUserSourceID needs to be 25 characters long"
|
|
||||||
TagIDEmpty = "tagID cannot be empty"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type EntityValidationFailed struct {
|
type EntityValidationFailed struct {
|
||||||
|
@ -2,25 +2,20 @@ package models
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type (
|
type AnthroveUserID string
|
||||||
UserID string
|
type AnthrovePostID string
|
||||||
PostID string
|
type AnthroveSourceID string
|
||||||
SourceID string
|
type AnthroveSourceDomain string
|
||||||
SourceDomain string
|
type AnthrovePostURL string
|
||||||
PostURL string
|
type AnthroveTagGroupName string
|
||||||
TagGroupName string
|
type AnthroveTagAliasName string
|
||||||
TagAliasName string
|
type AnthroveTagID string
|
||||||
TagID string
|
type AnthroveScrapeTimeInterval int
|
||||||
ScrapeTimeInterval int
|
type AnthroveUserLastScrapeTime time.Time
|
||||||
UserLastScrapeTime time.Time
|
type AnthroveTagName string
|
||||||
TagName string
|
|
||||||
|
|
||||||
Rating string
|
type Rating string
|
||||||
TagType string
|
type TagType string
|
||||||
|
|
||||||
UserSourceID string
|
|
||||||
UserFavoriteID string
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SFW Rating = "safe"
|
SFW Rating = "safe"
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ID interface {
|
type ID interface {
|
||||||
UserID | SourceID | PostID | UserSourceID | UserFavoriteID
|
AnthroveUserID | AnthroveSourceID | AnthrovePostID
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseModel[T ID] struct {
|
type BaseModel[T ID] struct {
|
||||||
|
@ -42,8 +42,8 @@ func TestBaseModel_BeforeCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
base := &BaseModel[PostID]{
|
base := &BaseModel[AnthrovePostID]{
|
||||||
ID: PostID(tt.fields.ID),
|
ID: AnthrovePostID(tt.fields.ID),
|
||||||
CreatedAt: tt.fields.CreatedAt,
|
CreatedAt: tt.fields.CreatedAt,
|
||||||
UpdatedAt: tt.fields.UpdatedAt,
|
UpdatedAt: tt.fields.UpdatedAt,
|
||||||
DeletedAt: tt.fields.DeletedAt,
|
DeletedAt: tt.fields.DeletedAt,
|
||||||
|
@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
// Post model
|
// Post model
|
||||||
type Post struct {
|
type Post struct {
|
||||||
BaseModel[PostID]
|
BaseModel[AnthrovePostID]
|
||||||
Rating Rating `json:"rating" gorm:"type:enum('safe','questionable','explicit')"`
|
Rating Rating `json:"rating" gorm:"type:enum('safe','questionable','explicit')"`
|
||||||
Tags []Tag `json:"-" gorm:"many2many:post_tags;"`
|
Tags []Tag `json:"-" gorm:"many2many:post_tags;"`
|
||||||
Favorites []UserFavorites `json:"-" gorm:"foreignKey:PostID"`
|
Favorites []UserFavorites `json:"-" gorm:"foreignKey:PostID"`
|
||||||
|
@ -4,7 +4,7 @@ import "testing"
|
|||||||
|
|
||||||
func TestPost_TableName(t *testing.T) {
|
func TestPost_TableName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
BaseModel BaseModel[PostID]
|
BaseModel BaseModel[AnthrovePostID]
|
||||||
Rating Rating
|
Rating Rating
|
||||||
Tags []Tag
|
Tags []Tag
|
||||||
Favorites []UserFavorites
|
Favorites []UserFavorites
|
||||||
|
@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
// Source model
|
// Source model
|
||||||
type Source struct {
|
type Source struct {
|
||||||
BaseModel[SourceID]
|
BaseModel[AnthroveSourceID]
|
||||||
DisplayName string `json:"display_name" `
|
DisplayName string `json:"display_name" `
|
||||||
Domain string `json:"domain" gorm:"not null;unique"`
|
Domain string `json:"domain" gorm:"not null;unique"`
|
||||||
Icon string `json:"icon" gorm:"not null"`
|
Icon string `json:"icon" gorm:"not null"`
|
||||||
|
@ -4,7 +4,7 @@ import "testing"
|
|||||||
|
|
||||||
func TestSource_TableName(t *testing.T) {
|
func TestSource_TableName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
BaseModel BaseModel[SourceID]
|
BaseModel BaseModel[AnthroveSourceID]
|
||||||
DisplayName string
|
DisplayName string
|
||||||
Domain string
|
Domain string
|
||||||
Icon string
|
Icon string
|
||||||
|
@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
// User model
|
// User model
|
||||||
type User struct {
|
type User struct {
|
||||||
BaseModel[UserID]
|
BaseModel[AnthroveUserID]
|
||||||
Favorites []UserFavorites `json:"-" gorm:"foreignKey:UserID"`
|
Favorites []UserFavorites `json:"-" gorm:"foreignKey:UserID"`
|
||||||
Sources []UserSource `json:"-" gorm:"foreignKey:UserID"`
|
Sources []UserSource `json:"-" gorm:"foreignKey:UserID"`
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,9 @@ package models
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type UserFavorites struct {
|
type UserFavorites struct {
|
||||||
BaseModel[UserFavoriteID]
|
UserID string `json:"user_id" gorm:"primaryKey"`
|
||||||
UserID string `json:"user_id"`
|
PostID string `json:"post_id" gorm:"primaryKey"`
|
||||||
PostID string `json:"post_id"`
|
CreatedAt time.Time `json:"-"`
|
||||||
UserSourceID UserSourceID `json:"user_source_id"`
|
|
||||||
UserSource UserSource `json:"-" gorm:"foreignKey:ID;references:UserSourceID"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (UserFavorites) TableName() string {
|
func (UserFavorites) TableName() string {
|
||||||
|
@ -3,11 +3,10 @@ package models
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type UserSource struct {
|
type UserSource struct {
|
||||||
BaseModel[UserSourceID]
|
|
||||||
User User `json:"user" gorm:"foreignKey:ID;references:UserID"`
|
User User `json:"user" gorm:"foreignKey:ID;references:UserID"`
|
||||||
UserID UserID `json:"user_id"`
|
UserID string `json:"user_id" gorm:"primaryKey"`
|
||||||
Source Source `json:"source" gorm:"foreignKey:ID;references:SourceID"`
|
Source Source `json:"source" gorm:"foreignKey:ID;references:SourceID"`
|
||||||
SourceID SourceID `json:"source_id"`
|
SourceID string `json:"source_id" gorm:"primaryKey"`
|
||||||
ScrapeTimeInterval string `json:"scrape_time_interval"`
|
ScrapeTimeInterval string `json:"scrape_time_interval"`
|
||||||
AccountUsername string `json:"account_username"`
|
AccountUsername string `json:"account_username"`
|
||||||
AccountID string `json:"account_id"`
|
AccountID string `json:"account_id"`
|
||||||
|
@ -5,9 +5,9 @@ import "testing"
|
|||||||
func TestUserSource_TableName(t *testing.T) {
|
func TestUserSource_TableName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
User User
|
User User
|
||||||
UserID UserID
|
UserID string
|
||||||
Source Source
|
Source Source
|
||||||
SourceID SourceID
|
SourceID string
|
||||||
ScrapeTimeInterval string
|
ScrapeTimeInterval string
|
||||||
AccountUsername string
|
AccountUsername string
|
||||||
AccountID string
|
AccountID string
|
||||||
|
@ -4,7 +4,7 @@ import "testing"
|
|||||||
|
|
||||||
func TestUser_TableName(t *testing.T) {
|
func TestUser_TableName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
BaseModel BaseModel[UserID]
|
BaseModel BaseModel[AnthroveUserID]
|
||||||
Favorites []UserFavorites
|
Favorites []UserFavorites
|
||||||
Sources []UserSource
|
Sources []UserSource
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user