From b2d0a3dda64c65f802ea8ea77fe18364926b0943 Mon Sep 17 00:00:00 2001 From: Ian McKenzie Date: Fri, 20 Dec 2024 23:43:58 -0700 Subject: [PATCH] Add ability to find scene updated times by id list --- .../src/graphql/queries/ScenesUpdates.gql | 6 + frontend/src/graphql/types.ts | 79 ++++ graphql/schema/schema.graphql | 3 + graphql/schema/types/scene.graphql | 5 + pkg/api/resolver_query_find_scene.go | 12 +- pkg/models/generated_exec.go | 349 +++++++++++++++++- pkg/models/generated_models.go | 5 + pkg/models/scene.go | 1 + pkg/sqlx/querybuilder_scene.go | 23 ++ 9 files changed, 481 insertions(+), 2 deletions(-) create mode 100644 frontend/src/graphql/queries/ScenesUpdates.gql diff --git a/frontend/src/graphql/queries/ScenesUpdates.gql b/frontend/src/graphql/queries/ScenesUpdates.gql new file mode 100644 index 000000000..52114814a --- /dev/null +++ b/frontend/src/graphql/queries/ScenesUpdates.gql @@ -0,0 +1,6 @@ +query ScenesUpdates($ids: [ID!]!) { + findScenesUpdates(ids: $ids) { + ids + updated + } +} diff --git a/frontend/src/graphql/types.ts b/frontend/src/graphql/types.ts index fb46820a0..1b2ddc5c7 100644 --- a/frontend/src/graphql/types.ts +++ b/frontend/src/graphql/types.ts @@ -1181,6 +1181,8 @@ export type Query = { /** @deprecated Use findScenesBySceneFingerprints */ findScenesByFullFingerprints: Array; findScenesBySceneFingerprints: Array>; + /** Find scene updated time by ID */ + findScenesUpdates?: Maybe; /** Find an external site by ID */ findSite?: Maybe; /** Find a studio by ID or name */ @@ -1255,6 +1257,11 @@ export type QueryFindScenesBySceneFingerprintsArgs = { fingerprints: Array>; }; +/** The query root for this schema */ +export type QueryFindScenesUpdatesArgs = { + ids: Array; +}; + /** The query root for this schema */ export type QueryFindSiteArgs = { id: Scalars["ID"]["input"]; @@ -1410,6 +1417,12 @@ export type QueryScenesResultType = { scenes: Array; }; +export type QueryScenesUpdatesResult = { + __typename: "QueryScenesUpdatesResult"; + ids: Array; + updated: Array; +}; + export type QuerySitesResultType = { __typename: "QuerySitesResultType"; count: Scalars["Int"]["output"]; @@ -29957,6 +29970,18 @@ export type ScenesQuery = { }; }; +export type ScenesUpdatesQueryVariables = Exact<{ + ids: Array | Scalars["ID"]["input"]; +}>; + +export type ScenesUpdatesQuery = { + __typename: "Query"; + findScenesUpdates?: { + __typename: "QueryScenesUpdatesResult"; + ids: Array; + } | null; +}; + export type ScenesWithFingerprintsQueryVariables = Exact<{ input: SceneQueryInput; submitted: Scalars["Boolean"]["input"]; @@ -65258,6 +65283,60 @@ export const ScenesDocument = { }, ], } as unknown as DocumentNode; +export const ScenesUpdatesDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { kind: "Name", value: "ScenesUpdates" }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "ids" } }, + type: { + kind: "NonNullType", + type: { + kind: "ListType", + type: { + kind: "NonNullType", + type: { + kind: "NamedType", + name: { kind: "Name", value: "ID" }, + }, + }, + }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "findScenesUpdates" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "ids" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "ids" }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "ids" } }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode; export const ScenesWithFingerprintsDocument = { kind: "Document", definitions: [ diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 8431c4a75..eb2fc0509 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -45,6 +45,9 @@ type Query { findSite(id: ID!): Site @hasRole(role: READ) querySites: QuerySitesResultType! @hasRole(role: READ) + """Find scene updated time by ID""" + findScenesUpdates(ids: [ID!]!): QueryScenesUpdatesResult @hasRole(role: READ) + #### Edits #### findEdit(id: ID!): Edit @hasRole(role: READ) diff --git a/graphql/schema/types/scene.graphql b/graphql/schema/types/scene.graphql index b979b4786..72392bda3 100644 --- a/graphql/schema/types/scene.graphql +++ b/graphql/schema/types/scene.graphql @@ -288,3 +288,8 @@ type QueryExistingSceneResult { edits: [Edit!]! scenes: [Scene!]! } + +type QueryScenesUpdatesResult { + ids: [ID!]! + updated: [Time!]! +} \ No newline at end of file diff --git a/pkg/api/resolver_query_find_scene.go b/pkg/api/resolver_query_find_scene.go index 7e6e8c1c9..d7738951a 100644 --- a/pkg/api/resolver_query_find_scene.go +++ b/pkg/api/resolver_query_find_scene.go @@ -3,7 +3,6 @@ package api import ( "context" "errors" - "github.com/gofrs/uuid" "github.com/stashapp/stash-box/pkg/manager/config" @@ -116,6 +115,17 @@ func (r *queryResolver) FindScenesBySceneFingerprints(ctx context.Context, scene return result, nil } +func (r *queryResolver) FindScenesUpdates(ctx context.Context, ids []uuid.UUID) (*models.QueryScenesUpdatesResult, error) { + if len(ids) > 100 { + return nil, errors.New("too many ids, request less than 100 ids") + } + + fac := r.getRepoFactory(ctx) + qb := fac.Scene() + + return qb.FindUpdatesByIds(ids) +} + type querySceneResolver struct{ *Resolver } func (r *querySceneResolver) Count(ctx context.Context, obj *models.SceneQuery) (int, error) { diff --git a/pkg/models/generated_exec.go b/pkg/models/generated_exec.go index c1b60dc97..e068c2447 100644 --- a/pkg/models/generated_exec.go +++ b/pkg/models/generated_exec.go @@ -401,6 +401,7 @@ type ComplexityRoot struct { FindScenesByFingerprints func(childComplexity int, fingerprints []string) int FindScenesByFullFingerprints func(childComplexity int, fingerprints []*FingerprintQueryInput) int FindScenesBySceneFingerprints func(childComplexity int, fingerprints [][]*FingerprintQueryInput) int + FindScenesUpdates func(childComplexity int, ids []uuid.UUID) int FindSite func(childComplexity int, id uuid.UUID) int FindStudio func(childComplexity int, id *uuid.UUID, name *string) int FindTag func(childComplexity int, id *uuid.UUID, name *string) int @@ -458,6 +459,11 @@ type ComplexityRoot struct { Scenes func(childComplexity int) int } + QueryScenesUpdatesResult struct { + Ids func(childComplexity int) int + Updated func(childComplexity int) int + } + QuerySitesResultType struct { Count func(childComplexity int) int Sites func(childComplexity int) int @@ -859,6 +865,7 @@ type QueryResolver interface { QueryScenes(ctx context.Context, input SceneQueryInput) (*SceneQuery, error) FindSite(ctx context.Context, id uuid.UUID) (*Site, error) QuerySites(ctx context.Context) (*QuerySitesResultType, error) + FindScenesUpdates(ctx context.Context, ids []uuid.UUID) (*QueryScenesUpdatesResult, error) FindEdit(ctx context.Context, id uuid.UUID) (*Edit, error) QueryEdits(ctx context.Context, input EditQueryInput) (*EditQuery, error) FindUser(ctx context.Context, id *uuid.UUID, username *string) (*User, error) @@ -2975,6 +2982,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.FindScenesBySceneFingerprints(childComplexity, args["fingerprints"].([][]*FingerprintQueryInput)), true + case "Query.findScenesUpdates": + if e.complexity.Query.FindScenesUpdates == nil { + break + } + + args, err := ec.field_Query_findScenesUpdates_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.FindScenesUpdates(childComplexity, args["ids"].([]uuid.UUID)), true + case "Query.findSite": if e.complexity.Query.FindSite == nil { break @@ -3329,6 +3348,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.QueryScenesResultType.Scenes(childComplexity), true + case "QueryScenesUpdatesResult.ids": + if e.complexity.QueryScenesUpdatesResult.Ids == nil { + break + } + + return e.complexity.QueryScenesUpdatesResult.Ids(childComplexity), true + + case "QueryScenesUpdatesResult.updated": + if e.complexity.QueryScenesUpdatesResult.Updated == nil { + break + } + + return e.complexity.QueryScenesUpdatesResult.Updated(childComplexity), true + case "QuerySitesResultType.count": if e.complexity.QuerySitesResultType.Count == nil { break @@ -5717,7 +5750,11 @@ type QueryExistingSceneResult { edits: [Edit!]! scenes: [Scene!]! } -`, BuiltIn: false}, + +type QueryScenesUpdatesResult { + ids: [ID!]! + updated: [Time!]! +}`, BuiltIn: false}, {Name: "../../graphql/schema/types/site.graphql", Input: `type Site { id: ID! name: String! @@ -6205,6 +6242,9 @@ type Query { findSite(id: ID!): Site @hasRole(role: READ) querySites: QuerySitesResultType! @hasRole(role: READ) + """Find scene updated time by ID""" + findScenesUpdates(ids: [ID!]!): QueryScenesUpdatesResult @hasRole(role: READ) + #### Edits #### findEdit(id: ID!): Edit @hasRole(role: READ) @@ -8568,6 +8608,38 @@ func (ec *executionContext) field_Query_findScenesBySceneFingerprints_argsFinger return zeroVal, nil } +func (ec *executionContext) field_Query_findScenesUpdates_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Query_findScenesUpdates_argsIds(ctx, rawArgs) + if err != nil { + return nil, err + } + args["ids"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query_findScenesUpdates_argsIds( + ctx context.Context, + rawArgs map[string]interface{}, +) ([]uuid.UUID, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["ids"] + if !ok { + var zeroVal []uuid.UUID + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("ids")) + if tmp, ok := rawArgs["ids"]; ok { + return ec.unmarshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, tmp) + } + + var zeroVal []uuid.UUID + return zeroVal, nil +} + func (ec *executionContext) field_Query_findSite_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -24498,6 +24570,91 @@ func (ec *executionContext) fieldContext_Query_querySites(_ context.Context, fie return fc, nil } +func (ec *executionContext) _Query_findScenesUpdates(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_findScenesUpdates(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().FindScenesUpdates(rctx, fc.Args["ids"].([]uuid.UUID)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋpkgᚋmodelsᚐRoleEnum(ctx, "READ") + if err != nil { + var zeroVal *QueryScenesUpdatesResult + return zeroVal, err + } + if ec.directives.HasRole == nil { + var zeroVal *QueryScenesUpdatesResult + return zeroVal, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*QueryScenesUpdatesResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/stashapp/stash-box/pkg/models.QueryScenesUpdatesResult`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*QueryScenesUpdatesResult) + fc.Result = res + return ec.marshalOQueryScenesUpdatesResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋpkgᚋmodelsᚐQueryScenesUpdatesResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_findScenesUpdates(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "ids": + return ec.fieldContext_QueryScenesUpdatesResult_ids(ctx, field) + case "updated": + return ec.fieldContext_QueryScenesUpdatesResult_updated(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type QueryScenesUpdatesResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_findScenesUpdates_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_findEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_findEdit(ctx, field) if err != nil { @@ -27142,6 +27299,94 @@ func (ec *executionContext) fieldContext_QueryScenesResultType_scenes(_ context. return fc, nil } +func (ec *executionContext) _QueryScenesUpdatesResult_ids(ctx context.Context, field graphql.CollectedField, obj *QueryScenesUpdatesResult) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QueryScenesUpdatesResult_ids(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Ids, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]uuid.UUID) + fc.Result = res + return ec.marshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QueryScenesUpdatesResult_ids(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QueryScenesUpdatesResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _QueryScenesUpdatesResult_updated(ctx context.Context, field graphql.CollectedField, obj *QueryScenesUpdatesResult) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QueryScenesUpdatesResult_updated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Updated, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*time.Time) + fc.Result = res + return ec.marshalNTime2ᚕᚖtimeᚐTimeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QueryScenesUpdatesResult_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QueryScenesUpdatesResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _QuerySitesResultType_count(ctx context.Context, field graphql.CollectedField, obj *QuerySitesResultType) (ret graphql.Marshaler) { fc, err := ec.fieldContext_QuerySitesResultType_count(ctx, field) if err != nil { @@ -46116,6 +46361,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "findScenesUpdates": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_findScenesUpdates(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findEdit": field := field @@ -47146,6 +47410,50 @@ func (ec *executionContext) _QueryScenesResultType(ctx context.Context, sel ast. return out } +var queryScenesUpdatesResultImplementors = []string{"QueryScenesUpdatesResult"} + +func (ec *executionContext) _QueryScenesUpdatesResult(ctx context.Context, sel ast.SelectionSet, obj *QueryScenesUpdatesResult) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, queryScenesUpdatesResultImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("QueryScenesUpdatesResult") + case "ids": + out.Values[i] = ec._QueryScenesUpdatesResult_ids(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updated": + out.Values[i] = ec._QueryScenesUpdatesResult_updated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var querySitesResultTypeImplementors = []string{"QuerySitesResultType"} func (ec *executionContext) _QuerySitesResultType(ctx context.Context, sel ast.SelectionSet, obj *QuerySitesResultType) graphql.Marshaler { @@ -53086,6 +53394,38 @@ func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel as return res } +func (ec *executionContext) unmarshalNTime2ᚕᚖtimeᚐTimeᚄ(ctx context.Context, v interface{}) ([]*time.Time, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]*time.Time, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNTime2ᚖtimeᚐTime(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalNTime2ᚕᚖtimeᚐTimeᚄ(ctx context.Context, sel ast.SelectionSet, v []*time.Time) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + for i := range v { + ret[i] = ec.marshalNTime2ᚖtimeᚐTime(ctx, sel, v[i]) + } + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) unmarshalNTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { res, err := graphql.UnmarshalTime(v) return &res, graphql.ErrorOnPath(ctx, err) @@ -54420,6 +54760,13 @@ func (ec *executionContext) unmarshalOPerformerScenesInput2ᚖgithubᚗcomᚋsta return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) marshalOQueryScenesUpdatesResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋpkgᚋmodelsᚐQueryScenesUpdatesResult(ctx context.Context, sel ast.SelectionSet, v *QueryScenesUpdatesResult) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._QueryScenesUpdatesResult(ctx, sel, v) +} + func (ec *executionContext) unmarshalORoleCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋpkgᚋmodelsᚐRoleCriterionInput(ctx context.Context, v interface{}) (*RoleCriterionInput, error) { if v == nil { return nil, nil diff --git a/pkg/models/generated_models.go b/pkg/models/generated_models.go index 3d87525d9..db82404a9 100644 --- a/pkg/models/generated_models.go +++ b/pkg/models/generated_models.go @@ -520,6 +520,11 @@ type QueryNotificationsInput struct { PerPage int `json:"per_page"` } +type QueryScenesUpdatesResult struct { + Ids []uuid.UUID `json:"ids"` + Updated []*time.Time `json:"updated"` +} + type QuerySitesResultType struct { Count int `json:"count"` Sites []*Site `json:"sites"` diff --git a/pkg/models/scene.go b/pkg/models/scene.go index 0e6969dc2..b269c98b1 100644 --- a/pkg/models/scene.go +++ b/pkg/models/scene.go @@ -14,6 +14,7 @@ type SceneRepo interface { DestroyFingerprints(sceneID uuid.UUID, toDelete SceneFingerprints) error Find(id uuid.UUID) (*Scene, error) FindByIds(ids []uuid.UUID) ([]*Scene, []error) + FindUpdatesByIds(inputIds []uuid.UUID) (*QueryScenesUpdatesResult, error) FindByFingerprint(algorithm FingerprintAlgorithm, hash string) ([]*Scene, error) FindByFingerprints(fingerprints []string) ([]*Scene, error) FindByFullFingerprints(fingerprints []*FingerprintQueryInput) ([]*Scene, error) diff --git a/pkg/sqlx/querybuilder_scene.go b/pkg/sqlx/querybuilder_scene.go index 187693145..59b0d1ef8 100644 --- a/pkg/sqlx/querybuilder_scene.go +++ b/pkg/sqlx/querybuilder_scene.go @@ -256,6 +256,29 @@ func (qb *sceneQueryBuilder) FindByIds(ids []uuid.UUID) ([]*models.Scene, []erro return result, nil } +func (qb *sceneQueryBuilder) FindUpdatesByIds(inputIds []uuid.UUID) (*models.QueryScenesUpdatesResult, error) { + query := ` + SELECT id, updated_at FROM scenes + WHERE id IN (?) + ` + query, args, _ := sqlx.In(query, inputIds) + queryRes, err := qb.queryScenes(query, args) + if err != nil { + return nil, err + } + + resultIds := make([]uuid.UUID, 0, len(inputIds)) + times := make([]*time.Time, 0, len(inputIds)) + for _, scene := range queryRes { + times = append(times, &scene.UpdatedAt) + resultIds = append(resultIds, scene.ID) + } + return &models.QueryScenesUpdatesResult{ + Ids: resultIds, + Updated: times, + }, nil +} + func (qb *sceneQueryBuilder) FindIdsBySceneFingerprints(fingerprints []*models.FingerprintQueryInput) (map[string][]uuid.UUID, error) { hashClause := ` SELECT scene_id, hash