SDK v3 #8
@ -1,42 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func ExecuteRawStatement(ctx context.Context, db *gorm.DB, query string, args ...any) error {
|
||||
if query == "" {
|
||||
return errors.New("query can not be empty")
|
||||
}
|
||||
|
||||
if args == nil {
|
||||
return errors.New("arguments can not be nil")
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Exec(query, args...)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func QueryRawStatement(ctx context.Context, db *gorm.DB, query string, args ...any) (*sql.Rows, error) {
|
||||
if query == "" {
|
||||
return nil, errors.New("query can not be empty")
|
||||
}
|
||||
|
||||
if args == nil {
|
||||
return nil, errors.New("arguments can not be nil")
|
||||
}
|
||||
|
||||
result, err := db.WithContext(ctx).Raw(query, args...).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/test"
|
||||
"gorm.io/gorm"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExecuteRawStatement(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
query string
|
||||
args []any
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *sql.Rows
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 01: Empty Query",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
query: "",
|
||||
args: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 02: Nil Query",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
query: "aasd",
|
||||
args: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ExecuteRawStatement(tt.args.ctx, tt.args.db, tt.args.query, tt.args.args...)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ExecuteRawStatement() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryRawStatement(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
query string
|
||||
args []any
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *sql.Rows
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 01: Empty Query",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
query: "",
|
||||
args: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 02: Nil Query",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
query: "aasd",
|
||||
args: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := QueryRawStatement(tt.args.ctx, tt.args.db, tt.args.query, tt.args.args...)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("QueryRawStatement() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("QueryRawStatement() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
||||
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreatePost(ctx context.Context, db *gorm.DB, anthrovePost *models.Post) error {
|
||||
|
||||
if anthrovePost == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthrovePost is nil"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Create(&anthrovePost)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_post_id": anthrovePost.ID,
|
||||
"anthrove_post_rating": anthrovePost.Rating,
|
||||
}).Trace("database: created anthrove post")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreatePostInBatch(ctx context.Context, db *gorm.DB, anthrovePost []models.Post, batchSize int) error {
|
||||
if anthrovePost == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthrovePost cannot be nil"}
|
||||
}
|
||||
|
||||
if len(anthrovePost) == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthrovePost cannot be empty"}
|
||||
}
|
||||
|
||||
if batchSize == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "batch size cannot be zero"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).CreateInBatches(anthrovePost, batchSize)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_size": len(anthrovePost),
|
||||
"batch_size": batchSize,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPostByAnthroveID(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID) (*models.Post, error) {
|
||||
|
||||
if anthrovePostID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "anthrovePostID is not set"}
|
||||
}
|
||||
|
||||
if len(anthrovePostID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"}
|
||||
}
|
||||
|
||||
var post models.Post
|
||||
result := db.WithContext(ctx).First(&post, "id = ?", anthrovePostID)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
return &post, nil
|
||||
}
|
||||
|
||||
func GetPostBySourceURL(ctx context.Context, db *gorm.DB, sourceURL string) (*models.Post, error) {
|
||||
|
||||
if sourceURL == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "sourceURL is not set"}
|
||||
}
|
||||
|
||||
var post models.Post
|
||||
result := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.url = $1 LIMIT 1`, sourceURL).First(&post)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
return &post, nil
|
||||
}
|
||||
|
||||
func GetPostBySourceID(ctx context.Context, db *gorm.DB, sourceID models.AnthroveSourceID) (*models.Post, error) {
|
||||
|
||||
if sourceID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "sourceID is not set"}
|
||||
}
|
||||
|
||||
var post models.Post
|
||||
result := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.source_id = $1 LIMIT 1`, sourceID).First(&post)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
return &post, nil
|
||||
}
|
@ -1,469 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/test"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestCreateAnthrovePostNode(t *testing.T) {
|
||||
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Tests
|
||||
|
||||
validPost := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: models.AnthrovePostID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
invalidPost := &models.Post{
|
||||
Rating: "error",
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthrovePost *models.Post
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid AnthrovePostID and Rating",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
db: gormDB,
|
||||
anthrovePost: validPost,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Invalid Rating",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
db: gormDB,
|
||||
anthrovePost: invalidPost,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: Nill",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
db: gormDB,
|
||||
anthrovePost: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := CreatePost(tt.args.ctx, tt.args.db, tt.args.anthrovePost); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CreatePost() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPostByAnthroveID(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Tests
|
||||
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: models.AnthrovePostID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal("Could not create post", err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthrovePostID models.AnthrovePostID
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Post
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid anthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
want: post,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Invalid anthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePostID: "1234",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: No anthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePostID: "",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetPostByAnthroveID(tt.args.ctx, tt.args.db, tt.args.anthrovePostID)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetPostByAnthroveID() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !checkPost(got, tt.want) {
|
||||
t.Errorf("GetPostByAnthroveID() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPostBySourceURL(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Tests
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: models.AnthrovePostID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal("Could not create post", err)
|
||||
}
|
||||
|
||||
source := models.Source{
|
||||
BaseModel: models.BaseModel[models.AnthroveSourceID]{
|
||||
ID: models.AnthroveSourceID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
DisplayName: "e621",
|
||||
Domain: "e621.net",
|
||||
Icon: "https://e621.net/icon.ico",
|
||||
}
|
||||
|
||||
err = CreateSource(ctx, gormDB, &source)
|
||||
if err != nil {
|
||||
t.Fatal("Could not create source", err)
|
||||
}
|
||||
|
||||
err = CreateReferenceBetweenPostAndSource(ctx, gormDB, post.ID, models.AnthroveSourceDomain(source.Domain), "http://test.org", models.PostReferenceConfig{})
|
||||
if err != nil {
|
||||
t.Fatal("Could not create source reference", err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
sourceURL string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Post
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid sourceURL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceURL: "http://test.org",
|
||||
},
|
||||
want: post,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Invalid sourceURL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceURL: "1234",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: No sourceURL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceURL: "",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetPostBySourceURL(tt.args.ctx, tt.args.db, tt.args.sourceURL)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetPostBySourceURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !checkPost(got, tt.want) {
|
||||
t.Errorf("GetPostBySourceURL() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPostBySourceID(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Tests
|
||||
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: models.AnthrovePostID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal("Could not create post", err)
|
||||
}
|
||||
|
||||
source := models.Source{
|
||||
BaseModel: models.BaseModel[models.AnthroveSourceID]{
|
||||
ID: models.AnthroveSourceID(fmt.Sprintf("%025s", "1")),
|
||||
},
|
||||
DisplayName: "e621",
|
||||
Domain: "e621.net",
|
||||
Icon: "https://e621.net/icon.ico",
|
||||
}
|
||||
|
||||
err = CreateSource(ctx, gormDB, &source)
|
||||
if err != nil {
|
||||
t.Fatal("Could not create source", err)
|
||||
}
|
||||
|
||||
err = CreateReferenceBetweenPostAndSource(ctx, gormDB, post.ID, models.AnthroveSourceDomain(source.Domain), "http://test.otg", models.PostReferenceConfig{})
|
||||
if err != nil {
|
||||
t.Fatal("Could not create source reference", err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
sourceID models.AnthroveSourceID
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Post
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid sourceID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceID: source.ID,
|
||||
},
|
||||
want: post,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Invalid sourceID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceID: "1234",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: No sourceID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
sourceID: "",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetPostBySourceID(tt.args.ctx, tt.args.db, tt.args.sourceID)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetPostBySourceID() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !checkPost(got, tt.want) {
|
||||
t.Errorf("GetPostBySourceID() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreatePostInBatch(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Tests
|
||||
|
||||
validPosts := []models.Post{
|
||||
{
|
||||
Rating: models.SFW,
|
||||
},
|
||||
{
|
||||
Rating: models.NSFW,
|
||||
},
|
||||
{
|
||||
Rating: models.Questionable,
|
||||
},
|
||||
}
|
||||
|
||||
emptyPost := []models.Post{}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthrovePost []models.Post
|
||||
batchSize int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid Data",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePost: validPosts,
|
||||
batchSize: len(validPosts),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Emtpy Data",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePost: emptyPost,
|
||||
batchSize: 0,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: Nil Data",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePost: nil,
|
||||
batchSize: 0,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 4: batchSize 0",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthrovePost: validPosts,
|
||||
batchSize: 0,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := CreatePostInBatch(tt.args.ctx, tt.args.db, tt.args.anthrovePost, tt.args.batchSize); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CreatePostInBatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func checkPost(got *models.Post, want *models.Post) bool {
|
||||
|
||||
if got == nil && want == nil {
|
||||
return true
|
||||
} else if got == nil || want == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if got.ID != want.ID {
|
||||
return false
|
||||
}
|
||||
|
||||
if got.Rating != want.Rating {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateReferenceBetweenPostAndSource(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, sourceDomain models.AnthroveSourceDomain, postURL models.AnthrovePostURL, config models.PostReferenceConfig) error {
|
||||
if anthrovePostID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthrovePostID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if sourceDomain == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "sourceDomain cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Exec(`INSERT INTO "PostReference" (post_id, source_id, url, full_file_url, preview_file_url, sample_file_url, source_post_id) SELECT $1, source.id, $2, $4, $5, $6, $7 FROM "Source" AS source WHERE domain = $3;`, anthrovePostID, postURL, sourceDomain, config.FullFileURL, config.PreviewFileURL, config.SampleFileURL, config.SourcePostID)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return &otterError.NoDataFound{}
|
||||
}
|
||||
if errors.Is(result.Error, gorm.ErrCheckConstraintViolated) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_post_id": anthrovePostID,
|
||||
"anthrove_source_domain": sourceDomain,
|
||||
}).Trace("database: created anthrove post to source link")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateReferenceBetweenUserAndPost(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) error {
|
||||
|
||||
if anthrovePostID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthrovePostID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"}
|
||||
}
|
||||
|
||||
userFavorite := models.UserFavorite{
|
||||
UserID: string(anthroveUserID),
|
||||
PostID: string(anthrovePostID),
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Create(&userFavorite)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"anthrove_post_id": anthrovePostID,
|
||||
}).Trace("database: created user to post link")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckReferenceBetweenUserAndPost(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) (bool, error) {
|
||||
var count int64
|
||||
|
||||
if anthrovePostID == "" {
|
||||
return false, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthrovePostID) != 25 {
|
||||
return false, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return false, &otterError.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return false, &otterError.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ? AND post_id = ?", string(anthroveUserID), string(anthrovePostID)).Count(&count)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return false, &otterError.NoDataFound{}
|
||||
}
|
||||
return false, result.Error
|
||||
}
|
||||
|
||||
exists := count > 0
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"relationship_exists": exists,
|
||||
"relationship_anthrove_user_id": anthroveUserID,
|
||||
"relationship_anthrove_post_id": anthrovePostID,
|
||||
}).Trace("database: checked user post relationship")
|
||||
|
||||
return exists, nil
|
||||
}
|
@ -1,392 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/test"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestCheckUserToPostLink(t *testing.T) {
|
||||
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
validUserID := models.AnthroveUserID(fmt.Sprintf("%025s", "User1"))
|
||||
invalidUserID := models.AnthroveUserID("XXX")
|
||||
|
||||
validPostID := models.AnthrovePostID(fmt.Sprintf("%025s", "Post1"))
|
||||
|
||||
err = CreateUser(ctx, gormDB, validUserID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: validPostID,
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = CreateReferenceBetweenUserAndPost(ctx, gormDB, validUserID, post.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthroveUserID models.AnthroveUserID
|
||||
anthrovePostID models.AnthrovePostID
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid AnthroveUserID and AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Valid AnthroveUserID and invalid AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: "qadw",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: Valid AnthrovePostID and invalid AnthroveUserID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 4: Invalid AnthrovePostID and invalid AnthroveUserID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 5: No AnthrovePostID given",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: "",
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 6: No anthrovePostID given",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := CheckReferenceBetweenUserAndPost(tt.args.ctx, tt.args.db, tt.args.anthroveUserID, tt.args.anthrovePostID)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CheckIfUserHasPostAsFavorite() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("CheckIfUserHasPostAsFavorite() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckUserToPostLinkWithNoData(t *testing.T) {
|
||||
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
validUserID := models.AnthroveUserID(fmt.Sprintf("%025s", "User1"))
|
||||
invalidUserID := models.AnthroveUserID("XXX")
|
||||
|
||||
validPostID := models.AnthrovePostID(fmt.Sprintf("%025s", "Post1"))
|
||||
|
||||
err = CreateUser(ctx, gormDB, validUserID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: validPostID,
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = CreateReferenceBetweenUserAndPost(ctx, gormDB, validUserID, post.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthroveUserID models.AnthroveUserID
|
||||
anthrovePostID models.AnthrovePostID
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid AnthroveUserID and AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
want: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Valid AnthroveUserID and invalid AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: "qadw",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: Valid AnthrovePostID and invalid AnthroveUserID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 4: Invalid AnthrovePostID and invalid AnthroveUserID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 5: No AnthrovePostID given",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: "",
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 6: No anthrovePostID given",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "",
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := CheckReferenceBetweenUserAndPost(tt.args.ctx, tt.args.db, tt.args.anthroveUserID, tt.args.anthrovePostID)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("CheckIfUserHasPostAsFavorite() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("CheckIfUserHasPostAsFavorite() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEstablishUserToPostLink(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
validUserID := models.AnthroveUserID(fmt.Sprintf("%025s", "User1"))
|
||||
invalidUserID := models.AnthroveUserID("XXX")
|
||||
|
||||
validPostID := models.AnthrovePostID(fmt.Sprintf("%025s", "Post1"))
|
||||
|
||||
err = CreateUser(ctx, gormDB, validUserID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
post := &models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: validPostID,
|
||||
},
|
||||
Rating: "safe",
|
||||
}
|
||||
|
||||
err = CreatePost(ctx, gormDB, post)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthroveUserID models.AnthroveUserID
|
||||
anthrovePostID models.AnthrovePostID
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid AnthroveUserID and AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Valid AnthroveUserID and invalid AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: validUserID,
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: invalid AnthroveUserID and valid AnthrovePostID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: post.ID,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 4: Invalid AnthrovePostID and invalid AnthroveUserID",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "123456",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 5: AnthrovePostID is empty",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: invalidUserID,
|
||||
anthrovePostID: "",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 6: anthroveUserID is empty",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveUserID: "",
|
||||
anthrovePostID: validPostID,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := CreateReferenceBetweenUserAndPost(tt.args.ctx, tt.args.db, tt.args.anthroveUserID, tt.args.anthrovePostID); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CreateReferenceBetweenUserAndPost() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CreateSource creates a pgModels.Source
|
||||
func CreateSource(ctx context.Context, db *gorm.DB, anthroveSource *models.Source) error {
|
||||
|
||||
if anthroveSource.Domain == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "Domain is required"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Where(models.Source{Domain: anthroveSource.Domain}).FirstOrCreate(anthroveSource)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"node_source_url": anthroveSource.Domain,
|
||||
"node_source_displayName": anthroveSource.DisplayName,
|
||||
"node_source_icon": anthroveSource.Icon,
|
||||
}).Trace("database: created source node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllSource returns a list of all pgModels.Source
|
||||
func GetAllSource(ctx context.Context, db *gorm.DB) ([]models.Source, error) {
|
||||
var sources []models.Source
|
||||
|
||||
result := db.WithContext(ctx).Find(&sources)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_amount": result.RowsAffected,
|
||||
}).Trace("database: get all source nodes")
|
||||
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
// GetSourceByDomain returns the first source it finds based on the domain
|
||||
func GetSourceByDomain(ctx context.Context, db *gorm.DB, sourceDomain models.AnthroveSourceDomain) (*models.Source, error) {
|
||||
var sources models.Source
|
||||
|
||||
if sourceDomain == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "AnthroveSourceDomain is not set"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Where("domain = ?", sourceDomain).First(&sources)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_amount": result.RowsAffected,
|
||||
}).Trace("database: get all source nodes")
|
||||
|
||||
return &sources, nil
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/test"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestCreateSourceNode(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
validPostID := models.AnthroveSourceID(fmt.Sprintf("%025s", "Post1"))
|
||||
|
||||
validSource := &models.Source{
|
||||
BaseModel: models.BaseModel[models.AnthroveSourceID]{ID: validPostID},
|
||||
DisplayName: "e621",
|
||||
Domain: "e621.net",
|
||||
Icon: "icon.e621.net",
|
||||
}
|
||||
|
||||
invalidSource := &models.Source{
|
||||
BaseModel: models.BaseModel[models.AnthroveSourceID]{ID: validPostID},
|
||||
Domain: "notfound.intern",
|
||||
}
|
||||
|
||||
invalidSourceDomain := &models.Source{
|
||||
BaseModel: models.BaseModel[models.AnthroveSourceID]{ID: validPostID},
|
||||
Domain: "",
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
anthroveSource *models.Source
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid anthroveSource",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveSource: validSource,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: inValid anthroveSource",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveSource: invalidSourceDomain,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 3: unique anthroveSource",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
anthroveSource: invalidSource,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := CreateSource(tt.args.ctx, tt.args.db, tt.args.anthroveSource); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CreateSource() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllSourceNodes(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
sources := []models.Source{
|
||||
{
|
||||
DisplayName: "e621",
|
||||
Domain: "e621.net",
|
||||
Icon: "icon.e621.net",
|
||||
},
|
||||
{
|
||||
DisplayName: "furaffinity",
|
||||
Domain: "furaffinity.net",
|
||||
Icon: "icon.furaffinity.net",
|
||||
},
|
||||
{
|
||||
DisplayName: "fenpaws",
|
||||
Domain: "fenpa.ws",
|
||||
Icon: "icon.fenpa.ws",
|
||||
},
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
err = CreateSource(ctx, gormDB, &source)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []models.Source
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Get all entries",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
},
|
||||
want: sources,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetAllSource(tt.args.ctx, tt.args.db)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetAllSource() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !checkSourcesNode(got, tt.want) {
|
||||
t.Errorf("GetAllSource() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSourceNodesByURL(t *testing.T) {
|
||||
// Setup trow away container
|
||||
ctx := context.Background()
|
||||
container, gormDB, err := test.StartPostgresContainer(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not start PostgreSQL container: %v", err)
|
||||
}
|
||||
defer container.Terminate(ctx)
|
||||
|
||||
// Setup Test
|
||||
|
||||
source := &models.Source{
|
||||
DisplayName: "e621",
|
||||
Domain: "e621.net",
|
||||
Icon: "icon.e621.net",
|
||||
}
|
||||
|
||||
err = CreateSource(ctx, gormDB, source)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
db *gorm.DB
|
||||
domain models.AnthroveSourceDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Source
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test 1: Valid URL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
domain: "e621.net",
|
||||
},
|
||||
want: source,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Test 2: Invalid URL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
domain: "eeeee.net",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test 2: No URL",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
db: gormDB,
|
||||
domain: "",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetSourceByDomain(tt.args.ctx, tt.args.db, tt.args.domain)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetSourceByDomain() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !checkSourceNode(got, tt.want) {
|
||||
t.Errorf("GetSourceByDomain() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func checkSourcesNode(got []models.Source, want []models.Source) bool {
|
||||
for i, source := range want {
|
||||
if source.DisplayName != got[i].DisplayName {
|
||||
return false
|
||||
}
|
||||
if source.Domain != got[i].Domain {
|
||||
return false
|
||||
}
|
||||
if source.Icon != got[i].Icon {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func checkSourceNode(got *models.Source, want *models.Source) bool {
|
||||
|
||||
if want == nil && got == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if got.Domain != want.Domain {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
@ -1,440 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateTag(ctx context.Context, db *gorm.DB, tagName models.AnthroveTagName, tagType models.TagType) error {
|
||||
|
||||
if tagName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagName cannot be empty"}
|
||||
}
|
||||
|
||||
if tagType == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagType cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Create(&models.Tag{Name: string(tagName), Type: tagType})
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_name": tagName,
|
||||
"tag_type": tagType,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTagInBatchAndUpdate(ctx context.Context, db *gorm.DB, tags []models.Tag, batchSize int) error {
|
||||
if len(tags) == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "tags cannot be empty"}
|
||||
}
|
||||
|
||||
if tags == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "tags cannot be nil"}
|
||||
}
|
||||
|
||||
if batchSize == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "batch size cannot be zero"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).
|
||||
Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "name"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"tag_type"}),
|
||||
}).CreateInBatches(tags, batchSize)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_size": len(tags),
|
||||
"batch_size": batchSize,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteTag(ctx context.Context, db *gorm.DB, tagName models.AnthroveTagName) error {
|
||||
|
||||
if tagName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagName cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Delete(&models.Tag{Name: string(tagName)})
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return &otterError.NoDataFound{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_name": tagName,
|
||||
}).Trace("database: deleted tag")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllTagByTagsType(ctx context.Context, db *gorm.DB, tagType models.TagType) ([]models.Tag, error) {
|
||||
var tags []models.Tag
|
||||
|
||||
if tagType == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "tagType cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.Tag{}).Where("tag_type = ?", tagType).Scan(&tags)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tags_length": len(tags),
|
||||
}).Trace("database: got tag")
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func CreateTagAndReferenceToPost(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, tag *models.Tag) error {
|
||||
|
||||
if anthrovePostID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthrovePostID cannot be empty"}
|
||||
}
|
||||
|
||||
if len(anthrovePostID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"}
|
||||
}
|
||||
|
||||
if tag == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "Tag is nil"}
|
||||
}
|
||||
|
||||
pgPost := models.Post{
|
||||
BaseModel: models.BaseModel[models.AnthrovePostID]{
|
||||
ID: anthrovePostID,
|
||||
},
|
||||
}
|
||||
|
||||
err := db.WithContext(ctx).Model(&pgPost).Association("Tags").Append(tag)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return &otterError.NoDataFound{}
|
||||
}
|
||||
return errors.Join(err, &otterError.NoRelationCreated{})
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_post_id": anthrovePostID,
|
||||
"tag_name": tag.Name,
|
||||
"tag_type": tag.Type,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetTags(ctx context.Context, db *gorm.DB) ([]models.Tag, error) {
|
||||
var tags []models.Tag
|
||||
|
||||
result := db.WithContext(ctx).Find(&tags)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_amount": len(tags),
|
||||
}).Trace("database: got tags")
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func CreateTagAlias(ctx context.Context, db *gorm.DB, tagAliasName models.AnthroveTagAliasName, tagID models.AnthroveTagID) error {
|
||||
|
||||
if tagAliasName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliasName cannot be empty"}
|
||||
}
|
||||
if tagID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveTagIDEmpty}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "name"}},
|
||||
DoNothing: true,
|
||||
}).Create(&models.TagAlias{
|
||||
Name: string(tagAliasName),
|
||||
TagID: string(tagID),
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_name": tagAliasName,
|
||||
"tag_alias_tag_id": tagID,
|
||||
}).Trace("database: created tagAlias")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTagAliasInBatch(ctx context.Context, db *gorm.DB, tagAliases []models.TagAlias, batchSize int) error {
|
||||
if len(tagAliases) == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliases cannot be empty"}
|
||||
}
|
||||
|
||||
if tagAliases == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliases cannot be nil"}
|
||||
}
|
||||
|
||||
if batchSize == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "batch size cannot be zero"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "name"}},
|
||||
DoNothing: true,
|
||||
}).CreateInBatches(tagAliases, batchSize)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_size": len(tagAliases),
|
||||
"batch_size": batchSize,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllTagAlias(ctx context.Context, db *gorm.DB) ([]models.TagAlias, error) {
|
||||
var tagAliases []models.TagAlias
|
||||
|
||||
result := db.WithContext(ctx).Find(&tagAliases)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_length": len(tagAliases),
|
||||
}).Trace("database: created tagAlias")
|
||||
|
||||
return tagAliases, nil
|
||||
}
|
||||
|
||||
func GetAllTagAliasByTag(ctx context.Context, db *gorm.DB, tagID models.AnthroveTagID) ([]models.TagAlias, error) {
|
||||
var tagAliases []models.TagAlias
|
||||
|
||||
if tagID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveTagIDEmpty}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Where("tag_id = ?", tagID).Find(&tagAliases)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_length": len(tagAliases),
|
||||
"tag_alias_tag_id": tagID,
|
||||
}).Trace("database: get specific tagAlias")
|
||||
|
||||
return tagAliases, nil
|
||||
}
|
||||
|
||||
func DeleteTagAlias(ctx context.Context, db *gorm.DB, tagAliasName models.AnthroveTagAliasName) error {
|
||||
|
||||
if tagAliasName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliasName cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Delete(&models.TagAlias{Name: string(tagAliasName)})
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return &otterError.NoDataFound{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_name": tagAliasName,
|
||||
}).Trace("database: deleted tagAlias")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTagGroup(ctx context.Context, db *gorm.DB, tagGroupName models.AnthroveTagGroupName, tagID models.AnthroveTagID) error {
|
||||
|
||||
if tagGroupName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagGroupName cannot be empty"}
|
||||
}
|
||||
if tagID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveTagIDEmpty}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Create(&models.TagGroup{
|
||||
Name: string(tagGroupName),
|
||||
TagID: string(tagID),
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_group_name": tagGroupName,
|
||||
"tag_group_tag_id": tagID,
|
||||
}).Trace("database: created tagGroup")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTagGroupInBatch(ctx context.Context, db *gorm.DB, tagGroups []models.TagGroup, batchSize int) error {
|
||||
if len(tagGroups) == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliases cannot be empty"}
|
||||
}
|
||||
|
||||
if tagGroups == nil {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagAliases cannot be nil"}
|
||||
}
|
||||
|
||||
if batchSize == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "batch size cannot be zero"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).CreateInBatches(tagGroups, batchSize)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_size": len(tagGroups),
|
||||
"batch_size": batchSize,
|
||||
}).Trace("database: created tag node")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllTagGroup(ctx context.Context, db *gorm.DB) ([]models.TagGroup, error) {
|
||||
var tagGroups []models.TagGroup
|
||||
|
||||
result := db.WithContext(ctx).Find(&tagGroups)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_length": len(tagGroups),
|
||||
}).Trace("database: created tagGroup")
|
||||
|
||||
return tagGroups, nil
|
||||
}
|
||||
|
||||
func GetAllTagGroupByTag(ctx context.Context, db *gorm.DB, tagID models.AnthroveTagID) ([]models.TagGroup, error) {
|
||||
var tagGroups []models.TagGroup
|
||||
|
||||
if tagID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveTagIDEmpty}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Where("tag_id = ?", tagID).Find(&tagGroups)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_length": len(tagGroups),
|
||||
"tag_alias_tag_id": tagID,
|
||||
}).Trace("database: get specific tagGroup")
|
||||
|
||||
return tagGroups, nil
|
||||
}
|
||||
|
||||
func DeleteTagGroup(ctx context.Context, db *gorm.DB, tagGroupName models.AnthroveTagGroupName) error {
|
||||
|
||||
if tagGroupName == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "tagGroupName cannot be empty"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Delete(&models.TagGroup{Name: string(tagGroupName)})
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return &otterError.NoDataFound{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tag_alias_name": tagGroupName,
|
||||
}).Trace("database: deleted tagAlias")
|
||||
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,398 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error"
|
||||
"git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models"
|
||||
gonanoid "github.com/matoous/go-nanoid/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Workaround, should be changed later maybe, but its not that bad right now
|
||||
type selectFrequencyTag struct {
|
||||
tagName string `gorm:"tag_name"`
|
||||
count int64 `gorm:"count"`
|
||||
tagType models.TagType `gorm:"tag_type"`
|
||||
}
|
||||
|
||||
func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) error {
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
user := models.User{
|
||||
BaseModel: models.BaseModel[models.AnthroveUserID]{
|
||||
ID: anthroveUserID,
|
||||
},
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).FirstOrCreate(&user)
|
||||
if result.Error != nil {
|
||||
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateUserWithRelationToSource(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, accountId string, accountUsername string) error {
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if accountId == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "accountID cannot be empty"}
|
||||
}
|
||||
|
||||
if accountUsername == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: "accountUsername cannot be empty"}
|
||||
}
|
||||
|
||||
validationCode, err := gonanoid.New(25)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Exec(`WITH userObj AS (
|
||||
INSERT INTO "User" (id)
|
||||
VALUES ($1)
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
)
|
||||
INSERT INTO "UserSource" (user_id, source_id, account_username, account_id, account_validate, account_validation_key)
|
||||
SELECT $2, source.id, $3, $4, false, $5
|
||||
FROM "Source" AS source
|
||||
WHERE source.id = $6;`, anthroveUserID, anthroveUserID, accountUsername, accountId, validationCode, sourceID)
|
||||
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
|
||||
return &otterError.EntityAlreadyExists{}
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return &otterError.NoDataWritten{}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"source_id": sourceID,
|
||||
"account_username": accountUsername,
|
||||
"account_id": accountId,
|
||||
}).Info("database: created user-source relationship")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetUserFavoritesCount(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (int64, error) {
|
||||
var count int64
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return 0, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return 0, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Count(&count)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return 0, &otterError.NoDataFound{}
|
||||
}
|
||||
return 0, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"anthrove_user_fav_count": count,
|
||||
}).Trace("database: got user favorite count")
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func GetUserSourceLinks(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
|
||||
var userSources []models.UserSource
|
||||
userSourceMap := make(map[string]models.UserSource)
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
for _, userSource := range userSources {
|
||||
var source models.Source
|
||||
result = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
userSourceMap[source.DisplayName] = models.UserSource{
|
||||
UserID: userSource.AccountID,
|
||||
AccountUsername: userSource.AccountUsername,
|
||||
Source: models.Source{
|
||||
DisplayName: source.DisplayName,
|
||||
Domain: source.Domain,
|
||||
Icon: source.Icon,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
}).Trace("database: got user source link")
|
||||
|
||||
return userSourceMap, nil
|
||||
}
|
||||
|
||||
func GetUserSourceBySourceID(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID) (*models.UserSource, error) {
|
||||
var userSource models.UserSource
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if sourceID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "sourceID cannot be empty"}
|
||||
}
|
||||
|
||||
if len(sourceID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: "sourceID needs to be 25 characters long"}
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("id = ?", sourceID)).Where("user_id = ?", string(anthroveUserID)).First(&userSource)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"source_id": sourceID,
|
||||
}).Trace("database: got specified user source link")
|
||||
|
||||
return &userSource, nil
|
||||
}
|
||||
|
||||
func GetAllUsers(ctx context.Context, db *gorm.DB) ([]models.User, error) {
|
||||
var users []models.User
|
||||
|
||||
result := db.WithContext(ctx).Model(&models.User{}).Find(&users)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id_count": len(users),
|
||||
}).Trace("database: got all anthrove user IDs")
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// TODO: FIX THE TEST
|
||||
func GetUserFavoriteWithPagination(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error) {
|
||||
var favoritePosts []models.Post
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
db.WithContext(ctx).Joins("RIGHT JOIN \"UserFavorite\" AS of ON \"Post\".id = of.post_id AND of.user_id = ?", anthroveUserID).Preload("References").Offset(skip).Limit(limit).Find(&favoritePosts)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"anthrove_user_fav_count": len(favoritePosts),
|
||||
}).Trace("database: got all anthrove user favorites")
|
||||
|
||||
return &models.FavoriteList{Posts: favoritePosts}, nil
|
||||
}
|
||||
|
||||
func GetUserTagWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) {
|
||||
var queryUserFavorites []selectFrequencyTag
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return nil, &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
rows, err := db.WithContext(ctx).Raw(
|
||||
`WITH user_posts AS (
|
||||
SELECT post_id FROM "UserFavorite" WHERE user_id = $1
|
||||
)
|
||||
SELECT post_tags.tag_name AS tag_name, count(*) AS count, (SELECT tag_type FROM "Tag" WHERE "Tag".name = post_tags.tag_name LIMIT 1) AS tag_type FROM post_tags, user_posts WHERE post_tags.post_id IN (user_posts.post_id) GROUP BY post_tags.tag_name ORDER BY tag_type DESC, tag_name DESC`, anthroveUserID).Rows()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, &otterError.NoDataFound{}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var userFavoritesFrequency = make([]models.TagsWithFrequency, 0)
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var tagName string
|
||||
var count int64
|
||||
var tagType string
|
||||
rows.Scan(&tagName, &count, &tagType)
|
||||
userFavoritesFrequency = append(userFavoritesFrequency, models.TagsWithFrequency{
|
||||
Frequency: count,
|
||||
Tags: models.Tag{
|
||||
Name: tagName,
|
||||
Type: models.TagType(tagType),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"anthrove_user_id": anthroveUserID,
|
||||
"tag_amount": len(queryUserFavorites),
|
||||
}).Trace("database: got user tag node with relation to faved posts")
|
||||
|
||||
return userFavoritesFrequency, nil
|
||||
}
|
||||
|
||||
func UpdateUserSourceScrapeTimeInterval(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, scrapeTime models.AnthroveScrapeTimeInterval) error {
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if sourceID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDEmpty}
|
||||
}
|
||||
|
||||
if len(sourceID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDToShort}
|
||||
}
|
||||
|
||||
if scrapeTime == 0 {
|
||||
return &otterError.EntityValidationFailed{Reason: "ScrapeTimeInterval cannot be empty"}
|
||||
}
|
||||
|
||||
userSource := &models.UserSource{
|
||||
UserID: string(anthroveUserID),
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&userSource).Update("scrape_time_interval", scrapeTime)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateUserSourceLastScrapeTime(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, lastScrapeTime models.AnthroveUserLastScrapeTime) error {
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if sourceID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDEmpty}
|
||||
}
|
||||
|
||||
if len(sourceID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDToShort}
|
||||
}
|
||||
|
||||
if time.Time.IsZero(time.Time(lastScrapeTime)) {
|
||||
return &otterError.EntityValidationFailed{Reason: "LastScrapeTime cannot be empty"}
|
||||
}
|
||||
|
||||
userSource := &models.UserSource{
|
||||
UserID: string(anthroveUserID),
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&userSource).Update("last_scrape_time", time.Time(lastScrapeTime))
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateUserSourceValidation(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, valid bool) error {
|
||||
|
||||
if anthroveUserID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDIsEmpty}
|
||||
}
|
||||
|
||||
if len(anthroveUserID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveUserIDToShort}
|
||||
}
|
||||
|
||||
if sourceID == "" {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDEmpty}
|
||||
}
|
||||
|
||||
if len(sourceID) != 25 {
|
||||
return &otterError.EntityValidationFailed{Reason: otterError.AnthroveSourceIDToShort}
|
||||
}
|
||||
|
||||
userSource := &models.UserSource{
|
||||
UserID: string(anthroveUserID),
|
||||
}
|
||||
|
||||
result := db.WithContext(ctx).Model(&userSource).Update("account_validate", valid)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user