diff --git a/dataloader/loaders.go b/dataloader/loaders.go index 7eeb6512..8f3523d7 100644 --- a/dataloader/loaders.go +++ b/dataloader/loaders.go @@ -47,7 +47,7 @@ func Middleware() func(handlerFunc echo.HandlerFunc) echo.HandlerFunc { if u, ok := byID[id]; ok { results[i] = &dataloader.Result[[]*ent.VersionDependency]{Data: u} } else { - results[i] = &dataloader.Result[[]*ent.VersionDependency]{Error: errors.New("version not found")} + results[i] = &dataloader.Result[[]*ent.VersionDependency]{Data: []*ent.VersionDependency{}} } } @@ -70,7 +70,7 @@ func Middleware() func(handlerFunc echo.HandlerFunc) echo.HandlerFunc { if u, ok := byID[id]; ok { results[i] = &dataloader.Result[[]*ent.UserMod]{Data: u} } else { - results[i] = &dataloader.Result[[]*ent.UserMod]{Error: errors.New("version not found")} + results[i] = &dataloader.Result[[]*ent.UserMod]{Error: errors.New("mod not found")} } } @@ -97,7 +97,7 @@ func Middleware() func(handlerFunc echo.HandlerFunc) echo.HandlerFunc { if u, ok := byID[id]; ok { results[i] = &dataloader.Result[[]*ent.Version]{Data: u} } else { - results[i] = &dataloader.Result[[]*ent.Version]{Error: errors.New("version not found")} + results[i] = &dataloader.Result[[]*ent.Version]{Data: []*ent.Version{}} } } @@ -145,7 +145,7 @@ func Middleware() func(handlerFunc echo.HandlerFunc) echo.HandlerFunc { if u, ok := byID[id]; ok { results[i] = &dataloader.Result[[]*ent.Version]{Data: u} } else { - results[i] = &dataloader.Result[[]*ent.Version]{Error: errors.New("version not found")} + results[i] = &dataloader.Result[[]*ent.Version]{Data: []*ent.Version{}} } } diff --git a/db/mod.go b/db/mod.go index 2e3f212a..c61fa064 100644 --- a/db/mod.go +++ b/db/mod.go @@ -28,22 +28,31 @@ func ConvertModFilter(query *ent.ModQuery, filter *models.ModFilter, count bool, if filter.OrderBy != nil && *filter.OrderBy != generated.ModFieldsSearch { if string(*filter.OrderBy) == "last_version_date" { - query = query.Modify(func(s *sql.Selector) { - s.OrderExpr(sql.ExprP("case when last_version_date is null then 1 else 0 end, last_version_date")) - }).Clone() - } else { - query = query.Order(sql.OrderByField( - filter.OrderBy.String(), - OrderToOrder(filter.Order.String()), - ).ToFunc()) + query = query.Order(func(s *sql.Selector) { + s.OrderExpr(sql.ExprP("case when last_version_date is null then 1 else 0 end")) + }) } + query = query.Order(sql.OrderByField( + filter.OrderBy.String(), + OrderToOrder(filter.Order.String()), + ).ToFunc()) } if filter.Search != nil && *filter.Search != "" { cleanSearch := strings.ReplaceAll(strings.TrimSpace(*filter.Search), " ", " & ") query = query.Where(func(s *sql.Selector) { - join := sql.SelectExpr(sql.ExprP("id, (similarity(name, ?) * 2 + similarity(short_description, ?) + similarity(full_description, ?) * 0.5) as s", cleanSearch, cleanSearch, cleanSearch)) + join := sql.Select("id") + join = join.AppendSelectExprAs( + sql.P(func(builder *sql.Builder) { + builder.WriteString("similarity(name, ").Arg(cleanSearch).WriteString(") * 2"). + WriteString(" + "). + WriteString("similarity(short_description, ").Arg(cleanSearch).WriteString(")"). + WriteString(" + "). + WriteString("similarity(full_description, ").Arg(cleanSearch).WriteString(") * 0.5") + }), + "s", + ) join.From(sql.Table(mod.Table)).As("t1") s.Join(join).On(s.C(mod.FieldID), join.C("id")) }) @@ -64,10 +73,7 @@ func ConvertModFilter(query *ent.ModQuery, filter *models.ModFilter, count bool, } if filter.TagIDs != nil && len(filter.TagIDs) > 0 { - query = query.Where(func(s *sql.Selector) { - t := sql.Table(modtag.Table) - s.Join(t).OnP(sql.ExprP("mod_tags.tag_id in ? AND mod_tags.mod_id = mods.id", filter.TagIDs)) - }) + query = query.Where(mod.HasModTagsWith(modtag.TagIDIn(filter.TagIDs...))) } } diff --git a/db/oauth.go b/db/oauth.go index abdf0cde..0f5b03de 100644 --- a/db/oauth.go +++ b/db/oauth.go @@ -5,6 +5,7 @@ import ( "context" "github.com/satisfactorymodding/smr-api/generated/ent" + "github.com/satisfactorymodding/smr-api/generated/ent/predicate" "github.com/satisfactorymodding/smr-api/generated/ent/user" "github.com/satisfactorymodding/smr-api/oauth" "github.com/satisfactorymodding/smr-api/storage" @@ -15,16 +16,18 @@ func CompleteOAuthFlow(ctx context.Context, u *oauth.UserData, userAgent string) avatarURL := u.Avatar u.Avatar = "" - find := From(ctx).User.Query().Where(user.Email(u.Email)) + var oauthPredicate predicate.User if u.Site == oauth.SiteGithub { - find = find.Where(user.GithubID(u.ID)) + oauthPredicate = user.GithubID(u.ID) } else if u.Site == oauth.SiteGoogle { - find = find.Where(user.GoogleID(u.ID)) + oauthPredicate = user.GoogleID(u.ID) } else if u.Site == oauth.SiteFacebook { - find = find.Where(user.FacebookID(u.ID)) + oauthPredicate = user.FacebookID(u.ID) } + find := From(ctx).User.Query().Where(user.Or(user.Email(u.Email), oauthPredicate)) + found, err := find.First(ctx) if err != nil && !ent.IsNotFound(err) { return nil, err diff --git a/gql/resolver_guides.go b/gql/resolver_guides.go index 15aa809d..ca997980 100644 --- a/gql/resolver_guides.go +++ b/gql/resolver_guides.go @@ -207,9 +207,13 @@ func convertGuideFilter(query *ent.GuideQuery, filter *models.GuideFilter) *ent. ).ToFunc()) if filter.Search != nil && *filter.Search != "" { + cleanedSearch := strings.ReplaceAll(*filter.Search, " ", " & ") + query = query.Modify(func(s *sql.Selector) { - s.Where(sql.ExprP("to_tsvector(name) @@ to_tsquery(?)", strings.ReplaceAll(*filter.Search, " ", " & "))) - }).Clone() + s.Where(sql.P(func(builder *sql.Builder) { + builder.WriteString("to_tsvector(name) @@ to_tsquery(").Arg(cleanedSearch).WriteString(")") + })) + }).GuideQuery } if filter.TagIDs != nil && len(filter.TagIDs) > 0 { diff --git a/gql/resolver_mods.go b/gql/resolver_mods.go index bd64daa0..29e82daa 100644 --- a/gql/resolver_mods.go +++ b/gql/resolver_mods.go @@ -244,12 +244,28 @@ func (r *mutationResolver) UpdateMod(ctx context.Context, modID string, updateMo role = "editor" } - if err := db.From(ctx).UserMod.Create(). - SetUserID(userMod.UserID). - SetModID(modID). - SetRole(role). - Exec(ctx); err != nil { - return nil, err + var existing *ent.UserMod + for _, author := range authors { + if author.UserID == userMod.UserID { + existing = author + break + } + } + + if existing != nil { + if err := db.From(ctx).UserMod.UpdateOne(existing). + SetRole(role). + Exec(ctx); err != nil { + return nil, err + } + } else { + if err := db.From(ctx).UserMod.Create(). + SetUserID(userMod.UserID). + SetModID(modID). + SetRole(role). + Exec(ctx); err != nil { + return nil, err + } } } } diff --git a/gql/resolver_sml_versions.go b/gql/resolver_sml_versions.go index bceb993e..14906ce3 100644 --- a/gql/resolver_sml_versions.go +++ b/gql/resolver_sml_versions.go @@ -232,9 +232,13 @@ func convertSMLVersionFilter(query *ent.SmlVersionQuery, filter *models.SMLVersi ).ToFunc()) if filter.Search != nil && *filter.Search != "" { + cleanedSearch := strings.ReplaceAll(*filter.Search, " ", " & ") + query = query.Modify(func(s *sql.Selector) { - s.Where(sql.ExprP("to_tsvector(name) @@ to_tsquery(?)", strings.ReplaceAll(*filter.Search, " ", " & "))) - }).Clone() + s.Where(sql.P(func(builder *sql.Builder) { + builder.WriteString("to_tsvector(version) @@ to_tsquery(").Arg(cleanedSearch).WriteString(")") + })) + }).SmlVersionQuery } } return query diff --git a/gql/resolver_tags.go b/gql/resolver_tags.go index 452e56ca..f9731974 100644 --- a/gql/resolver_tags.go +++ b/gql/resolver_tags.go @@ -95,9 +95,10 @@ func (r *queryResolver) GetTags(ctx context.Context, filter *generated.TagFilter cleanSearch := strings.ReplaceAll(strings.TrimSpace(*filter.Search), " ", " & ") query = query.Modify(func(s *sql.Selector) { - s.AppendSelectExpr(sql.Expr("similarity(name, ?) as s", cleanSearch)) - s.Where(sql.ExprP("s > 0.2")) - }).Clone() + s.Where(sql.P(func(builder *sql.Builder) { + builder.WriteString("similarity(name, ").Arg(cleanSearch).WriteString(") > 0.2") + })) + }).TagQuery } if filter.Ids != nil && len(filter.Ids) > 0 { diff --git a/gql/resolver_users.go b/gql/resolver_users.go index 3f14a250..7ad726de 100644 --- a/gql/resolver_users.go +++ b/gql/resolver_users.go @@ -300,7 +300,7 @@ func (r *userModResolver) User(ctx context.Context, obj *generated.UserMod) (*ge } func (r *userModResolver) Mod(ctx context.Context, obj *generated.UserMod) (*generated.Mod, error) { - result, err := db.From(ctx).Mod.Get(ctx, obj.ModID) + result, err := db.From(ctx).Mod.Query().WithTags().Where(mod.ID(obj.ModID)).Only(ctx) if err != nil { return nil, err } diff --git a/gql/resolver_versions.go b/gql/resolver_versions.go index 11bf9d67..9bf8f63a 100644 --- a/gql/resolver_versions.go +++ b/gql/resolver_versions.go @@ -472,9 +472,13 @@ func convertVersionFilter(query *ent.VersionQuery, filter *models.VersionFilter, ).ToFunc()) if filter.Search != nil && *filter.Search != "" { + cleanedSearch := strings.ReplaceAll(*filter.Search, " ", " & ") + query = query.Modify(func(s *sql.Selector) { - s.Where(sql.ExprP("to_tsvector(name) @@ to_tsquery(?)", strings.ReplaceAll(*filter.Search, " ", " & "))) - }).Clone() + s.Where(sql.P(func(builder *sql.Builder) { + builder.WriteString("to_tsvector(version) @@ to_tsquery(").Arg(cleanedSearch).WriteString(")") + })) + }).VersionQuery } } diff --git a/migrations/utils/utils.go b/migrations/utils/utils.go index f15f9002..9ea0cf14 100644 --- a/migrations/utils/utils.go +++ b/migrations/utils/utils.go @@ -16,7 +16,7 @@ func ReindexAllModFiles(ctx context.Context, withMetadata bool, modFilter func(* offset := 0 for { - mods, err := db.From(ctx).Mod.Query().Limit(100).Offset(100).Order(mod.ByCreatedAt(sql.OrderDesc())).All(ctx) + mods, err := db.From(ctx).Mod.Query().Limit(100).Offset(offset).Order(mod.ByCreatedAt(sql.OrderDesc())).All(ctx) if err != nil { return err } diff --git a/util/converter/converter_windows.go b/util/converter/converter_windows.go index 725e9e08..a9860ce3 100755 --- a/util/converter/converter_windows.go +++ b/util/converter/converter_windows.go @@ -9,6 +9,7 @@ import ( "github.com/Vilsol/slox" "github.com/chai2010/webp" + // GIF Support _ "image/gif" // JPEG Support