Compare commits

...

9 Commits

Author SHA1 Message Date
7842976f4b test(postgres): fixed the tests & also squashed some bugs
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-23 01:18:23 +02:00
bb7cb23c2a refactor(postgres): Refactor post retrieval functions and remove unnecessary code in tag and user creation
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 23:25:28 +02:00
9471941e02 refactor(postgres): fixed any IDE errors
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 23:25:06 +02:00
b28891f383 refactor(postgres): fixed any IDE errors
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 23:23:23 +02:00
55296d9a95 refactor(postgres): renamed functions to be more clear
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 22:30:03 +02:00
78145fe02a refactor(postgres): removed old docs
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 22:28:29 +02:00
2621eea00c refactor(postgres): fixed implementation
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 22:27:38 +02:00
b11cfbaa24 refactor(postgres): removed old graph related code
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 22:07:36 +02:00
58dcf94d49 refactor(postgres): removed old graph related code
Signed-off-by: soxx <soxx@fenpa.ws>
2024-06-22 22:06:36 +02:00
37 changed files with 784 additions and 2047 deletions

View File

@ -1,46 +0,0 @@
package graph
import (
"fmt"
neo4jLog "github.com/neo4j/neo4j-go-driver/v5/neo4j/log"
log "github.com/sirupsen/logrus"
)
type graphLogger struct {
graphDebug bool
}
func NewGraphLogger(graphDebug bool) neo4jLog.Logger {
return &graphLogger{graphDebug: graphDebug}
}
func (n graphLogger) Error(name string, id string, err error) {
log.WithFields(log.Fields{
"name": name,
"id": id,
}).Errorf("database: %s", err)
}
func (n graphLogger) Warnf(name string, id string, msg string, args ...any) {
log.WithFields(log.Fields{
"name": name,
"id": id,
}).Warnf("database: %v", fmt.Sprintf(msg, args...))
}
func (n graphLogger) Infof(name string, id string, msg string, args ...any) {
log.WithFields(log.Fields{
"name": name,
"id": id,
}).Infof("database: %v", fmt.Sprintf(msg, args...))
}
func (n graphLogger) Debugf(name string, id string, msg string, args ...any) {
if n.graphDebug {
log.WithFields(log.Fields{
"name": name,
"id": id,
}).Debugf("database: %v", fmt.Sprintf(msg, args...))
}
}

View File

@ -1,116 +0,0 @@
package graph
import (
"context"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
log "github.com/sirupsen/logrus"
)
func CreateAnthrovePostNode(ctx context.Context, driver neo4j.DriverWithContext, anthrovePost *graphModels.AnthrovePost) error {
query := `
CREATE (newPostNode:AnthrovePost {post_id: $anthrove_post_id, rating: $anthrove_rating})
`
params := map[string]any{
"anthrove_post_id": anthrovePost.PostID,
"anthrove_rating": anthrovePost.Rating,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return err
}
log.WithFields(log.Fields{
"anthrove_post_id": anthrovePost.PostID,
"anthrove_post_rating": anthrovePost.Rating,
}).Trace("database: created anthrove post")
return nil
}
func CheckIfAnthrovePostNodeExistsByAnthroveID(ctx context.Context, driver neo4j.DriverWithContext, anthrovePost *graphModels.AnthrovePost) (*graphModels.AnthrovePost, bool, error) {
query := `
OPTIONAL MATCH (postNode:AnthrovePost {post_id: $anthrove_post_id})
RETURN postNode.post_id AS AnthrovePostID
`
params := map[string]any{
"anthrove_post_id": anthrovePost.PostID,
}
anthrovePost, exists, err := executeCheckQuery(ctx, driver, query, params)
if err != nil {
return nil, false, err
}
return anthrovePost, exists, nil
}
func CheckIfAnthrovePostNodeExistsBySourceURl(ctx context.Context, driver neo4j.DriverWithContext, sourceUrl string) (*graphModels.AnthrovePost, bool, error) {
query := `
OPTIONAL MATCH (postNode:AnthrovePost)<-[:REFERENCE {url: $source_url}]-()
RETURN postNode.post_id AS AnthrovePostID
`
params := map[string]any{
"source_url": sourceUrl,
}
anthrovePost, exists, err := executeCheckQuery(ctx, driver, query, params)
if err != nil {
return nil, false, err
}
return anthrovePost, exists, nil
}
func CheckIfAnthrovePostNodeExistsBySourceID(ctx context.Context, driver neo4j.DriverWithContext, sourcePostID string) (*graphModels.AnthrovePost, bool, error) {
query := `
OPTIONAL MATCH (postNode:AnthrovePost)<-[:REFERENCE {source_post_id: $source_post_id}]-()
RETURN postNode.post_id AS AnthrovePostID
`
params := map[string]any{
"source_post_id": sourcePostID,
}
anthrovePost, exists, err := executeCheckQuery(ctx, driver, query, params)
if err != nil {
return nil, false, err
}
return anthrovePost, exists, nil
}
func executeCheckQuery(ctx context.Context, driver neo4j.DriverWithContext, query string, params map[string]any) (*graphModels.AnthrovePost, bool, error) {
var anthrovePost graphModels.AnthrovePost
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return &anthrovePost, false, err
}
record := result.Records
anthrovePostID, isNil, err := neo4j.GetRecordValue[string](record[0], "AnthrovePostID")
exists := !isNil
if err != nil {
return &anthrovePost, exists, err
}
anthrovePost.PostID = models.AnthrovePostID(anthrovePostID)
log.WithFields(log.Fields{
"anthrove_post_id": anthrovePost.PostID,
"anthrove_post_exists": exists,
}).Trace("database: checked if post exists")
if !exists {
return nil, exists, nil
}
return &anthrovePost, exists, nil
}

View File

@ -1,100 +0,0 @@
package graph
import (
"context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
log "github.com/sirupsen/logrus"
)
func EstablishAnthrovePostToSourceLink(ctx context.Context, driver neo4j.DriverWithContext, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *graphModels.AnthrovePostRelationship) error {
query := `
MATCH (sourceNode:Source {domain: $source_url})
MATCH (postNode:AnthrovePost {post_id: $anthrove_post_id})
MERGE (sourceNode)-[:REFERENCE {url: $source_post_url, source_post_id: $source_post_id}]->(postNode)
`
params := map[string]any{
"source_url": anthroveSourceDomain,
"anthrove_post_id": anthrovePostID,
"source_post_url": anthrovePostRelationship.Url,
"source_post_id": anthrovePostRelationship.PostID,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return err
}
log.WithFields(log.Fields{
"source_url": anthroveSourceDomain,
"anthrove_post_id": anthrovePostID,
"source_post_url": anthrovePostRelationship.Url,
"source_post_id": anthrovePostRelationship.PostID,
}).Trace("database: creating anthrove post to source link")
return nil
}
func EstablishUserToPostLink(ctx context.Context, driver neo4j.DriverWithContext, anthroveUser *graphModels.AnthroveUser, anthrovePost *graphModels.AnthrovePost) error {
query := `
MATCH (user:User {user_id: $anthrove_user_id})
MATCH (anthrovePost:AnthrovePost {post_id: $anthrove_post_id})
MERGE (user)-[:FAV]->(anthrovePost)
`
params := map[string]any{
"anthrove_post_id": anthrovePost.PostID,
"anthrove_user_id": anthroveUser.UserID,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return err
}
log.WithFields(log.Fields{
"anthrove_post_id": anthrovePost.PostID,
"anthrove_user_id": anthroveUser.UserID,
}).Trace("database: created user to post link")
return nil
}
func CheckUserToPostLink(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error) {
query := `
OPTIONAL MATCH (:User {user_id: $anthrove_user_id})-[f:FAV]->(:AnthrovePost)<-[:REFERENCE{source_post_id: $source_post_id}]-(:Source{domain: $source_domain})
RETURN COUNT(f) > 0 AS hasRelationship
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
"source_post_id": sourcePostID,
"source_domain": sourceUrl,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return false, err
}
if len(result.Records) == 0 {
return false, fmt.Errorf("no records found")
}
exists, _, err := neo4j.GetRecordValue[bool](result.Records[0], "hasRelationship")
if err != nil {
return false, err
}
log.WithFields(log.Fields{
"relationship_exists": exists,
"relationship_anthrove_user_id": anthroveUserID,
"relationship_e621_post_id": "",
}).Trace("database: checked user post relationship")
return exists, nil
}

View File

@ -1,113 +0,0 @@
package graph
import (
"context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
log "github.com/sirupsen/logrus"
)
func CreateSourceNode(ctx context.Context, driver neo4j.DriverWithContext, anthroveSource *graphModels.AnthroveSource) error {
query := `
MERGE (sourceNode:Source {domain: $source_url})
ON CREATE SET sourceNode.domain = $source_url, sourceNode.display_name = $source_display_name, sourceNode.icon = $source_icon
`
params := map[string]any{
"source_url": anthroveSource.Domain,
"source_display_name": anthroveSource.DisplayName,
"source_icon": anthroveSource.Icon,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return fmt.Errorf("database: %w", err)
}
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
}
func GetAllSourceNodes(ctx context.Context, driver neo4j.DriverWithContext) ([]graphModels.AnthroveSource, error) {
var sources []graphModels.AnthroveSource
query := `
MATCH (s:Source)
RETURN s as source
`
params := map[string]any{}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, nil
}
for i := range result.Records {
record := result.Records[i]
source, _, err := neo4j.GetRecordValue[neo4j.Node](record, "source")
if err != nil {
return nil, err
}
sources = append(sources, graphModels.AnthroveSource{
DisplayName: source.Props["display_name"].(string),
Domain: source.Props["domain"].(string),
Icon: source.Props["icon"].(string),
})
}
log.WithFields(log.Fields{
"tag_amount": len(sources),
}).Trace("database: created tag node")
return sources, nil
}
func GetSourceNodesByURL(ctx context.Context, driver neo4j.DriverWithContext, sourceUrl string) (*graphModels.AnthroveSource, error) {
var source graphModels.AnthroveSource
query := `
MATCH (s:Source {domain: $source_url})
RETURN s as source
`
params := map[string]any{
"source_url": sourceUrl,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, fmt.Errorf("source not found")
}
record, _, err := neo4j.GetRecordValue[neo4j.Node](result.Records[0], "source")
if err != nil {
return nil, err
}
source.DisplayName = record.Props["display_name"].(string)
source.Domain = record.Props["domain"].(string)
source.Icon = record.Props["icon"].(string)
log.WithFields(log.Fields{
"source_url": sourceUrl,
}).Trace("database: got source node")
return &source, nil
}

View File

@ -1,84 +0,0 @@
package graph
import (
"context"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
log "github.com/sirupsen/logrus"
)
func CreateTagNodeWitRelation(ctx context.Context, driver neo4j.DriverWithContext, anthrovePostID models.AnthrovePostID, anthroveTag *graphModels.AnthroveTag) error {
query := `
MATCH (anthrovePost:AnthrovePost {post_id: $anthrove_post_id})
MERGE (tagNode:Tag {name: $tag_name, type: $tag_type})
MERGE (anthrovePost)-[:HAS]->(tagNode)
`
params := map[string]interface{}{
"tag_name": anthroveTag.Name,
"tag_type": anthroveTag.Type,
"anthrove_post_id": anthrovePostID,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return err
}
log.WithFields(log.Fields{
"anthrove_post_id": anthrovePostID,
"tag_name": anthroveTag.Name,
"tag_type": anthroveTag.Type,
}).Trace("database: created tag node")
return nil
}
func GetTags(ctx context.Context, driver neo4j.DriverWithContext) ([]graphModels.TagsWithFrequency, error) {
var userTags []graphModels.TagsWithFrequency
query := `
MATCH (:AnthrovePost)-[:HAS]->(t:Tag)
RETURN t as tag, COUNT(t) AS frequency
ORDER BY frequency DESC
`
params := map[string]any{}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, nil
}
for i := range result.Records {
record := result.Records[i]
tag, _, err := neo4j.GetRecordValue[neo4j.Node](record, "tag")
if err != nil {
return nil, err
}
frequency, _, err := neo4j.GetRecordValue[int64](record, "frequency")
if err != nil {
return nil, err
}
userTags = append(userTags, graphModels.TagsWithFrequency{
Frequency: frequency,
Tags: graphModels.AnthroveTag{
Name: tag.Props["name"].(string),
Type: tag.Props["type"].(string),
},
})
}
log.WithFields(log.Fields{
"tag_amount": len(userTags),
}).Trace("database: created tag node")
return userTags, nil
}

View File

@ -1,454 +0,0 @@
package graph
import (
"context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/internal/utils"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
log "github.com/sirupsen/logrus"
)
func CreateUserNodeWithSourceRelation(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error {
query := `
MATCH (userNode:User {user_id: $anthrove_user_id})
MATCH (sourceNode:Source {domain: $source_domain})
MERGE (userNode)-[r:HAS_ACCOUNT_AT {username: $source_user_name, user_id: $source_user_id}]->(sourceNode)
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
"source_user_id": userID,
"source_user_name": username,
"source_domain": sourceDomain,
}
_, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return err
}
var anthroveUserRelationship []graphModels.AnthroveUserRelationship
anthroveUserRelationship = append(anthroveUserRelationship, graphModels.AnthroveUserRelationship{
UserID: userID,
Username: username,
ScrapeTimeInterval: "",
Source: graphModels.AnthroveSource{
DisplayName: "",
Domain: sourceDomain,
Icon: "",
},
})
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
"source_user_id": userID,
"source_user_name": username,
"source_domain": sourceDomain,
}).Trace("database: crated user with relationship")
return nil
}
func GetUserFavoritesCount(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID) (int64, error) {
var userFavoriteCount int64
query := `
MATCH (userNode:User {user_id: $anthrove_user_id})
MATCH (userNode)-[:FAV]->(favPost:AnthrovePost)
MATCH (sourceNode)-[:REFERENCE]->(favPost)
RETURN count( DISTINCT favPost) AS FavoritePostsCount
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return 0, err
}
if len(result.Records) == 0 {
// no matches -> user does not exist, return count 0
return userFavoriteCount, err
}
record := result.Records[0]
userFavoriteCount, _, err = neo4j.GetRecordValue[int64](record, "FavoritePostsCount")
if err != nil {
return userFavoriteCount, err
}
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
"anthrove_user_fav_count": userFavoriteCount,
}).Trace("database: got user favorite count")
return userFavoriteCount, nil
}
func GetUserSourceLink(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error) {
userSource := make(map[string]graphModels.AnthroveUserRelationship)
query := `
MATCH (user:User{user_id: $anthrove_user_id})-[r:HAS_ACCOUNT_AT]->(s:Source)
RETURN toString(r.user_id) AS sourceUserID, toString(r.username) AS sourceUsername, s as source;
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, fmt.Errorf("user has no relations")
}
for i := range result.Records {
record := result.Records[i]
source, _, err := neo4j.GetRecordValue[neo4j.Node](record, "source")
if err != nil {
return nil, err
}
sourceUserID, _, err := neo4j.GetRecordValue[string](record, "sourceUserID")
if err != nil {
return nil, err
}
sourceUsername, _, err := neo4j.GetRecordValue[string](record, "sourceUsername")
if err != nil {
return nil, err
}
displayName := source.Props["display_name"].(string)
domain := source.Props["domain"].(string)
icon := source.Props["icon"].(string)
anthroveSourceUser := graphModels.AnthroveUserRelationship{
UserID: sourceUserID,
Username: sourceUsername,
Source: graphModels.AnthroveSource{
DisplayName: displayName,
Domain: domain,
Icon: icon,
},
}
userSource[displayName] = anthroveSourceUser
}
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
"anthrove_data": userSource,
}).Trace("database: got user favorite count")
return userSource, nil
}
func GetSpecifiedUserSourceLink(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error) {
userSource := make(map[string]graphModels.AnthroveUserRelationship)
query := `
MATCH (user:User{user_id: $anthrove_user_id})-[r:HAS_ACCOUNT_AT]->(s:Source{display_name: $source_display_name})
RETURN toString(r.user_id) AS sourceUserID, toString(r.username) AS sourceUsername, s as source;
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
"source_display_name": sourceDisplayName,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, fmt.Errorf("user has no relations with the source %s", sourceDisplayName)
}
for i := range result.Records {
record := result.Records[i]
source, _, err := neo4j.GetRecordValue[neo4j.Node](record, "source")
if err != nil {
return nil, err
}
sourceUserID, _, err := neo4j.GetRecordValue[string](record, "sourceUserID")
if err != nil {
return nil, err
}
sourceUsername, _, err := neo4j.GetRecordValue[string](record, "sourceUsername")
if err != nil {
return nil, err
}
displayName := source.Props["display_name"].(string)
domain := source.Props["domain"].(string)
icon := source.Props["icon"].(string)
anthroveSourceUser := graphModels.AnthroveUserRelationship{
UserID: sourceUserID,
Username: sourceUsername,
Source: graphModels.AnthroveSource{
DisplayName: displayName,
Domain: domain,
Icon: icon,
},
}
userSource[displayName] = anthroveSourceUser
}
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
"anthrove_data": userSource,
}).Trace("database: got user favorite count")
return userSource, nil
}
func GetAnthroveUser(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error) {
var err error
var anthroveUser graphModels.AnthroveUser
var userSources graphModels.AnthroveSource
userRelationships := make([]graphModels.AnthroveUserRelationship, 0)
query := `
MATCH (user:User{user_id: $anthrove_user_id})-[relation:HAS_ACCOUNT_AT]->(source:Source)
RETURN user as User, relation as Relation, source as Source;
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, fmt.Errorf("user has no relations")
}
for i := range result.Records {
record := result.Records[i]
user, _, err := neo4j.GetRecordValue[neo4j.Node](record, "User")
if err != nil {
return nil, err
}
relation, _, err := neo4j.GetRecordValue[neo4j.Relationship](record, "Relation")
if err != nil {
return nil, err
}
source, _, err := neo4j.GetRecordValue[neo4j.Node](record, "Source")
if err != nil {
return nil, err
}
userRelationships = append(userRelationships, graphModels.AnthroveUserRelationship{
UserID: fmt.Sprintf("%v", utils.GetOrDefault(relation.Props, "user_id", "")),
Username: utils.GetOrDefault(relation.Props, "username", "").(string),
ScrapeTimeInterval: utils.GetOrDefault(relation.Props, "scrape_time_interval", "").(string),
})
userSources = graphModels.AnthroveSource{
DisplayName: utils.GetOrDefault(source.Props, "display_name", "").(string),
Domain: utils.GetOrDefault(source.Props, "domain", "").(string),
Icon: utils.GetOrDefault(source.Props, "icon", "").(string),
}
anthroveUser.UserID = models.AnthroveUserID(utils.GetOrDefault(user.Props, "user_id", "").(string))
anthroveUser.Relationship = userRelationships
for j := range userRelationships {
anthroveUser.Relationship[j].Source = userSources
}
}
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
}).Trace("database: got anthrove user")
return &anthroveUser, nil
}
func GetAllAnthroveUserIDs(ctx context.Context, driver neo4j.DriverWithContext) ([]models.AnthroveUserID, error) {
var err error
var anthroveUsers []models.AnthroveUserID
query := `
MATCH (anthroveUser:User)
RETURN anthroveUser
`
result, err := neo4j.ExecuteQuery(ctx, driver, query, nil, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
log.Warnf("No users found, this should not be happening!")
return []models.AnthroveUserID{}, nil
}
for i := range result.Records {
record := result.Records[i]
user, _, err := neo4j.GetRecordValue[neo4j.Node](record, "anthroveUser")
if err != nil {
return nil, err
}
anthroveUsers = append(anthroveUsers, models.AnthroveUserID(fmt.Sprintf(user.Props["user_id"].(string))))
}
log.WithFields(log.Fields{
"anthrove_user_id_count": len(anthroveUsers),
}).Trace("database: got al anthrove user IDs")
return anthroveUsers, nil
}
func GetUserFavoriteNodeWithPagination(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) {
var err error
var favoritePosts []graphModels.FavoritePost
query := `
CALL {
MATCH (user:User{user_id: $anthrove_user_id})-[r:FAV]->(p:AnthrovePost)
RETURN p.post_id AS post_id
ORDER BY id(p) ASC
SKIP $skip
LIMIT $limit
}
WITH collect(post_id) AS faves
MATCH (a:AnthrovePost)<-[r:REFERENCE]-(s:Source)
WHERE a.post_id in faves
RETURN a AS anthrovePost, r AS postRelation, s AS Source
ORDER BY id(a) ASC
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
"limit": limit,
"skip": skip,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, nil
}
for i := range result.Records {
record := result.Records[i]
anthrovePost, _, err := neo4j.GetRecordValue[neo4j.Node](record, "anthrovePost")
if err != nil {
return nil, err
}
postRelation, _, err := neo4j.GetRecordValue[neo4j.Relationship](record, "postRelation")
if err != nil {
return nil, err
}
source, _, err := neo4j.GetRecordValue[neo4j.Node](record, "Source")
if err != nil {
return nil, err
}
if len(favoritePosts) != 0 && favoritePosts[len(favoritePosts)-1].AnthrovePost.PostID == models.AnthrovePostID(anthrovePost.Props["post_id"].(string)) {
favoritePosts[len(favoritePosts)-1].Relations = append(favoritePosts[len(favoritePosts)-1].Relations, graphModels.FavoriteRelations{
SourcesID: source.Props["display_name"].(string),
Relations: graphModels.AnthrovePostRelationship{
PostID: postRelation.Props["source_post_id"].(string),
Url: postRelation.Props["url"].(string),
},
})
} else {
favoritePosts = append(favoritePosts, graphModels.FavoritePost{
AnthrovePost: graphModels.AnthrovePost{
PostID: models.AnthrovePostID(anthrovePost.Props["post_id"].(string)),
Rating: models.Rating(anthrovePost.Props["rating"].(string)),
},
Relations: []graphModels.FavoriteRelations{{
SourcesID: source.Props["display_name"].(string),
Relations: graphModels.AnthrovePostRelationship{
PostID: postRelation.Props["source_post_id"].(string),
Url: postRelation.Props["url"].(string),
},
}},
})
}
}
log.WithFields(log.Fields{
"anthrove_user_fav_count": len(favoritePosts),
}).Trace("database: got al anthrove user favorites")
return &graphModels.FavoriteList{Posts: favoritePosts}, nil
}
func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, driver neo4j.DriverWithContext, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) {
var userTags []graphModels.TagsWithFrequency
query := `
MATCH (u:User {user_id: $anthrove_user_id})-[:FAV]->(:AnthrovePost)-[:HAS]->(t:Tag)
RETURN t as tag, COUNT(t) AS frequency
ORDER BY frequency DESC
`
params := map[string]any{
"anthrove_user_id": anthroveUserID,
}
result, err := neo4j.ExecuteQuery(ctx, driver, query, params, neo4j.EagerResultTransformer)
if err != nil {
return nil, err
}
if len(result.Records) == 0 {
return nil, nil
}
for i := range result.Records {
record := result.Records[i]
tag, _, err := neo4j.GetRecordValue[neo4j.Node](record, "tag")
if err != nil {
return nil, err
}
frequency, _, err := neo4j.GetRecordValue[int64](record, "frequency")
if err != nil {
return nil, err
}
userTags = append(userTags, graphModels.TagsWithFrequency{
Frequency: frequency,
Tags: graphModels.AnthroveTag{
Name: tag.Props["name"].(string),
Type: tag.Props["type"].(string),
},
})
}
log.WithFields(log.Fields{
"tag_amount": len(userTags),
}).Trace("database: created tag node")
return userTags, nil
}

View File

@ -5,89 +5,62 @@ import (
"errors" "errors"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
) )
func CreateAnthrovePostNode(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, anthroveRating models.Rating) error { func CreatePost(ctx context.Context, db *gorm.DB, anthrovePost *models.Post) error {
post := pgModels.Post{ err := db.WithContext(ctx).Create(&anthrovePost).Error
BaseModel: pgModels.BaseModel{
ID: string(anthrovePostID),
},
Rating: anthroveRating,
}
err := db.WithContext(ctx).Create(&post).Error
if err != nil { if err != nil {
return err return err
} }
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_post_id": anthrovePostID, "anthrove_post_id": anthrovePost.ID,
"anthrove_post_rating": anthroveRating, "anthrove_post_rating": anthrovePost.Rating,
}).Trace("database: created anthrove post") }).Trace("database: created anthrove post")
return nil return nil
} }
func CheckIfAnthrovePostNodeExistsByAnthroveID(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID) (bool, error) { func GetPostByAnthroveID(ctx context.Context, db *gorm.DB, anthrovePostID string) (*models.Post, error) {
if anthrovePostID == "" { if anthrovePostID == "" {
return false, fmt.Errorf("anthrovePostID is required") return nil, fmt.Errorf("anthrovePostID is required")
} }
return executeCheckQuery(ctx, db, "id = ?", string(anthrovePostID)) var post models.Post
err := db.WithContext(ctx).First(&post, "id = ?", anthrovePostID).Error
if err != nil {
return nil, err
}
return &post, nil
} }
func CheckIfAnthrovePostNodeExistsBySourceURL(ctx context.Context, db *gorm.DB, sourceURL string) (*graphModels.AnthrovePost, bool, error) { func GetPostBySourceURL(ctx context.Context, db *gorm.DB, sourceURL string) (*models.Post, error) {
postRef := pgModels.PostReference{} var post models.Post
err := db.WithContext(ctx).Model(&pgModels.PostReference{}).Where("url = ?", sourceURL).First(&postRef).Error err := 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).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil return nil, nil
} }
return nil, false, err return nil, err
} }
var post pgModels.Post return &post, nil
err = db.WithContext(ctx).First(&post, "id = ?", postRef.PostID).Error }
func GetPostBySourceID(ctx context.Context, db *gorm.DB, sourceID string) (*models.Post, error) {
var post models.Post
err := 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).Error
if err != nil { if err != nil {
return nil, false, err if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
} }
pgPost := graphModels.AnthrovePost{ return &post, nil
PostID: models.AnthrovePostID(post.ID),
Rating: post.Rating,
}
//TODO Now test it! :D
// Naaa
// D:
return &pgPost, true, nil
}
func CheckIfAnthrovePostNodeExistsBySourceID(ctx context.Context, db *gorm.DB, sourceID string) (bool, error) {
return executeCheckQuery(ctx, db, "source_id = ?", sourceID)
}
func executeCheckQuery(ctx context.Context, db *gorm.DB, query string, args ...interface{}) (bool, error) {
var count int64
err := db.WithContext(ctx).Model(&pgModels.Post{}).Where(query, args...).Count(&count).Error
if err != nil {
return false, err
}
exists := count > 0
log.WithFields(log.Fields{
"query": query,
"args": args,
"exists": exists,
}).Trace("database: executed check query")
return exists, nil
} }

View File

@ -2,6 +2,7 @@ package postgres
import ( import (
"context" "context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/test" "git.dragse.it/anthrove/otter-space-sdk/test"
_ "github.com/lib/pq" _ "github.com/lib/pq"
@ -19,11 +20,24 @@ func TestCreateAnthrovePostNode(t *testing.T) {
} }
defer container.Terminate(ctx) defer container.Terminate(ctx)
// Setup Tests
validPost := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
invalidPost := &models.Post{
Rating: "error",
}
// Test
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthrovePostID models.AnthrovePostID anthrovePost *models.Post
anthroveRating models.Rating
} }
tests := []struct { tests := []struct {
name string name string
@ -35,32 +49,30 @@ func TestCreateAnthrovePostNode(t *testing.T) {
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
db: gormDB, db: gormDB,
anthrovePostID: "1234", anthrovePost: validPost,
anthroveRating: models.Rating("safe"),
}, },
wantErr: false, wantErr: false,
}, },
{ {
name: "Test 2: Invalid AnthrovePostID and Rating", name: "Test 2: Invalid Rating",
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
db: gormDB, db: gormDB,
anthrovePostID: "", anthrovePost: invalidPost,
anthroveRating: "a4dsa4d",
}, },
wantErr: true, wantErr: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := CreateAnthrovePostNode(tt.args.ctx, tt.args.db, tt.args.anthrovePostID, tt.args.anthroveRating); (err != nil) != tt.wantErr { if err := CreatePost(tt.args.ctx, tt.args.db, tt.args.anthrovePost); (err != nil) != tt.wantErr {
t.Errorf("CreateAnthrovePostNode() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("CreatePost() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })
} }
} }
func TestCheckIfAnthrovePostNodeExistsByAnthroveID(t *testing.T) { func TestGetPostByAnthroveID(t *testing.T) {
// Setup trow away container // Setup trow away container
ctx := context.Background() ctx := context.Background()
container, gormDB, err := test.StartPostgresContainer(ctx) container, gormDB, err := test.StartPostgresContainer(ctx)
@ -69,68 +81,284 @@ func TestCheckIfAnthrovePostNodeExistsByAnthroveID(t *testing.T) {
} }
defer container.Terminate(ctx) defer container.Terminate(ctx)
// Setup Test // Setup Tests
err = CreateAnthrovePostNode(ctx, gormDB, "1234", "safe") post := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
err = CreatePost(ctx, gormDB, post)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal("Could not create post", err)
} }
// Test // Test
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthrovePostID models.AnthrovePostID anthrovePostID string
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want bool want *models.Post
wantErr bool wantErr bool
}{ }{
{ {
name: "Test 1: Valid AnthroveID", 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{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "1234", anthrovePostID: "1234",
}, },
want: true, want: nil,
wantErr: false, wantErr: true,
}, },
{ {
name: "Test 2: Invalid AnthroveID", name: "Test 3: No anthrovePostID",
args: args{
ctx: ctx,
db: gormDB,
anthrovePostID: "123456",
},
want: false,
wantErr: false,
},
{
name: "Test 3: No AnthroveID",
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "", anthrovePostID: "",
}, },
want: false, want: nil,
wantErr: true, wantErr: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := CheckIfAnthrovePostNodeExistsByAnthroveID(tt.args.ctx, tt.args.db, tt.args.anthrovePostID) got, err := GetPostByAnthroveID(tt.args.ctx, tt.args.db, tt.args.anthrovePostID)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("CheckIfAnthrovePostNodeExistsByAnthroveID() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("GetPostByAnthroveID() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if got != tt.want { if !checkPost(got, tt.want) {
t.Errorf("CheckIfAnthrovePostNodeExistsByAnthroveID() got = %v, want %v", 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{
ID: 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{ID: fmt.Sprintf("%025s", "1")},
DisplayName: "e621",
Domain: "e621.net",
Icon: "https://e621.net/icon.ico",
}
err = CreateSourceNode(ctx, gormDB, &source)
if err != nil {
t.Fatal("Could not create source", err)
}
err = EstablishAnthrovePostToSourceLink(ctx, gormDB, post.ID, source.Domain)
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: source.Domain,
},
want: post,
wantErr: false,
},
{
name: "Test 2: Invalid sourceURL",
args: args{
ctx: ctx,
db: gormDB,
sourceURL: "1234",
},
want: nil,
wantErr: false,
},
{
name: "Test 3: No sourceURL",
args: args{
ctx: ctx,
db: gormDB,
sourceURL: "",
},
want: nil,
wantErr: false,
},
}
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{
ID: 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{ID: fmt.Sprintf("%025s", "1")},
DisplayName: "e621",
Domain: "e621.net",
Icon: "https://e621.net/icon.ico",
}
err = CreateSourceNode(ctx, gormDB, &source)
if err != nil {
t.Fatal("Could not create source", err)
}
err = EstablishAnthrovePostToSourceLink(ctx, gormDB, post.ID, source.Domain)
if err != nil {
t.Fatal("Could not create source reference", err)
}
// Test
type args struct {
ctx context.Context
db *gorm.DB
sourceID string
}
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: false,
},
{
name: "Test 3: No sourceID",
args: args{
ctx: ctx,
db: gormDB,
sourceID: "",
},
want: nil,
wantErr: false,
},
}
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 checkPost(got *models.Post, want *models.Post) bool {
if got == nil {
return true
}
if got.ID != want.ID {
return false
}
if got.Rating != want.Rating {
return false
}
return true
}

View File

@ -3,27 +3,25 @@ package postgres
import ( import (
"context" "context"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
) )
func EstablishAnthrovePostToSourceLink(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *graphModels.AnthrovePostRelationship) error { func EstablishAnthrovePostToSourceLink(ctx context.Context, db *gorm.DB, anthrovePostID string, sourceDomain string) error {
var source pgModels.Source var source models.Source
var err error var err error
// Find the source // Find the source
err = db.WithContext(ctx).Where("domain = ?", anthroveSourceDomain).First(&source).Error err = db.WithContext(ctx).Where("domain = ?", sourceDomain).First(&source).Error
if err != nil { if err != nil {
return err return err
} }
// Establish the relationship // Establish the relationship
err = db.WithContext(ctx).Create(pgModels.PostReference{ err = db.WithContext(ctx).Create(models.PostReference{
PostID: string(anthrovePostID), PostID: anthrovePostID,
SourceID: source.ID, SourceID: source.ID,
URL: anthrovePostRelationship.Url, URL: sourceDomain,
}).Error }).Error
if err != nil { if err != nil {
@ -32,14 +30,14 @@ func EstablishAnthrovePostToSourceLink(ctx context.Context, db *gorm.DB, anthrov
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_post_id": anthrovePostID, "anthrove_post_id": anthrovePostID,
"anthrove_source_domain": anthroveSourceDomain, "anthrove_source_domain": sourceDomain,
}).Trace("database: created anthrove post to source link") }).Trace("database: created anthrove post to source link")
return nil return nil
} }
func EstablishUserToPostLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) error { func EstablishUserToPostLink(ctx context.Context, db *gorm.DB, anthroveUserID string, anthrovePostID string) error {
userFavorite := pgModels.UserFavorite{ userFavorite := models.UserFavorite{
UserID: string(anthroveUserID), UserID: string(anthroveUserID),
PostID: string(anthrovePostID), PostID: string(anthrovePostID),
} }
@ -57,9 +55,9 @@ func EstablishUserToPostLink(ctx context.Context, db *gorm.DB, anthroveUserID mo
return nil return nil
} }
func CheckUserToPostLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) (bool, error) { func CheckUserToPostLink(ctx context.Context, db *gorm.DB, anthroveUserID string, anthrovePostID string) (bool, error) {
var count int64 var count int64
err := db.WithContext(ctx).Model(&pgModels.UserFavorite{}).Where("user_id = ? AND post_id = ?", string(anthroveUserID), string(anthrovePostID)).Count(&count).Error err := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ? AND post_id = ?", string(anthroveUserID), string(anthrovePostID)).Count(&count).Error
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@ -2,14 +2,14 @@ package postgres
import ( import (
"context" "context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
"git.dragse.it/anthrove/otter-space-sdk/test" "git.dragse.it/anthrove/otter-space-sdk/test"
"gorm.io/gorm" "gorm.io/gorm"
"testing" "testing"
) )
func TestEstablishAnthrovePostToSourceLink(t *testing.T) { func TestCheckUserToPostLink(t *testing.T) {
// Setup trow away container // Setup trow away container
ctx := context.Background() ctx := context.Background()
@ -20,13 +20,123 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
defer container.Terminate(ctx) defer container.Terminate(ctx)
// Setup Test // Setup Test
err = CreateUser(ctx, gormDB, "1")
err = CreateAnthrovePostNode(ctx, gormDB, "1234", "safe")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
source := &pgModels.Source{ post := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
err = CreatePost(ctx, gormDB, post)
if err != nil {
t.Fatal(err)
}
err = EstablishUserToPostLink(ctx, gormDB, "1", post.ID)
if err != nil {
t.Fatal(err)
}
// Test
type args struct {
ctx context.Context
db *gorm.DB
anthroveUserID string
anthrovePostID string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{
name: "Test 1: Valid AnthroveUserID and AnthrovePostID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "1",
anthrovePostID: post.ID,
},
want: true,
wantErr: false,
},
{
name: "Test 2: Valid AnthroveUserID and invalid AnthrovePostID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "1",
anthrovePostID: "qadw",
},
want: false,
wantErr: false,
},
{
name: "Test 3: Valid AnthrovePostID and invalid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "123",
anthrovePostID: post.ID,
},
want: false,
wantErr: false,
},
{
name: "Test 4: Invalid AnthrovePostID and invalid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "123",
anthrovePostID: "123456",
},
want: false,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CheckUserToPostLink(tt.args.ctx, tt.args.db, tt.args.anthroveUserID, tt.args.anthrovePostID)
if (err != nil) != tt.wantErr {
t.Errorf("CheckUserToPostLink() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("CheckUserToPostLink() got = %v, want %v", got, tt.want)
}
})
}
}
func TestEstablishAnthrovePostToSourceLink(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
post := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
err = CreatePost(ctx, gormDB, post)
if err != nil {
t.Fatal(err)
}
source := &models.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
Icon: "icon.e621.net", Icon: "icon.e621.net",
@ -37,12 +147,12 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
} }
// Test // Test
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthrovePostID models.AnthrovePostID anthrovePostID string
anthroveSourceDomain string sourceDomain string
anthrovePostRelationship *models.PostReference
} }
tests := []struct { tests := []struct {
name string name string
@ -54,8 +164,8 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "1234", anthrovePostID: post.ID,
anthroveSourceDomain: "e621.net", sourceDomain: "e621.net",
}, },
wantErr: false, wantErr: false,
}, },
@ -65,7 +175,7 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "123456", anthrovePostID: "123456",
anthroveSourceDomain: "e621.net", sourceDomain: "e621.net",
}, },
wantErr: true, wantErr: true,
}, },
@ -75,7 +185,7 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "1234", anthrovePostID: "1234",
anthroveSourceDomain: "fa.banana", sourceDomain: "fa.banana",
}, },
wantErr: true, wantErr: true,
}, },
@ -85,14 +195,14 @@ func TestEstablishAnthrovePostToSourceLink(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthrovePostID: "696969", anthrovePostID: "696969",
anthroveSourceDomain: "hehe.funny.number", sourceDomain: "hehe.funny.number",
}, },
wantErr: true, wantErr: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := EstablishAnthrovePostToSourceLink(tt.args.ctx, tt.args.db, tt.args.anthrovePostID, tt.args.anthroveSourceDomain); (err != nil) != tt.wantErr { if err := EstablishAnthrovePostToSourceLink(tt.args.ctx, tt.args.db, tt.args.anthrovePostID, tt.args.sourceDomain); (err != nil) != tt.wantErr {
t.Errorf("EstablishAnthrovePostToSourceLink() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("EstablishAnthrovePostToSourceLink() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })
@ -114,7 +224,14 @@ func TestEstablishUserToPostLink(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = CreateAnthrovePostNode(ctx, gormDB, "1234", "safe") post := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
err = CreatePost(ctx, gormDB, post)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -123,8 +240,8 @@ func TestEstablishUserToPostLink(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthroveUserID models.AnthroveUserID anthroveUserID string
anthrovePostID models.AnthrovePostID anthrovePostID string
} }
tests := []struct { tests := []struct {
name string name string
@ -137,7 +254,7 @@ func TestEstablishUserToPostLink(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "1", anthroveUserID: "1",
anthrovePostID: "1234", anthrovePostID: post.ID,
}, },
wantErr: false, wantErr: false,
}, },
@ -180,101 +297,3 @@ func TestEstablishUserToPostLink(t *testing.T) {
}) })
} }
} }
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
err = CreateUser(ctx, gormDB, "1")
if err != nil {
t.Fatal(err)
}
err = CreateAnthrovePostNode(ctx, gormDB, "1234", "safe")
if err != nil {
t.Fatal(err)
}
err = EstablishUserToPostLink(ctx, gormDB, "1", "1234")
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: "1",
anthrovePostID: "1234",
},
want: true,
wantErr: false,
},
{
name: "Test 2: Valid AnthroveUserID and invalid AnthrovePostID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "1",
anthrovePostID: "123456",
},
want: false,
wantErr: false,
},
{
name: "Test 3: Valid AnthrovePostID and invalid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "123",
anthrovePostID: "1234",
},
want: false,
wantErr: false,
},
{
name: "Test 4: Invalid AnthrovePostID and invalid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "123",
anthrovePostID: "123456",
},
want: false,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CheckUserToPostLink(tt.args.ctx, tt.args.db, tt.args.anthroveUserID, tt.args.anthrovePostID)
if (err != nil) != tt.wantErr {
t.Errorf("CheckUserToPostLink() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("CheckUserToPostLink() got = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -3,20 +3,20 @@ package postgres
import ( import (
"context" "context"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
) )
// CreateSourceNode creates a pgModels.Source // CreateSourceNode creates a pgModels.Source
func CreateSourceNode(ctx context.Context, db *gorm.DB, anthroveSource *pgModels.Source) error { func CreateSourceNode(ctx context.Context, db *gorm.DB, anthroveSource *models.Source) error {
if anthroveSource.Domain == "" { if anthroveSource.Domain == "" {
return fmt.Errorf("anthroveSource domain is required") return fmt.Errorf("anthroveSource domain is required")
} }
result := db.WithContext(ctx).Where(pgModels.Source{Domain: anthroveSource.Domain}).FirstOrCreate(anthroveSource) result := db.WithContext(ctx).Where(models.Source{Domain: anthroveSource.Domain}).FirstOrCreate(anthroveSource)
if result.Error != nil { if result.Error != nil {
return result.Error return result.Error
@ -32,8 +32,8 @@ func CreateSourceNode(ctx context.Context, db *gorm.DB, anthroveSource *pgModels
} }
// GetAllSourceNodes returns a list of all pgModels.Source // GetAllSourceNodes returns a list of all pgModels.Source
func GetAllSourceNodes(ctx context.Context, db *gorm.DB) ([]pgModels.Source, error) { func GetAllSourceNodes(ctx context.Context, db *gorm.DB) ([]models.Source, error) {
var sources []pgModels.Source var sources []models.Source
result := db.WithContext(ctx).Find(&sources) result := db.WithContext(ctx).Find(&sources)
@ -49,8 +49,8 @@ func GetAllSourceNodes(ctx context.Context, db *gorm.DB) ([]pgModels.Source, err
} }
// GetSourceNodesByURL returns the first source it finds based on the domain // GetSourceNodesByURL returns the first source it finds based on the domain
func GetSourceNodesByURL(ctx context.Context, db *gorm.DB, domain string) (*pgModels.Source, error) { func GetSourceNodesByURL(ctx context.Context, db *gorm.DB, domain string) (*models.Source, error) {
var sources pgModels.Source var sources models.Source
if domain == "" { if domain == "" {
return nil, fmt.Errorf("domain is required") return nil, fmt.Errorf("domain is required")

View File

@ -2,7 +2,7 @@ package postgres
import ( import (
"context" "context"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/test" "git.dragse.it/anthrove/otter-space-sdk/test"
"gorm.io/gorm" "gorm.io/gorm"
"testing" "testing"
@ -19,13 +19,13 @@ func TestCreateSourceNode(t *testing.T) {
// Setup Test // Setup Test
validAnthroveSource := &pgModels.Source{ validSource := &models.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
Icon: "icon.e621.net", Icon: "icon.e621.net",
} }
invalidAnthroveSource := &pgModels.Source{ invalidSource := &models.Source{
Domain: "", Domain: "",
} }
@ -33,7 +33,7 @@ func TestCreateSourceNode(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthroveSource *pgModels.Source anthroveSource *models.Source
} }
tests := []struct { tests := []struct {
name string name string
@ -45,7 +45,7 @@ func TestCreateSourceNode(t *testing.T) {
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveSource: validAnthroveSource, anthroveSource: validSource,
}, },
wantErr: false, wantErr: false,
}, },
@ -54,7 +54,7 @@ func TestCreateSourceNode(t *testing.T) {
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveSource: invalidAnthroveSource, anthroveSource: invalidSource,
}, },
wantErr: true, wantErr: true,
}, },
@ -63,7 +63,7 @@ func TestCreateSourceNode(t *testing.T) {
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveSource: validAnthroveSource, anthroveSource: validSource,
}, },
wantErr: false, wantErr: false,
}, },
@ -88,7 +88,7 @@ func TestGetAllSourceNodes(t *testing.T) {
// Setup Test // Setup Test
sources := []pgModels.Source{ sources := []models.Source{
{ {
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
@ -121,7 +121,7 @@ func TestGetAllSourceNodes(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want []pgModels.Source want []models.Source
wantErr bool wantErr bool
}{ }{
{ {
@ -159,7 +159,7 @@ func TestGetSourceNodesByURL(t *testing.T) {
// Setup Test // Setup Test
source := &pgModels.Source{ source := &models.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
Icon: "icon.e621.net", Icon: "icon.e621.net",
@ -179,7 +179,7 @@ func TestGetSourceNodesByURL(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want *pgModels.Source want *models.Source
wantErr bool wantErr bool
}{ }{
{ {
@ -227,7 +227,7 @@ func TestGetSourceNodesByURL(t *testing.T) {
} }
} }
func checkSourcesNode(got []pgModels.Source, want []pgModels.Source) bool { func checkSourcesNode(got []models.Source, want []models.Source) bool {
for i, source := range want { for i, source := range want {
if source.DisplayName != got[i].DisplayName { if source.DisplayName != got[i].DisplayName {
return false return false
@ -244,7 +244,7 @@ func checkSourcesNode(got []pgModels.Source, want []pgModels.Source) bool {
} }
func checkSourceNode(got *pgModels.Source, want *pgModels.Source) bool { func checkSourceNode(got *models.Source, want *models.Source) bool {
if want == nil && got == nil { if want == nil && got == nil {
return true return true

View File

@ -4,12 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
) )
func CreateTag(ctx context.Context, db *gorm.DB, tag *pgModels.Tag) error { func createTag(ctx context.Context, db *gorm.DB, tag *models.Tag) error {
resultTag := db.WithContext(ctx).Where(tag).Create(tag) resultTag := db.WithContext(ctx).Where(tag).Create(tag)
@ -25,20 +24,18 @@ func CreateTag(ctx context.Context, db *gorm.DB, tag *pgModels.Tag) error {
return nil return nil
} }
func CreateTagNodeWitRelation(ctx context.Context, db *gorm.DB, PostID models.AnthrovePostID, tag *pgModels.Tag) error { func CreateTagNodeWitRelation(ctx context.Context, db *gorm.DB, PostID string, tag *models.Tag) error {
if PostID == "" { if PostID == "" {
return fmt.Errorf("PostID is empty") return fmt.Errorf("PostID is empty")
} }
resultTag := db.WithContext(ctx).Where(tag).FirstOrCreate(tag) if tag == nil {
return fmt.Errorf("tag is nill")
if resultTag.Error != nil {
return resultTag.Error
} }
pgPost := pgModels.Post{ pgPost := models.Post{
BaseModel: pgModels.BaseModel{ BaseModel: models.BaseModel{
ID: string(PostID), ID: string(PostID),
}, },
} }
@ -58,8 +55,8 @@ func CreateTagNodeWitRelation(ctx context.Context, db *gorm.DB, PostID models.An
return nil return nil
} }
func GetTags(ctx context.Context, db *gorm.DB) ([]pgModels.Tag, error) { func GetTags(ctx context.Context, db *gorm.DB) ([]models.Tag, error) {
var tags []pgModels.Tag var tags []models.Tag
result := db.WithContext(ctx).Find(&tags) result := db.WithContext(ctx).Find(&tags)
if result.Error != nil { if result.Error != nil {
return nil, result.Error return nil, result.Error

View File

@ -2,8 +2,8 @@ package postgres
import ( import (
"context" "context"
"fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
"git.dragse.it/anthrove/otter-space-sdk/test" "git.dragse.it/anthrove/otter-space-sdk/test"
"gorm.io/gorm" "gorm.io/gorm"
"testing" "testing"
@ -20,12 +20,19 @@ func TestCreateTagNodeWitRelation(t *testing.T) {
// Setup Test // Setup Test
err = CreateAnthrovePostNode(ctx, gormDB, "1234", "safe") post := &models.Post{
BaseModel: models.BaseModel{
ID: fmt.Sprintf("%025s", "1"),
},
Rating: "safe",
}
err = CreatePost(ctx, gormDB, post)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
tag := &pgModels.Tag{ tag := &models.Tag{
Name: "JayTheFerret", Name: "JayTheFerret",
Type: "artist", Type: "artist",
} }
@ -34,8 +41,8 @@ func TestCreateTagNodeWitRelation(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
PostID models.AnthrovePostID PostID string
tag *pgModels.Tag tag *models.Tag
} }
tests := []struct { tests := []struct {
name string name string
@ -47,17 +54,17 @@ func TestCreateTagNodeWitRelation(t *testing.T) {
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
PostID: "1234", PostID: post.ID,
tag: tag, tag: tag,
}, },
wantErr: false, wantErr: false,
}, },
{ {
name: "Test 2: Valid PostID and invalid Tag", name: "Test 2: Valid PostID and no Tag",
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
PostID: "1234", PostID: post.ID,
tag: nil, tag: nil,
}, },
wantErr: true, wantErr: true,
@ -103,7 +110,7 @@ func TestGetTags(t *testing.T) {
// Setup Test // Setup Test
tags := []pgModels.Tag{ tags := []models.Tag{
{ {
Name: "JayTheFerret", Name: "JayTheFerret",
Type: "artist", Type: "artist",
@ -119,7 +126,7 @@ func TestGetTags(t *testing.T) {
} }
for _, tag := range tags { for _, tag := range tags {
err = CreateTag(ctx, gormDB, &tag) err = createTag(ctx, gormDB, &tag)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -133,7 +140,7 @@ func TestGetTags(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want []pgModels.Tag want []models.Tag
wantErr bool wantErr bool
}{ }{
{ {
@ -160,7 +167,7 @@ func TestGetTags(t *testing.T) {
} }
} }
func checkTag(got []pgModels.Tag, want []pgModels.Tag) bool { func checkTag(got []models.Tag, want []models.Tag) bool {
for i, tag := range want { for i, tag := range want {
if tag.Type != got[i].Type { if tag.Type != got[i].Type {
return false return false

View File

@ -4,25 +4,23 @@ import (
"context" "context"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
) )
func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) error { func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID string) error {
if anthroveUserID == "" { if anthroveUserID == "" {
return fmt.Errorf("anthroveUserID cannot be empty") return fmt.Errorf("anthroveUserID cannot be empty")
} }
user := pgModels.User{ user := models.User{
BaseModel: pgModels.BaseModel{ BaseModel: models.BaseModel{
ID: string(anthroveUserID), ID: string(anthroveUserID),
}, },
} }
err := db.WithContext(ctx).Create(&user).Error err := db.WithContext(ctx).FirstOrCreate(&user).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID, "anthrove_user_id": anthroveUserID,
@ -33,26 +31,18 @@ func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.Anthrove
return nil return nil
} }
func CreateUserNodeWithSourceRelation(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error { func CreateUserNodeWithSourceRelation(ctx context.Context, db *gorm.DB, anthroveUserID string, sourceDomain string, userID string, username string) error {
if anthroveUserID == "" || username == "" || userID == "" { if anthroveUserID == "" || username == "" || userID == "" {
return fmt.Errorf("anthroveUserID cannot be empty") return fmt.Errorf("anthroveUserID cannot be empty")
} }
user := pgModels.User{ err := CreateUser(ctx, db, anthroveUserID)
BaseModel: pgModels.BaseModel{ if err != nil {
ID: string(anthroveUserID),
},
}
if err := db.WithContext(ctx).FirstOrCreate(&user).Error; err != nil {
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
}).Error("database: failed to find or create user")
return err return err
} }
source := pgModels.Source{ source := models.Source{
Domain: sourceDomain, Domain: sourceDomain,
} }
@ -63,11 +53,12 @@ func CreateUserNodeWithSourceRelation(ctx context.Context, db *gorm.DB, anthrove
return err return err
} }
userSource := pgModels.UserSource{ userSource := models.UserSource{
UserID: user.ID, User: models.User{BaseModel: models.BaseModel{ID: anthroveUserID}},
SourceID: source.ID, SourceID: source.ID,
AccountUsername: username, AccountUsername: username,
AccountID: userID, AccountID: userID,
UserID: anthroveUserID,
} }
if err := db.WithContext(ctx).FirstOrCreate(&userSource).Error; err != nil { if err := db.WithContext(ctx).FirstOrCreate(&userSource).Error; err != nil {
@ -96,7 +87,7 @@ func GetUserFavoritesCount(ctx context.Context, db *gorm.DB, anthroveUserID mode
} }
var count int64 var count int64
err := db.WithContext(ctx).Model(&pgModels.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Count(&count).Error err := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Count(&count).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID, "anthrove_user_id": anthroveUserID,
@ -112,11 +103,11 @@ func GetUserFavoritesCount(ctx context.Context, db *gorm.DB, anthroveUserID mode
return count, nil return count, nil
} }
func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error) { func GetUserSourceLinks(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
var userSources []pgModels.UserSource var userSources []models.UserSource
userSourceMap := make(map[string]graphModels.AnthroveUserRelationship) userSourceMap := make(map[string]models.UserSource)
err := db.WithContext(ctx).Model(&pgModels.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error err := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID, "anthrove_user_id": anthroveUserID,
@ -125,8 +116,8 @@ func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.A
} }
for _, userSource := range userSources { for _, userSource := range userSources {
var source pgModels.Source var source models.Source
err = db.WithContext(ctx).Model(&pgModels.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error err = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"source_id": userSource.SourceID, "source_id": userSource.SourceID,
@ -134,10 +125,10 @@ func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.A
return nil, err return nil, err
} }
userSourceMap[source.DisplayName] = graphModels.AnthroveUserRelationship{ userSourceMap[source.DisplayName] = models.UserSource{
UserID: userSource.AccountID, UserID: userSource.AccountID,
Username: userSource.AccountUsername, AccountUsername: userSource.AccountUsername,
Source: graphModels.AnthroveSource{ Source: models.Source{
DisplayName: source.DisplayName, DisplayName: source.DisplayName,
Domain: source.Domain, Domain: source.Domain,
Icon: source.Icon, Icon: source.Icon,
@ -152,15 +143,15 @@ func GetUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.A
return userSourceMap, nil return userSourceMap, nil
} }
func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error) { func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error) {
if anthroveUserID == "" || sourceDisplayName == "" { if anthroveUserID == "" || sourceDisplayName == "" {
return nil, fmt.Errorf("anthroveUserID or sourceDisplayName is empty") return nil, fmt.Errorf("anthroveUserID or sourceDisplayName is empty")
} }
var userSources []pgModels.UserSource var userSources []models.UserSource
userSourceMap := make(map[string]graphModels.AnthroveUserRelationship) userSourceMap := make(map[string]models.UserSource)
err := db.WithContext(ctx).Model(&pgModels.UserSource{}).InnerJoins("Source", db.Where("display_name = ?", sourceDisplayName)).Where("user_id = ?", string(anthroveUserID)).First(&userSources).Error err := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("display_name = ?", sourceDisplayName)).Where("user_id = ?", string(anthroveUserID)).First(&userSources).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID, "anthrove_user_id": anthroveUserID,
@ -170,8 +161,8 @@ func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID
} }
for _, userSource := range userSources { for _, userSource := range userSources {
var source pgModels.Source var source models.Source
err = db.WithContext(ctx).Model(&pgModels.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error err = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"source_id": userSource.SourceID, "source_id": userSource.SourceID,
@ -179,10 +170,10 @@ func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID
return nil, err return nil, err
} }
userSourceMap[source.DisplayName] = graphModels.AnthroveUserRelationship{ userSourceMap[source.DisplayName] = models.UserSource{
UserID: userSource.AccountID, UserID: userSource.AccountID,
Username: userSource.AccountUsername, AccountUsername: userSource.AccountUsername,
Source: graphModels.AnthroveSource{ Source: models.Source{
DisplayName: source.DisplayName, DisplayName: source.DisplayName,
Domain: source.Domain, Domain: source.Domain,
Icon: source.Icon, Icon: source.Icon,
@ -198,74 +189,18 @@ func GetSpecifiedUserSourceLink(ctx context.Context, db *gorm.DB, anthroveUserID
return userSourceMap, nil return userSourceMap, nil
} }
func GetAnthroveUser(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error) { func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]string, error) {
var users []models.User
var userIDs []string
if anthroveUserID == "" { err := db.WithContext(ctx).Model(&models.User{}).Find(&users).Error
return nil, fmt.Errorf("anthroveUserID cannot be empty")
}
var user pgModels.User
var userSources []pgModels.UserSource
anthroveUser := &graphModels.AnthroveUser{
UserID: anthroveUserID,
}
err := db.WithContext(ctx).First(&user, "id = ?", string(anthroveUserID)).Error
if err != nil {
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
}).Error("database: failed to get user")
return nil, err
}
err = db.WithContext(ctx).Model(&pgModels.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error
if err != nil {
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
}).Error("database: failed to get user sources")
return nil, err
}
for _, userSource := range userSources {
var source pgModels.Source
err = db.WithContext(ctx).Model(&pgModels.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error
if err != nil {
log.WithFields(log.Fields{
"source_id": userSource.SourceID,
}).Error("database: failed to get source")
return nil, err
}
anthroveUser.Relationship = append(anthroveUser.Relationship, graphModels.AnthroveUserRelationship{
UserID: userSource.AccountID,
Username: userSource.AccountUsername,
Source: graphModels.AnthroveSource{
DisplayName: source.DisplayName,
Domain: source.Domain,
Icon: source.Icon,
},
})
}
log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID,
}).Trace("database: got anthrove user")
return anthroveUser, nil
}
func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveUserID, error) {
var users []pgModels.User
var userIDs []models.AnthroveUserID
err := db.WithContext(ctx).Model(&pgModels.User{}).Find(&users).Error
if err != nil { if err != nil {
log.Error("database: failed to get all anthrove user IDs") log.Error("database: failed to get all anthrove user IDs")
return nil, err return nil, err
} }
for _, user := range users { for _, user := range users {
userIDs = append(userIDs, models.AnthroveUserID(user.ID)) userIDs = append(userIDs, user.ID)
} }
log.WithFields(log.Fields{ log.WithFields(log.Fields{
@ -275,11 +210,11 @@ func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveU
return userIDs, nil return userIDs, nil
} }
func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) { func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthroveUserID string, skip int, limit int) (*models.FavoriteList, error) {
var userFavorites []pgModels.UserFavorite var userFavorites []models.UserFavorite
var favoritePosts []graphModels.FavoritePost var favoritePosts []models.Post
err := db.WithContext(ctx).Model(&pgModels.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Offset(skip).Limit(limit).Find(&userFavorites).Error err := db.WithContext(ctx).Model(&models.UserFavorite{}).Where("user_id = ?", string(anthroveUserID)).Offset(skip).Limit(limit).Find(&userFavorites).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"anthrove_user_id": anthroveUserID, "anthrove_user_id": anthroveUserID,
@ -290,8 +225,8 @@ func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthrov
} }
for _, userFavorite := range userFavorites { for _, userFavorite := range userFavorites {
var post pgModels.Post var post models.Post
err = db.WithContext(ctx).Model(&pgModels.Post{}).Where("id = ?", userFavorite.PostID).First(&post).Error err = db.WithContext(ctx).Model(&models.Post{}).Where("id = ?", userFavorite.PostID).First(&post).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"post_id": userFavorite.PostID, "post_id": userFavorite.PostID,
@ -299,11 +234,10 @@ func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthrov
return nil, err return nil, err
} }
favoritePosts = append(favoritePosts, graphModels.FavoritePost{ favoritePosts = append(favoritePosts,
AnthrovePost: graphModels.AnthrovePost{ models.Post{
PostID: models.AnthrovePostID(post.ID), BaseModel: models.BaseModel{ID: post.ID},
Rating: post.Rating, Rating: post.Rating,
},
}) })
} }
@ -312,11 +246,11 @@ func GetUserFavoriteNodeWithPagination(ctx context.Context, db *gorm.DB, anthrov
"anthrove_user_fav_count": len(favoritePosts), "anthrove_user_fav_count": len(favoritePosts),
}).Trace("database: got all anthrove user favorites") }).Trace("database: got all anthrove user favorites")
return &graphModels.FavoriteList{Posts: favoritePosts}, nil return &models.FavoriteList{Posts: favoritePosts}, nil
} }
func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) { func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) {
var userFavorites []pgModels.UserFavorite var userFavorites []models.UserFavorite
err := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites).Error err := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
@ -329,8 +263,9 @@ func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, ant
name string name string
typeName string typeName string
}]int) }]int)
for _, userFavorite := range userFavorites { for _, userFavorite := range userFavorites {
var post pgModels.Post var post models.Post
err = db.WithContext(ctx).Preload("Tags").First(&post, "id = ?", userFavorite.PostID).Error err = db.WithContext(ctx).Preload("Tags").First(&post, "id = ?", userFavorite.PostID).Error
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
@ -347,13 +282,13 @@ func GetUserTagNodeWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, ant
} }
} }
var tagsWithFrequency []graphModels.TagsWithFrequency var tagsWithFrequency []models.TagsWithFrequency
for data, frequency := range tagFrequency { for data, frequency := range tagFrequency {
tagsWithFrequency = append(tagsWithFrequency, graphModels.TagsWithFrequency{ tagsWithFrequency = append(tagsWithFrequency, models.TagsWithFrequency{
Frequency: int64(frequency), Frequency: int64(frequency),
Tags: graphModels.AnthroveTag{ Tags: models.Tag{
Name: data.name, Name: data.name,
Type: data.typeName, Type: models.TagType(data.typeName),
}, },
}) })
} }

View File

@ -4,8 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
"git.dragse.it/anthrove/otter-space-sdk/test" "git.dragse.it/anthrove/otter-space-sdk/test"
"gorm.io/gorm" "gorm.io/gorm"
"reflect" "reflect"
@ -27,7 +25,7 @@ func TestCreateUser(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthroveUserID models.AnthroveUserID anthroveUserID string
} }
tests := []struct { tests := []struct {
name string name string
@ -73,7 +71,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
// Setup Test // Setup Test
source := &pgModels.Source{ source := &models.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
Icon: "icon.e621.net", Icon: "icon.e621.net",
@ -87,7 +85,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthroveUserID models.AnthroveUserID anthroveUserID string
sourceDomain string sourceDomain string
userID string userID string
username string username string
@ -103,7 +101,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "1", anthroveUserID: "1",
sourceDomain: "e621.net", sourceDomain: source.Domain,
userID: "e1", userID: "e1",
username: "marius", username: "marius",
}, },
@ -115,7 +113,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "2", anthroveUserID: "2",
sourceDomain: "e621.net", sourceDomain: source.Domain,
userID: "e1", userID: "e1",
username: "marius", username: "marius",
}, },
@ -127,7 +125,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "", anthroveUserID: "",
sourceDomain: "e621.net", sourceDomain: source.Domain,
userID: "e1", userID: "e1",
username: "marius", username: "marius",
}, },
@ -151,7 +149,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "1", anthroveUserID: "1",
sourceDomain: "e621.net", sourceDomain: source.Domain,
userID: "", userID: "",
username: "marius", username: "marius",
}, },
@ -163,7 +161,7 @@ func TestCreateUserNodeWithSourceRelation(t *testing.T) {
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,
anthroveUserID: "1", anthroveUserID: "1",
sourceDomain: "e621.net", sourceDomain: source.Domain,
userID: "aa", userID: "aa",
username: "", username: "",
}, },
@ -190,7 +188,7 @@ func TestGetAllAnthroveUserIDs(t *testing.T) {
// Setup Test // Setup Test
users := []models.AnthroveUserID{"1", "2", "3"} users := []string{"1", "2", "3"}
for _, user := range users { for _, user := range users {
err = CreateUser(ctx, gormDB, user) err = CreateUser(ctx, gormDB, user)
@ -207,7 +205,7 @@ func TestGetAllAnthroveUserIDs(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want []models.AnthroveUserID want []string
wantErr bool wantErr bool
}{ }{
{ {
@ -234,82 +232,6 @@ func TestGetAllAnthroveUserIDs(t *testing.T) {
} }
} }
func TestGetAnthroveUser(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
user := graphModels.AnthroveUser{
UserID: "1",
}
err = CreateUser(ctx, gormDB, user.UserID)
if err != nil {
t.Fatal(err)
}
// Test
type args struct {
ctx context.Context
db *gorm.DB
anthroveUserID models.AnthroveUserID
}
tests := []struct {
name string
args args
want *graphModels.AnthroveUser
wantErr bool
}{
{
name: "Test 1: Valid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "1",
},
want: &user,
wantErr: false,
},
{
name: "Test 2: Invalid AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "2",
},
want: nil,
wantErr: true,
},
{
name: "Test 3: No AnthroveUserID",
args: args{
ctx: ctx,
db: gormDB,
anthroveUserID: "",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetAnthroveUser(tt.args.ctx, tt.args.db, tt.args.anthroveUserID)
if (err != nil) != tt.wantErr {
t.Errorf("GetAnthroveUser() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAnthroveUser() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetSpecifiedUserSourceLink(t *testing.T) { func TestGetSpecifiedUserSourceLink(t *testing.T) {
// Setup trow away container // Setup trow away container
ctx := context.Background() ctx := context.Background()
@ -320,31 +242,33 @@ func TestGetSpecifiedUserSourceLink(t *testing.T) {
defer container.Terminate(ctx) defer container.Terminate(ctx)
// Setup Test // Setup Test
source := &pgModels.Source{
expectedResult := make(map[string]models.UserSource)
expectedResult["e621"] = models.UserSource{
UserID: "e1",
AccountUsername: "euser",
Source: models.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
},
} }
source := &models.Source{
DisplayName: expectedResult["e621"].Source.DisplayName,
Domain: expectedResult["e621"].Source.Domain,
}
err = CreateSourceNode(ctx, gormDB, source) err = CreateSourceNode(ctx, gormDB, source)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
expectedResult := make(map[string]graphModels.AnthroveUserRelationship) err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", source.Domain, expectedResult["e621"].UserID, expectedResult["e621"].AccountUsername)
expectedResult["e621"] = graphModels.AnthroveUserRelationship{
UserID: "e1",
Username: "euser",
Source: graphModels.AnthroveSource{
DisplayName: source.DisplayName,
Domain: source.Domain,
},
}
err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", source.Domain, expectedResult["e621"].UserID, expectedResult["e621"].Username)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Test
// Test
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
@ -354,7 +278,7 @@ func TestGetSpecifiedUserSourceLink(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want map[string]graphModels.AnthroveUserRelationship want map[string]models.UserSource
wantErr bool wantErr bool
}{ }{
{ {
@ -432,7 +356,7 @@ func TestGetSpecifiedUserSourceLink(t *testing.T) {
return return
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetSpecifiedUserSourceLink() got = %v, expectedResult %v", got, tt.want) t.Errorf("GetSpecifiedUserSourceLink() got = %v, want %v", got, tt.want)
} }
}) })
} }
@ -449,52 +373,41 @@ func TestGetUserFavoriteNodeWithPagination(t *testing.T) {
// Setup Test // Setup Test
expectedResultPostsGraph := []graphModels.FavoritePost{ expectedResultPosts := []models.Post{
{ {
AnthrovePost: graphModels.AnthrovePost{ BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post1")},
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post1")),
Rating: "safe", Rating: "safe",
}, },
},
{ {
AnthrovePost: graphModels.AnthrovePost{
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post2")), BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post2")},
Rating: "safe", Rating: "safe",
}, },
},
{ {
AnthrovePost: graphModels.AnthrovePost{ BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post3")},
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post3")),
Rating: "explicit", Rating: "explicit",
}, },
},
{ {
AnthrovePost: graphModels.AnthrovePost{ BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post4")},
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post4")),
Rating: "explicit", Rating: "explicit",
}, },
},
{ {
AnthrovePost: graphModels.AnthrovePost{ BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post5")},
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post5")),
Rating: "questionable", Rating: "questionable",
}, },
},
{ {
AnthrovePost: graphModels.AnthrovePost{ BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post6")},
PostID: models.AnthrovePostID(fmt.Sprintf("%-25s", "Post6")),
Rating: "safe", Rating: "safe",
}, },
},
} }
expectedResult := &graphModels.FavoriteList{ expectedResult := &models.FavoriteList{
Posts: expectedResultPostsGraph, Posts: expectedResultPosts,
} }
expectedResult2 := &graphModels.FavoriteList{ expectedResult2 := &models.FavoriteList{
Posts: expectedResultPostsGraph[2:], Posts: expectedResultPosts[2:],
} }
expectedResult3 := &graphModels.FavoriteList{ expectedResult3 := &models.FavoriteList{
Posts: expectedResultPostsGraph[:3], Posts: expectedResultPosts[:3],
} }
err = CreateUser(ctx, gormDB, "1") err = CreateUser(ctx, gormDB, "1")
@ -502,39 +415,12 @@ func TestGetUserFavoriteNodeWithPagination(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
expectedResultPostsPg := []pgModels.Post{ for _, expectedResultPost := range expectedResultPosts {
{ err = CreatePost(ctx, gormDB, &expectedResultPost)
BaseModel: pgModels.BaseModel{ID: "Post1"},
Rating: "safe",
},
{
BaseModel: pgModels.BaseModel{ID: "Post2"},
Rating: "safe",
},
{
BaseModel: pgModels.BaseModel{ID: "Post3"},
Rating: "explicit",
},
{
BaseModel: pgModels.BaseModel{ID: "Post4"},
Rating: "explicit",
},
{
BaseModel: pgModels.BaseModel{ID: "Post5"},
Rating: "questionable",
},
{
BaseModel: pgModels.BaseModel{ID: "Post6"},
Rating: "safe",
},
}
for _, expectedResultPost := range expectedResultPostsPg {
err = CreateAnthrovePostNode(ctx, gormDB, models.AnthrovePostID(expectedResultPost.ID), expectedResultPost.Rating)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = EstablishUserToPostLink(ctx, gormDB, "1", models.AnthrovePostID(expectedResultPost.ID)) err = EstablishUserToPostLink(ctx, gormDB, "1", expectedResultPost.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -544,14 +430,14 @@ func TestGetUserFavoriteNodeWithPagination(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
db *gorm.DB db *gorm.DB
anthroveUserID models.AnthroveUserID anthroveUserID string
skip int skip int
limit int limit int
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *graphModels.FavoriteList want *models.FavoriteList
wantErr bool wantErr bool
}{ }{
{ {
@ -621,39 +507,39 @@ func TestGetUserFavoritesCount(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
expectedResultPostsPg := []pgModels.Post{ expectedResultPosts := []models.Post{
{ {
BaseModel: pgModels.BaseModel{ID: "Post1"}, BaseModel: models.BaseModel{ID: "Post1"},
Rating: "safe", Rating: "safe",
}, },
{ {
BaseModel: pgModels.BaseModel{ID: "Post2"}, BaseModel: models.BaseModel{ID: "Post2"},
Rating: "safe", Rating: "safe",
}, },
{ {
BaseModel: pgModels.BaseModel{ID: "Post3"}, BaseModel: models.BaseModel{ID: "Post3"},
Rating: "explicit", Rating: "explicit",
}, },
{ {
BaseModel: pgModels.BaseModel{ID: "Post4"}, BaseModel: models.BaseModel{ID: "Post4"},
Rating: "explicit", Rating: "explicit",
}, },
{ {
BaseModel: pgModels.BaseModel{ID: "Post5"}, BaseModel: models.BaseModel{ID: "Post5"},
Rating: "questionable", Rating: "questionable",
}, },
{ {
BaseModel: pgModels.BaseModel{ID: "Post6"}, BaseModel: models.BaseModel{ID: "Post6"},
Rating: "safe", Rating: "safe",
}, },
} }
for _, expectedResultPost := range expectedResultPostsPg { for _, post := range expectedResultPosts {
err = CreateAnthrovePostNode(ctx, gormDB, models.AnthrovePostID(expectedResultPost.ID), expectedResultPost.Rating) err = CreatePost(ctx, gormDB, &post)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = EstablishUserToPostLink(ctx, gormDB, "1", models.AnthrovePostID(expectedResultPost.ID)) err = EstablishUserToPostLink(ctx, gormDB, "1", post.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -716,7 +602,7 @@ func TestGetUserFavoritesCount(t *testing.T) {
} }
} }
func TestGetUserSourceLink(t *testing.T) { func TestGetUserSourceLinks(t *testing.T) {
// Setup trow away containert // Setup trow away containert
ctx := context.Background() ctx := context.Background()
container, gormDB, err := test.StartPostgresContainer(ctx) container, gormDB, err := test.StartPostgresContainer(ctx)
@ -726,51 +612,51 @@ func TestGetUserSourceLink(t *testing.T) {
defer container.Terminate(ctx) defer container.Terminate(ctx)
// Setup Test // Setup Test
eSource := &models.Source{
esource := &pgModels.Source{
DisplayName: "e621", DisplayName: "e621",
Domain: "e621.net", Domain: "e621.net",
} }
err = CreateSourceNode(ctx, gormDB, esource) err = CreateSourceNode(ctx, gormDB, eSource)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
fasource := &pgModels.Source{ faSource := &models.Source{
DisplayName: "fa", DisplayName: "fa",
Domain: "fa.net", Domain: "fa.net",
} }
err = CreateSourceNode(ctx, gormDB, fasource) err = CreateSourceNode(ctx, gormDB, faSource)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
expectedResult := make(map[string]graphModels.AnthroveUserRelationship) expectedResult := make(map[string]models.UserSource)
expectedResult["e621"] = graphModels.AnthroveUserRelationship{ expectedResult["e621"] = models.UserSource{
UserID: "e1", UserID: "e1",
Username: "euser", AccountUsername: "e621-user",
Source: graphModels.AnthroveSource{ Source: models.Source{
DisplayName: esource.DisplayName, DisplayName: eSource.DisplayName,
Domain: esource.Domain, Domain: eSource.Domain,
}, },
} }
expectedResult["fa"] = graphModels.AnthroveUserRelationship{ expectedResult["fa"] = models.UserSource{
UserID: "fa1", UserID: "fa1",
Username: "fauser", AccountUsername: "fa-user",
Source: graphModels.AnthroveSource{ Source: models.Source{
DisplayName: fasource.DisplayName, DisplayName: faSource.DisplayName,
Domain: fasource.Domain, Domain: faSource.Domain,
}, },
} }
err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", esource.Domain, expectedResult["e621"].UserID, expectedResult["e621"].Username) err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", eSource.Domain, expectedResult["e621"].UserID, expectedResult["e621"].AccountUsername)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", fasource.Domain, expectedResult["fa"].UserID, expectedResult["fa"].Username) err = CreateUserNodeWithSourceRelation(ctx, gormDB, "1", faSource.Domain, expectedResult["fa"].UserID, expectedResult["fa"].AccountUsername)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Test // Test
type args struct { type args struct {
ctx context.Context ctx context.Context
@ -780,7 +666,7 @@ func TestGetUserSourceLink(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want map[string]graphModels.AnthroveUserRelationship want map[string]models.UserSource
wantErr bool wantErr bool
}{ }{
{ {
@ -796,13 +682,13 @@ func TestGetUserSourceLink(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) {
got, err := GetUserSourceLink(tt.args.ctx, tt.args.db, tt.args.anthroveUserID) got, err := GetUserSourceLinks(tt.args.ctx, tt.args.db, tt.args.anthroveUserID)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("GetUserSourceLink() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("GetUserSourceLinks() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetUserSourceLink() got = %v, want %v", got, tt.want) t.Errorf("GetUserSourceLinks() got = %v, want %v", got, tt.want)
} }
}) })
} }
@ -823,56 +709,56 @@ func TestGetUserTagNodeWitRelationToFavedPosts(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
posts := []pgModels.Post{ posts := []models.Post{
{BaseModel: pgModels.BaseModel{ID: fmt.Sprintf("%-25s", "Post1")}, Rating: "safe"}, {BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post1")}, Rating: "safe"},
{BaseModel: pgModels.BaseModel{ID: fmt.Sprintf("%-25s", "Post2")}, Rating: "safe"}, {BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post2")}, Rating: "safe"},
{BaseModel: pgModels.BaseModel{ID: fmt.Sprintf("%-25s", "Post3")}, Rating: "explicit"}, {BaseModel: models.BaseModel{ID: fmt.Sprintf("%-25s", "Post3")}, Rating: "explicit"},
} }
for _, post := range posts { for _, post := range posts {
err = CreateAnthrovePostNode(ctx, gormDB, models.AnthrovePostID(post.ID), post.Rating) err = CreatePost(ctx, gormDB, &post)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = EstablishUserToPostLink(ctx, gormDB, "1", models.AnthrovePostID(post.ID)) err = EstablishUserToPostLink(ctx, gormDB, "1", post.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
tags := []pgModels.Tag{ tags := []models.Tag{
{Name: "JayTheFerret", Type: "artist"}, {Name: "JayTheFerret", Type: "artist"},
{Name: "Ferret", Type: "species"}, {Name: "Ferret", Type: "species"},
{Name: "Jay", Type: "character"}, {Name: "Jay", Type: "character"},
} }
for i, tag := range tags { for i, tag := range tags {
err = CreateTagNodeWitRelation(ctx, gormDB, models.AnthrovePostID(posts[i].ID), &tag) err = CreateTagNodeWitRelation(ctx, gormDB, posts[i].ID, &tag)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
expectedResult := []graphModels.TagsWithFrequency{ expectedResult := []models.TagsWithFrequency{
{ {
Frequency: 1, Frequency: 1,
Tags: graphModels.AnthroveTag{ Tags: models.Tag{
Name: tags[0].Name, Name: tags[0].Name,
Type: string(tags[0].Type), Type: tags[0].Type,
}, },
}, },
{ {
Frequency: 1, Frequency: 1,
Tags: graphModels.AnthroveTag{ Tags: models.Tag{
Name: tags[1].Name, Name: tags[1].Name,
Type: string(tags[1].Type), Type: tags[1].Type,
}, },
}, },
{ {
Frequency: 1, Frequency: 1,
Tags: graphModels.AnthroveTag{ Tags: models.Tag{
Name: tags[2].Name, Name: tags[2].Name,
Type: string(tags[2].Type), Type: tags[2].Type,
}, },
}, },
} }
@ -886,11 +772,11 @@ func TestGetUserTagNodeWitRelationToFavedPosts(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want []graphModels.TagsWithFrequency want []models.TagsWithFrequency
wantErr bool wantErr bool
}{ }{
{ {
name: "", name: "Test 1: Get Data",
args: args{ args: args{
ctx: ctx, ctx: ctx,
db: gormDB, db: gormDB,

View File

@ -1,60 +0,0 @@
package utils
import (
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/pgModels"
)
// GraphConvertSource converts a graphModels.AnthroveSource to a pgModels.Source
func GraphConvertSource(graphSource *graphModels.AnthroveSource) *pgModels.Source {
pgSource := &pgModels.Source{
DisplayName: graphSource.DisplayName,
Domain: graphSource.Domain,
Icon: graphSource.Icon,
}
return pgSource
}
// PostgresConvertToAnthroveSource converts a pgModels.Source to a graphModels.AnthroveSource
func PostgresConvertToAnthroveSource(pgSource *pgModels.Source) *graphModels.AnthroveSource {
graphSource := &graphModels.AnthroveSource{
DisplayName: pgSource.DisplayName,
Domain: pgSource.Domain,
Icon: pgSource.Icon,
}
return graphSource
}
// GraphConvertTag converts a graphModels.AnthroveTag to a pgModels.Tag
func GraphConvertTag(graphTag *graphModels.AnthroveTag) *pgModels.Tag {
pgTag := &pgModels.Tag{
Name: graphTag.Name,
Type: models.TagType(graphTag.Type),
}
return pgTag
}
// PostgresConvertToAnthroveTag converts a pgModels.Tag to a graphModels.AnthroveTag
func PostgresConvertToAnthroveTag(pgTag *pgModels.Tag) *graphModels.AnthroveTag {
graphTag := &graphModels.AnthroveTag{
Name: pgTag.Name,
Type: string(pgTag.Type),
}
return graphTag
}
func ConvertToTagsWithFrequency(tags []pgModels.Tag) []graphModels.TagsWithFrequency {
var tagsWithFrequency []graphModels.TagsWithFrequency
for _, tag := range tags {
graphTag := PostgresConvertToAnthroveTag(&tag)
tagsWithFrequency = append(tagsWithFrequency, graphModels.TagsWithFrequency{
Frequency: 0,
Tags: *graphTag,
})
}
return tagsWithFrequency
}

View File

@ -1,116 +1,68 @@
// Package database provides a client for using the OtterSpace API.
//
// This package provides a client to interact with the OtterSpace API. It includes
// methods for all API endpoints, and convenience methods for common tasks.
//
// This is a simple usage example:
//
// package main
//
// import (
// "context"
// "fmt"
// "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
// "git.dragse.it/anthrove/otter-space-sdk/pkg/database"
// )
//
// func main() {
// client := database.NewGraphConnection()
// err := client.Connect(context.Background(), "your-endpoint", "your-username", "your-password")
// if err != nil {
// fmt.Println(err)
// return
// }
// // further usage of the client...
// }
package database package database
import ( import (
"context" "context"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
) )
// OtterSpace provides an interface for interacting with the OtterSpace API.
// It includes methods for connecting to the API, adding and linking users, posts, and sources,
// and retrieving information about users and posts.
type OtterSpace interface { type OtterSpace interface {
// Connect sets up a connection to the OtterSpace API endpoint using the provided username and password. // Connect establishes a connection to the database.
// It returns an error if the connection cannot be established.
Connect(ctx context.Context, endpoint string, username string, password string, database string, port int, ssl string, timezone string) error Connect(ctx context.Context, endpoint string, username string, password string, database string, port int, ssl string, timezone string) error
// AddUserWithRelationToSource adds a new user to the OtterSpace database and associates them with a source. // AddUserWithRelationToSource adds a user with a relation to a source.
// It returns the newly created user and an error if the operation fails.
AddUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error AddUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error
// AddSource adds a new source to the OtterSpace database. // AddSource adds a new source to the database.
// It returns an error if the operation fails. AddSource(ctx context.Context, anthroveSource *models.Source) error
AddSource(ctx context.Context, anthroveSource *graphModels.AnthroveSource) error
// AddPost adds a new post to the OtterSpace database. // AddPost adds a new post to the database.
// It returns an error if the operation fails. AddPost(ctx context.Context, anthrovePost *models.Post) error
AddPost(ctx context.Context, anthrovePost *graphModels.AnthrovePost) error
// AddTagWithRelationToPost adds a new tag to the OtterSpace database and associates it with a post. // AddTagWithRelationToPost adds a tag with a relation to a post.
// It returns an error if the operation fails. AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error
AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *graphModels.AnthroveTag) error
// LinkPostWithSource establishes a link between a post and a source in the OtterSpace database. // LinkPostWithSource links a post with a source.
// It returns an error if the operation fails. LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *models.PostReference) error
LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *graphModels.AnthrovePostRelationship) error
// LinkUserWithPost establishes a link between a user and a post in the OtterSpace database. // LinkUserWithPost links a user with a post.
// It returns an error if the operation fails. LinkUserWithPost(ctx context.Context, anthroveUser *models.User, anthrovePost *models.Post) error
LinkUserWithPost(ctx context.Context, anthroveUser *graphModels.AnthroveUser, anthrovePost *graphModels.AnthrovePost) error
// CheckUserPostLink checks if a link between a user and a post exists in the OtterSpace database. // CheckUserPostLink checks if a user-post link exists.
// It returns true if the link exists, false otherwise, and an error if the operation fails.
CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error) CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error)
// CheckPostNodeExistsByAnthroveID checks if a post node exists in the OtterSpace database by its Anthrove ID. // GetPostByAnthroveID retrieves a post by its Anthrove ID.
// It returns the post if it exists, a boolean indicating whether the post was found, and an error if the operation fails. GetPostByAnthroveID(ctx context.Context, anthrovePost *models.Post) (*models.Post, error)
CheckPostNodeExistsByAnthroveID(ctx context.Context, anthrovePost *graphModels.AnthrovePost) (*graphModels.AnthrovePost, bool, error)
// CheckPostNodeExistsBySourceURL checks if a post node exists in the OtterSpace database by its source URL. // GetPostBySourceURL retrieves a post by its source URL.
// It returns the post if it exists, a boolean indicating whether the post was found, and an error if the operation fails. GetPostBySourceURL(ctx context.Context, sourceUrl string) (*models.Post, error)
CheckPostNodeExistsBySourceURL(ctx context.Context, sourceUrl string) (*graphModels.AnthrovePost, bool, error)
// CheckPostNodeExistsBySourceID checks if a post node exists in the OtterSpace database by its source ID. // GetPostBySourceID retrieves a post by its source ID.
// It returns the post if it exists, a boolean indicating whether the post was found, and an error if the operation fails. GetPostBySourceID(ctx context.Context, sourcePostID string) (*models.Post, error)
CheckPostNodeExistsBySourceID(ctx context.Context, sourcePostID string) (*graphModels.AnthrovePost, bool, error)
// GetUserFavoriteCount retrieves the count of a user's favorite posts from the OtterSpace database. // GetUserFavoriteCount retrieves the count of a user's favorites.
// It returns the count and an error if the operation fails.
GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error) GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error)
// GetUserSourceLinks retrieves the links between a user and sources in the OtterSpace database. // GetUserSourceLinks retrieves the source links of a user.
// It returns a map of source domains to user-source relationships, and an error if the operation fails. GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error)
GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error)
// GetSpecifiedUserSourceLink GetUserSourceLinks retrieves the links between a user and a specific source in the OtterSpace database. // GetSpecifiedUserSourceLink retrieves a specified source link of a user.
// It returns a map of source domains to user-source relationships, and an error if the operation fails. GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error)
GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error)
// GetAnthroveUser retrieves a user from the OtterSpace database by their ID. // GetAllAnthroveUserIDs retrieves all Anthrove user IDs.
// It returns the user and an error if the operation fails.
GetAnthroveUser(ctx context.Context, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error)
// GetAllAnthroveUserIDs retrieves all user IDs from the OtterSpace database.
// It returns a slice of user IDs and an error if the operation fails.
GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error)
// GetUserFavoritePostsWithPagination gets all user favorites with relation and sources for the given user // GetUserFavoritePostsWithPagination retrieves a user's favorite posts with pagination.
GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error)
// GetUserTagsTroughFavedPosts returns a list of Tags that the user hs favorites through a post // GetUserTagsTroughFavedPosts retrieves a user's tags through their favorited posts.
GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error)
// GetAllTags returns a list of Tags that the user hs favorites through a post // GetAllTags retrieves all tags.
GetAllTags(ctx context.Context) ([]graphModels.TagsWithFrequency, error) GetAllTags(ctx context.Context) ([]models.TagsWithFrequency, error)
// GetAllSources returns a list of Sources in the database // GetAllSources retrieves all sources.
GetAllSources(ctx context.Context) ([]graphModels.AnthroveSource, error) GetAllSources(ctx context.Context) ([]models.Source, error)
// GetSourceByURL returns the Source Node based on the URL // GetSourceByURL retrieves a source by its URL.
GetSourceByURL(ctx context.Context, sourceUrl string) (*graphModels.AnthroveSource, error) GetSourceByURL(ctx context.Context, sourceUrl string) (*models.Source, error)
} }

View File

@ -1,123 +0,0 @@
package database
import (
"context"
"git.dragse.it/anthrove/otter-space-sdk/internal/graph"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
"github.com/neo4j/neo4j-go-driver/v5/neo4j/config"
)
type graphConnection struct {
driver neo4j.DriverWithContext
graphDebug bool
}
func NewGraphConnection(graphDebug bool) OtterSpace {
return &graphConnection{
driver: nil,
graphDebug: graphDebug,
}
}
func (g *graphConnection) Connect(ctx context.Context, endpoint string, username string, password string, _ string, _ int, _ string, _ string) error {
driver, err := neo4j.NewDriverWithContext(endpoint, neo4j.BasicAuth(username, password, ""),
logger(g.graphDebug))
if err != nil {
return err
}
err = driver.VerifyAuthentication(ctx, nil)
if err != nil {
return err
}
g.driver = driver
return nil
}
func (g *graphConnection) AddUserWithRelationToSource(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDomain string, userID string, username string) error {
return graph.CreateUserNodeWithSourceRelation(ctx, g.driver, anthroveUserID, sourceDomain, userID, username)
}
func (g *graphConnection) AddSource(ctx context.Context, anthroveSource *graphModels.AnthroveSource) error {
return graph.CreateSourceNode(ctx, g.driver, anthroveSource)
}
func (g *graphConnection) AddPost(ctx context.Context, anthrovePost *graphModels.AnthrovePost) error {
return graph.CreateAnthrovePostNode(ctx, g.driver, anthrovePost)
}
func (g *graphConnection) AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *graphModels.AnthroveTag) error {
return graph.CreateTagNodeWitRelation(ctx, g.driver, anthrovePostID, anthroveTag)
}
func (g *graphConnection) LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *graphModels.AnthrovePostRelationship) error {
return graph.EstablishAnthrovePostToSourceLink(ctx, g.driver, anthrovePostID, anthroveSourceDomain, anthrovePostRelationship)
}
func (g *graphConnection) LinkUserWithPost(ctx context.Context, anthroveUser *graphModels.AnthroveUser, anthrovePost *graphModels.AnthrovePost) error {
return graph.EstablishUserToPostLink(ctx, g.driver, anthroveUser, anthrovePost)
}
func (g *graphConnection) CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error) {
return graph.CheckUserToPostLink(ctx, g.driver, anthroveUserID, sourcePostID, sourceUrl)
}
func (g *graphConnection) CheckPostNodeExistsByAnthroveID(ctx context.Context, anthrovePost *graphModels.AnthrovePost) (*graphModels.AnthrovePost, bool, error) {
return graph.CheckIfAnthrovePostNodeExistsByAnthroveID(ctx, g.driver, anthrovePost)
}
func (g *graphConnection) CheckPostNodeExistsBySourceURL(ctx context.Context, sourceUrl string) (*graphModels.AnthrovePost, bool, error) {
return graph.CheckIfAnthrovePostNodeExistsBySourceURl(ctx, g.driver, sourceUrl)
}
func (g *graphConnection) CheckPostNodeExistsBySourceID(ctx context.Context, sourcePostID string) (*graphModels.AnthrovePost, bool, error) {
return graph.CheckIfAnthrovePostNodeExistsBySourceID(ctx, g.driver, sourcePostID)
}
func (g *graphConnection) GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error) {
return graph.GetUserFavoritesCount(ctx, g.driver, anthroveUserID)
}
func (g *graphConnection) GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error) {
return graph.GetUserSourceLink(ctx, g.driver, anthroveUserID)
}
func (g *graphConnection) GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error) {
return graph.GetSpecifiedUserSourceLink(ctx, g.driver, anthroveUserID, sourceDisplayName)
}
func (g *graphConnection) GetAnthroveUser(ctx context.Context, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error) {
return graph.GetAnthroveUser(ctx, g.driver, anthroveUserID)
}
func (g *graphConnection) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) {
return graph.GetAllAnthroveUserIDs(ctx, g.driver)
}
func (g *graphConnection) GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) {
return graph.GetUserFavoriteNodeWithPagination(ctx, g.driver, anthroveUserID, skip, limit)
}
func (g *graphConnection) GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) {
return graph.GetUserTagNodeWitRelationToFavedPosts(ctx, g.driver, anthroveUserID)
}
func (g *graphConnection) GetAllTags(ctx context.Context) ([]graphModels.TagsWithFrequency, error) {
return graph.GetTags(ctx, g.driver)
}
func (g *graphConnection) GetAllSources(ctx context.Context) ([]graphModels.AnthroveSource, error) {
return graph.GetAllSourceNodes(ctx, g.driver)
}
func (g *graphConnection) GetSourceByURL(ctx context.Context, sourceUrl string) (*graphModels.AnthroveSource, error) {
return graph.GetSourceNodesByURL(ctx, g.driver, sourceUrl)
}
func logger(graphDebug bool) func(config *config.Config) {
return func(config *config.Config) {
config.Log = graph.NewGraphLogger(graphDebug)
}
}

View File

@ -91,6 +91,7 @@ CREATE TABLE "UserSource"
( (
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 TEXT,
account_username TEXT, account_username TEXT,
account_id TEXT, account_id TEXT,
PRIMARY KEY (user_id, source_id), PRIMARY KEY (user_id, source_id),

View File

@ -6,9 +6,7 @@ import (
"embed" "embed"
"fmt" "fmt"
"git.dragse.it/anthrove/otter-space-sdk/internal/postgres" "git.dragse.it/anthrove/otter-space-sdk/internal/postgres"
"git.dragse.it/anthrove/otter-space-sdk/internal/utils"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models" "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
"git.dragse.it/anthrove/otter-space-sdk/pkg/models/graphModels"
_ "github.com/lib/pq" _ "github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate" migrate "github.com/rubenv/sql-migrate"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -70,97 +68,76 @@ func (p *postgresqlConnection) AddUserWithRelationToSource(ctx context.Context,
return postgres.CreateUserNodeWithSourceRelation(ctx, p.db, anthroveUserID, sourceDomain, userID, userID) return postgres.CreateUserNodeWithSourceRelation(ctx, p.db, anthroveUserID, sourceDomain, userID, userID)
} }
func (p *postgresqlConnection) AddSource(ctx context.Context, anthroveSource *graphModels.AnthroveSource) error { func (p *postgresqlConnection) AddSource(ctx context.Context, anthroveSource *models.Source) error {
source := utils.GraphConvertSource(anthroveSource) return postgres.CreateSourceNode(ctx, p.db, anthroveSource)
return postgres.CreateSourceNode(ctx, p.db, source)
} }
func (p *postgresqlConnection) AddPost(ctx context.Context, anthrovePost *graphModels.AnthrovePost) error { func (p *postgresqlConnection) AddPost(ctx context.Context, anthrovePost *models.Post) error {
return postgres.CreateAnthrovePostNode(ctx, p.db, anthrovePost.PostID, anthrovePost.Rating) return postgres.CreatePost(ctx, p.db, anthrovePost)
} }
func (p *postgresqlConnection) AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *graphModels.AnthroveTag) error { func (p *postgresqlConnection) AddTagWithRelationToPost(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveTag *models.Tag) error {
return postgres.CreateTagNodeWitRelation(ctx, p.db, anthrovePostID, utils.GraphConvertTag(anthroveTag)) return postgres.CreateTagNodeWitRelation(ctx, p.db, anthrovePostID, anthroveTag)
} }
func (p *postgresqlConnection) LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, anthroveSourceDomain string, anthrovePostRelationship *graphModels.AnthrovePostRelationship) error { func (p *postgresqlConnection) LinkPostWithSource(ctx context.Context, anthrovePostID models.AnthrovePostID, sourceDomain string, anthrovePostRelationship *models.PostReference) error {
return postgres.EstablishAnthrovePostToSourceLink(ctx, p.db, anthrovePostID, anthroveSourceDomain, anthrovePostRelationship) return postgres.EstablishAnthrovePostToSourceLink(ctx, p.db, anthrovePostID, sourceDomain, anthrovePostRelationship)
} }
func (p *postgresqlConnection) LinkUserWithPost(ctx context.Context, anthroveUser *graphModels.AnthroveUser, anthrovePost *graphModels.AnthrovePost) error { func (p *postgresqlConnection) LinkUserWithPost(ctx context.Context, anthroveUser *models.User, anthrovePost *models.Post) error {
return postgres.EstablishUserToPostLink(ctx, p.db, anthroveUser.UserID, anthrovePost.PostID) return postgres.EstablishUserToPostLink(ctx, p.db, anthroveUser.ID, anthrovePost.ID)
} }
func (p *postgresqlConnection) CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error) { func (p *postgresqlConnection) CheckUserPostLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourcePostID string, sourceUrl string) (bool, error) {
return postgres.CheckUserToPostLink(ctx, p.db, anthroveUserID, models.AnthrovePostID(sourcePostID)) return postgres.CheckUserToPostLink(ctx, p.db, anthroveUserID, models.AnthrovePostID(sourcePostID))
} }
func (p *postgresqlConnection) CheckPostNodeExistsByAnthroveID(ctx context.Context, anthrovePost *graphModels.AnthrovePost) (*graphModels.AnthrovePost, bool, error) { func (p *postgresqlConnection) GetPostByAnthroveID(ctx context.Context, anthrovePost *models.Post) (*models.Post, error) {
exists, err := postgres.CheckIfAnthrovePostNodeExistsByAnthroveID(ctx, p.db, anthrovePost.PostID) return postgres.GetPostByAnthroveID(ctx, p.db, anthrovePost.ID)
return anthrovePost, exists, err
} }
// CheckPostNodeExistsBySourceURL NOT WORKING! TODO! func (p *postgresqlConnection) GetPostBySourceURL(ctx context.Context, sourceUrl string) (*models.Post, error) {
func (p *postgresqlConnection) CheckPostNodeExistsBySourceURL(ctx context.Context, sourceUrl string) (*graphModels.AnthrovePost, bool, error) { return postgres.GetPostBySourceURL(ctx, p.db, sourceUrl)
post, exists, err := postgres.CheckIfAnthrovePostNodeExistsBySourceURL(ctx, p.db, sourceUrl)
return post, exists, err
} }
// CheckPostNodeExistsBySourceID NOT WORKING! TODO! func (p *postgresqlConnection) GetPostBySourceID(ctx context.Context, sourcePostID string) (*models.Post, error) {
func (p *postgresqlConnection) CheckPostNodeExistsBySourceID(ctx context.Context, sourcePostID string) (*graphModels.AnthrovePost, bool, error) { return postgres.GetPostBySourceID(ctx, p.db, sourcePostID)
var post graphModels.AnthrovePost
exists, err := postgres.CheckIfAnthrovePostNodeExistsBySourceID(ctx, p.db, sourcePostID)
return &post, exists, err
} }
func (p *postgresqlConnection) GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error) { func (p *postgresqlConnection) GetUserFavoriteCount(ctx context.Context, anthroveUserID models.AnthroveUserID) (int64, error) {
return postgres.GetUserFavoritesCount(ctx, p.db, anthroveUserID) return postgres.GetUserFavoritesCount(ctx, p.db, anthroveUserID)
} }
func (p *postgresqlConnection) GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]graphModels.AnthroveUserRelationship, error) { func (p *postgresqlConnection) GetUserSourceLinks(ctx context.Context, anthroveUserID models.AnthroveUserID) (map[string]models.UserSource, error) {
return postgres.GetUserSourceLink(ctx, p.db, anthroveUserID) return postgres.GetUserSourceLinks(ctx, p.db, anthroveUserID)
} }
func (p *postgresqlConnection) GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]graphModels.AnthroveUserRelationship, error) { func (p *postgresqlConnection) GetSpecifiedUserSourceLink(ctx context.Context, anthroveUserID models.AnthroveUserID, sourceDisplayName string) (map[string]models.UserSource, error) {
return postgres.GetSpecifiedUserSourceLink(ctx, p.db, anthroveUserID, sourceDisplayName) return postgres.GetSpecifiedUserSourceLink(ctx, p.db, anthroveUserID, sourceDisplayName)
} }
func (p *postgresqlConnection) GetAnthroveUser(ctx context.Context, anthroveUserID models.AnthroveUserID) (*graphModels.AnthroveUser, error) {
return postgres.GetAnthroveUser(ctx, p.db, anthroveUserID)
}
func (p *postgresqlConnection) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) { func (p *postgresqlConnection) GetAllAnthroveUserIDs(ctx context.Context) ([]models.AnthroveUserID, error) {
return postgres.GetAllAnthroveUserIDs(ctx, p.db) return postgres.GetAllAnthroveUserIDs(ctx, p.db)
} }
func (p *postgresqlConnection) GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*graphModels.FavoriteList, error) { func (p *postgresqlConnection) GetUserFavoritePostsWithPagination(ctx context.Context, anthroveUserID models.AnthroveUserID, skip int, limit int) (*models.FavoriteList, error) {
return postgres.GetUserFavoriteNodeWithPagination(ctx, p.db, anthroveUserID, skip, limit) return postgres.GetUserFavoriteNodeWithPagination(ctx, p.db, anthroveUserID, skip, limit)
} }
func (p *postgresqlConnection) GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]graphModels.TagsWithFrequency, error) { func (p *postgresqlConnection) GetUserTagsTroughFavedPosts(ctx context.Context, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) {
return postgres.GetUserTagNodeWitRelationToFavedPosts(ctx, p.db, anthroveUserID) return postgres.GetUserTagNodeWitRelationToFavedPosts(ctx, p.db, anthroveUserID)
} }
func (p *postgresqlConnection) GetAllTags(ctx context.Context) ([]graphModels.TagsWithFrequency, error) { func (p *postgresqlConnection) GetAllTags(ctx context.Context) ([]models.TagsWithFrequency, error) {
tags, err := postgres.GetTags(ctx, p.db) return postgres.GetTags(ctx, p.db)
return utils.ConvertToTagsWithFrequency(tags), err
} }
func (p *postgresqlConnection) GetAllSources(ctx context.Context) ([]graphModels.AnthroveSource, error) { func (p *postgresqlConnection) GetAllSources(ctx context.Context) ([]models.Source, error) {
var anthroveSources []graphModels.AnthroveSource return postgres.GetAllSourceNodes(ctx, p.db)
source, err := postgres.GetAllSourceNodes(ctx, p.db)
for _, v := range source {
anthroveSource := utils.PostgresConvertToAnthroveSource(&v)
anthroveSources = append(anthroveSources, *anthroveSource)
}
return nil, err
} }
func (p *postgresqlConnection) GetSourceByURL(ctx context.Context, sourceUrl string) (*graphModels.AnthroveSource, error) { func (p *postgresqlConnection) GetSourceByURL(ctx context.Context, sourceUrl string) (*models.Source, error) {
source, err := postgres.GetSourceNodesByURL(ctx, p.db, sourceUrl) return postgres.GetSourceNodesByURL(ctx, p.db, sourceUrl)
return utils.PostgresConvertToAnthroveSource(source), err
} }
func (p *postgresqlConnection) migrateDatabase(connectionString string) error { func (p *postgresqlConnection) migrateDatabase(connectionString string) error {

View File

@ -1,84 +0,0 @@
# Postgres
https://www.dbdiagram.io/d
````
Table User {
id string [primary key]
created_at timestamp
}
Table Post {
id varchar(25) [primary key]
rating Rating
created_at timestamp
}
Enum Rating {
safe
questionable
explicit
}
Table Source {
id varchar(25) [primary key]
display_name text
domain text [not null, unique]
}
Table Tag {
name text [primary key]
type TagType
}
Enum TagType {
general
species
character
artist
lore
meta
invalid
}
Table TagAlias {
name text [primary key]
tag_id text
}
Table TagGroup {
name text [primary key]
tag_id text
}
Table UserFavorites {
user_id text [primary key]
post_id text [primary key]
created_at timestamp
}
Table UserSource {
user_id text [primary key]
source_id text [primary key]
account_username text
account_id text
}
Table PostReference {
post_id text [primary key]
source_id text [primary key]
url text [not null, unique]
source_post_id text
}
Ref: Tag.name > TagAlias.tag_id
Ref: Tag.name > TagGroup.tag_id
Ref: Tag.name <> Post.id
Ref: UserFavorites.user_id > User.id
Ref: UserFavorites.post_id > Post.id
Ref: UserSource.user_id > User.id
Ref: UserSource.source_id > Source.id
Ref: PostReference.post_id > Post.id
Ref: PostReference.source_id > Source.id
````

View File

@ -1,20 +0,0 @@
package graphModels
type FavoriteRelations struct {
SourcesID string `json:"sources_id"`
Relations AnthrovePostRelationship `json:"relations"`
}
type FavoritePost struct {
AnthrovePost AnthrovePost `json:"anthrove_post"`
Relations []FavoriteRelations `json:"relations"`
}
type FavoriteList struct {
Posts []FavoritePost `json:"posts,omitempty"`
}
type TagsWithFrequency struct {
Frequency int64 `json:"frequency"`
Tags AnthroveTag `json:"tags"`
}

View File

@ -1,8 +0,0 @@
package graphModels
import "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
type AnthrovePost struct {
PostID models.AnthrovePostID `json:"post_id"`
Rating models.Rating `json:"rating"`
}

View File

@ -1,12 +0,0 @@
package graphModels
type AnthroveUserRelationship struct {
UserID string `json:"user_id"`
Username string `json:"username"`
ScrapeTimeInterval string `json:"scrape_time_interval"`
Source AnthroveSource `json:"source"`
}
type AnthrovePostRelationship struct {
PostID string `json:"post_id"`
Url string `json:"url"`
}

View File

@ -1,7 +0,0 @@
package graphModels
type AnthroveSource struct {
DisplayName string `json:"display_name"`
Domain string `json:"domain"`
Icon string `json:"icon"`
}

View File

@ -1,6 +0,0 @@
package graphModels
type AnthroveTag struct {
Name string `json:"name"`
Type string `json:"type"`
}

View File

@ -1,8 +0,0 @@
package graphModels
import "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
type AnthroveUser struct {
UserID models.AnthroveUserID `json:"user_id"`
Relationship []AnthroveUserRelationship `json:"relationship"`
}

View File

@ -1,4 +1,4 @@
package pgModels package models
import ( import (
gonanoid "github.com/matoous/go-nanoid/v2" gonanoid "github.com/matoous/go-nanoid/v2"

View File

@ -1,13 +0,0 @@
package pgModels
type UserSource struct {
UserID string `gorm:"primaryKey"`
Source Source `gorm:"foreignKey:ID;references:SourceID"`
SourceID string `gorm:"primaryKey"`
AccountUsername string
AccountID string
}
func (UserSource) TableName() string {
return "UserSource"
}

View File

@ -1,13 +1,9 @@
package pgModels package models
import (
"git.dragse.it/anthrove/otter-space-sdk/pkg/models"
)
// Post model // Post model
type Post struct { type Post struct {
BaseModel BaseModel
Rating models.Rating `gorm:"type:enum('safe','questionable','explicit')"` Rating Rating `gorm:"type:enum('safe','questionable','explicit')"`
Tags []Tag `gorm:"many2many:post_tags;"` Tags []Tag `gorm:"many2many:post_tags;"`
Favorites []UserFavorite `gorm:"foreignKey:PostID"` Favorites []UserFavorite `gorm:"foreignKey:PostID"`
References []PostReference `gorm:"foreignKey:PostID"` References []PostReference `gorm:"foreignKey:PostID"`

View File

@ -1,4 +1,4 @@
package pgModels package models
type PostReference struct { type PostReference struct {
PostID string `gorm:"primaryKey"` PostID string `gorm:"primaryKey"`

View File

@ -1,4 +1,4 @@
package pgModels package models
// Source model // Source model
type Source struct { type Source struct {

View File

@ -1,11 +1,9 @@
package pgModels package models
import "git.dragse.it/anthrove/otter-space-sdk/pkg/models"
// Tag models // Tag models
type Tag struct { type Tag struct {
Name string `gorm:"primaryKey"` Name string `gorm:"primaryKey"`
Type models.TagType `gorm:"column:tag_type"` Type TagType `gorm:"column:tag_type"`
Aliases []TagAlias `gorm:"foreignKey:TagID"` Aliases []TagAlias `gorm:"foreignKey:TagID"`
Groups []TagGroup `gorm:"foreignKey:TagID"` Groups []TagGroup `gorm:"foreignKey:TagID"`
Posts []Post `gorm:"many2many:post_tags;"` Posts []Post `gorm:"many2many:post_tags;"`
@ -34,3 +32,8 @@ type TagGroup struct {
func (TagGroup) TableName() string { func (TagGroup) TableName() string {
return "TagGroup" return "TagGroup"
} }
type TagsWithFrequency struct {
Frequency int64 `json:"frequency"`
Tags Tag `json:"tags"`
}

View File

@ -1,4 +1,4 @@
package pgModels package models
// User model // User model
type User struct { type User struct {

View File

@ -1,4 +1,4 @@
package pgModels package models
import "time" import "time"
@ -11,3 +11,7 @@ type UserFavorite struct {
func (UserFavorite) TableName() string { func (UserFavorite) TableName() string {
return "UserFavorites" return "UserFavorites"
} }
type FavoriteList struct {
Posts []Post `json:"posts,omitempty"`
}

15
pkg/models/userSource.go Normal file
View File

@ -0,0 +1,15 @@
package models
type UserSource struct {
User User `gorm:"foreignKey:ID;references:UserID"`
UserID string `gorm:"primaryKey"`
Source Source `gorm:"foreignKey:ID;references:SourceID"`
SourceID string `gorm:"primaryKey"`
ScrapeTimeInterval string
AccountUsername string
AccountID string
}
func (UserSource) TableName() string {
return "UserSource"
}