Add search resolver to api
This commit is contained in:
parent
5cee5d8dea
commit
c30f5a833a
|
@ -140,6 +140,7 @@ type ComplexityRoot struct {
|
|||
MyPhotos func(childComplexity int, filter *models.Filter) int
|
||||
MyUser func(childComplexity int) int
|
||||
Photo func(childComplexity int, id int) int
|
||||
Search func(childComplexity int, query string, limitPhotos *int, limitAlbums *int) int
|
||||
ShareToken func(childComplexity int, token string, password *string) int
|
||||
SiteInfo func(childComplexity int) int
|
||||
User func(childComplexity int, filter *models.Filter) int
|
||||
|
@ -152,6 +153,12 @@ type ComplexityRoot struct {
|
|||
Success func(childComplexity int) int
|
||||
}
|
||||
|
||||
SearchResult struct {
|
||||
Albums func(childComplexity int) int
|
||||
Photos func(childComplexity int) int
|
||||
Query func(childComplexity int) int
|
||||
}
|
||||
|
||||
ShareToken struct {
|
||||
Album func(childComplexity int) int
|
||||
Expire func(childComplexity int) int
|
||||
|
@ -216,6 +223,7 @@ type QueryResolver interface {
|
|||
MyPhotos(ctx context.Context, filter *models.Filter) ([]*models.Photo, error)
|
||||
Photo(ctx context.Context, id int) (*models.Photo, error)
|
||||
ShareToken(ctx context.Context, token string, password *string) (*models.ShareToken, error)
|
||||
Search(ctx context.Context, query string, limitPhotos *int, limitAlbums *int) (*models.SearchResult, error)
|
||||
}
|
||||
type ShareTokenResolver interface {
|
||||
Owner(ctx context.Context, obj *models.ShareToken) (*models.User, error)
|
||||
|
@ -770,6 +778,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Query.Photo(childComplexity, args["id"].(int)), true
|
||||
|
||||
case "Query.search":
|
||||
if e.complexity.Query.Search == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Query_search_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.Search(childComplexity, args["query"].(string), args["limitPhotos"].(*int), args["limitAlbums"].(*int)), true
|
||||
|
||||
case "Query.shareToken":
|
||||
if e.complexity.Query.ShareToken == nil {
|
||||
break
|
||||
|
@ -829,6 +849,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.ScannerResult.Success(childComplexity), true
|
||||
|
||||
case "SearchResult.albums":
|
||||
if e.complexity.SearchResult.Albums == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.SearchResult.Albums(childComplexity), true
|
||||
|
||||
case "SearchResult.photos":
|
||||
if e.complexity.SearchResult.Photos == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.SearchResult.Photos(childComplexity), true
|
||||
|
||||
case "SearchResult.query":
|
||||
if e.complexity.SearchResult.Query == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.SearchResult.Query(childComplexity), true
|
||||
|
||||
case "ShareToken.album":
|
||||
if e.complexity.ShareToken.Album == nil {
|
||||
break
|
||||
|
@ -1045,6 +1086,8 @@ type Query {
|
|||
photo(id: Int!): Photo!
|
||||
|
||||
shareToken(token: String!, password: String): ShareToken!
|
||||
|
||||
search(query: String!, limitPhotos: Int, limitAlbums: Int): SearchResult!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
|
@ -1234,6 +1277,12 @@ type PhotoEXIF {
|
|||
"An index describing the mode for adjusting the exposure of the image"
|
||||
exposureProgram: Int
|
||||
}
|
||||
|
||||
type SearchResult {
|
||||
query: String!
|
||||
albums: [Album!]!
|
||||
photos: [Photo!]!
|
||||
}
|
||||
`},
|
||||
)
|
||||
|
||||
|
@ -1623,6 +1672,36 @@ func (ec *executionContext) field_Query_photo_args(ctx context.Context, rawArgs
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_search_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["query"]; ok {
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["query"] = arg0
|
||||
var arg1 *int
|
||||
if tmp, ok := rawArgs["limitPhotos"]; ok {
|
||||
arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["limitPhotos"] = arg1
|
||||
var arg2 *int
|
||||
if tmp, ok := rawArgs["limitAlbums"]; ok {
|
||||
arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["limitAlbums"] = arg2
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_shareToken_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
|
@ -4325,6 +4404,50 @@ func (ec *executionContext) _Query_shareToken(ctx context.Context, field graphql
|
|||
return ec.marshalNShareToken2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_search(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "Query",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Query_search_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().Search(rctx, args["query"].(string), args["limitPhotos"].(*int), args["limitAlbums"].(*int))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !ec.HasError(rctx) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*models.SearchResult)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalNSearchResult2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSearchResult(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
|
@ -4542,6 +4665,117 @@ func (ec *executionContext) _ScannerResult_message(ctx context.Context, field gr
|
|||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _SearchResult_query(ctx context.Context, field graphql.CollectedField, obj *models.SearchResult) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "SearchResult",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Query, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !ec.HasError(rctx) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _SearchResult_albums(ctx context.Context, field graphql.CollectedField, obj *models.SearchResult) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "SearchResult",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Albums, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !ec.HasError(rctx) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*models.Album)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalNAlbum2ᚕᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbumᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _SearchResult_photos(ctx context.Context, field graphql.CollectedField, obj *models.SearchResult) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "SearchResult",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Photos, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !ec.HasError(rctx) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*models.Photo)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalNPhoto2ᚕᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ShareToken_id(ctx context.Context, field graphql.CollectedField, obj *models.ShareToken) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
|
@ -6836,6 +7070,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
|||
}
|
||||
return res
|
||||
})
|
||||
case "search":
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._Query_search(ctx, field)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
}
|
||||
return res
|
||||
})
|
||||
case "__type":
|
||||
out.Values[i] = ec._Query___type(ctx, field)
|
||||
case "__schema":
|
||||
|
@ -6887,6 +7135,43 @@ func (ec *executionContext) _ScannerResult(ctx context.Context, sel ast.Selectio
|
|||
return out
|
||||
}
|
||||
|
||||
var searchResultImplementors = []string{"SearchResult"}
|
||||
|
||||
func (ec *executionContext) _SearchResult(ctx context.Context, sel ast.SelectionSet, obj *models.SearchResult) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.RequestContext, sel, searchResultImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
var invalids uint32
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("SearchResult")
|
||||
case "query":
|
||||
out.Values[i] = ec._SearchResult_query(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "albums":
|
||||
out.Values[i] = ec._SearchResult_albums(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "photos":
|
||||
out.Values[i] = ec._SearchResult_photos(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch()
|
||||
if invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var shareTokenImplementors = []string{"ShareToken"}
|
||||
|
||||
func (ec *executionContext) _ShareToken(ctx context.Context, sel ast.SelectionSet, obj *models.ShareToken) graphql.Marshaler {
|
||||
|
@ -7537,6 +7822,20 @@ func (ec *executionContext) marshalNScannerResult2ᚖgithubᚗcomᚋviktorstrate
|
|||
return ec._ScannerResult(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNSearchResult2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSearchResult(ctx context.Context, sel ast.SelectionSet, v models.SearchResult) graphql.Marshaler {
|
||||
return ec._SearchResult(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNSearchResult2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSearchResult(ctx context.Context, sel ast.SelectionSet, v *models.SearchResult) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !ec.HasError(graphql.GetResolverContext(ctx)) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._SearchResult(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNShareToken2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v models.ShareToken) graphql.Marshaler {
|
||||
return ec._ShareToken(ctx, sel, &v)
|
||||
}
|
||||
|
|
|
@ -47,6 +47,12 @@ type ScannerResult struct {
|
|||
Message *string `json:"message"`
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
Query string `json:"query"`
|
||||
Albums []*Album `json:"albums"`
|
||||
Photos []*Photo `json:"photos"`
|
||||
}
|
||||
|
||||
// General public information about the site
|
||||
type SiteInfo struct {
|
||||
InitialSetup bool `json:"initialSetup"`
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/viktorstrate/photoview/api/graphql/auth"
|
||||
"github.com/viktorstrate/photoview/api/graphql/models"
|
||||
)
|
||||
|
||||
func (r *Resolver) Search(ctx context.Context, query string, _limitPhotos *int, _limitAlbums *int) (*models.SearchResult, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
|
||||
limitPhotos := 10
|
||||
limitAlbums := 10
|
||||
|
||||
if _limitPhotos != nil {
|
||||
limitPhotos = *_limitPhotos
|
||||
}
|
||||
|
||||
if _limitAlbums != nil {
|
||||
limitAlbums = *_limitAlbums
|
||||
}
|
||||
|
||||
wildQuery := "%" + query + "%"
|
||||
|
||||
photoRows, err := r.Database.Query(`
|
||||
SELECT photo.* FROM photo JOIN album ON photo.album_id = album.album_id
|
||||
WHERE album.owner_id = ? AND photo.title LIKE ? OR photo.path LIKE ?
|
||||
ORDER BY (
|
||||
case when photo.title LIKE ? then 2
|
||||
when photo.path LIKE ? then 1
|
||||
end ) DESC
|
||||
LIMIT ?
|
||||
`, user.UserID, wildQuery, wildQuery, wildQuery, wildQuery, limitPhotos)
|
||||
if err != nil {
|
||||
log.Printf("ERROR: searching photos %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
photos, err := models.NewPhotosFromRows(photoRows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
albumRows, err := r.Database.Query(`
|
||||
SELECT * FROM album
|
||||
WHERE owner_id = ? AND title LIKE ? OR path LIKE ?
|
||||
ORDER BY (
|
||||
case when title LIKE ? then 2
|
||||
when path LIKE ? then 1
|
||||
end ) DESC
|
||||
LIMIT ?
|
||||
`, user.UserID, wildQuery, wildQuery, wildQuery, wildQuery, limitAlbums)
|
||||
if err != nil {
|
||||
log.Printf("ERROR: searching albums %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
albums, err := models.NewAlbumsFromRows(albumRows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := models.SearchResult{
|
||||
Query: query,
|
||||
Photos: photos,
|
||||
Albums: albums,
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
|
@ -39,6 +39,8 @@ type Query {
|
|||
photo(id: Int!): Photo!
|
||||
|
||||
shareToken(token: String!, password: String): ShareToken!
|
||||
|
||||
search(query: String!, limitPhotos: Int, limitAlbums: Int): SearchResult!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
|
@ -228,3 +230,9 @@ type PhotoEXIF {
|
|||
"An index describing the mode for adjusting the exposure of the image"
|
||||
exposureProgram: Int
|
||||
}
|
||||
|
||||
type SearchResult {
|
||||
query: String!
|
||||
albums: [Album!]!
|
||||
photos: [Photo!]!
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue