1
Fork 0

Work on photo resolver

This commit is contained in:
viktorstrate 2020-02-05 14:51:46 +01:00
parent e877242fef
commit 43e214b5d0
10 changed files with 247 additions and 115 deletions

View File

@ -14,7 +14,7 @@ model:
package: models
resolver:
filename: graphql/resolver.go
filename: graphql/resolvers/root.go
type: Resolver
autobind: []
@ -22,3 +22,7 @@ autobind: []
models:
User:
model: github.com/viktorstrate/photoview/api/graphql/models.User
Photo:
model: github.com/viktorstrate/photoview/api/graphql/models.Photo
PhotoURL:
model: github.com/viktorstrate/photoview/api/graphql/models.PhotoURL

View File

@ -38,6 +38,7 @@ type Config struct {
type ResolverRoot interface {
Mutation() MutationResolver
Photo() PhotoResolver
Query() QueryResolver
}
@ -129,6 +130,12 @@ type MutationResolver interface {
ScanAll(ctx context.Context) (*models.ScannerResult, error)
ScanUser(ctx context.Context, userID string) (*models.ScannerResult, error)
}
type PhotoResolver interface {
Original(ctx context.Context, obj *models.Photo) (*models.PhotoURL, error)
Thumbnail(ctx context.Context, obj *models.Photo) (*models.PhotoURL, error)
Album(ctx context.Context, obj *models.Photo) (*models.Album, error)
Exif(ctx context.Context, obj *models.Photo) (*models.PhotoExif, error)
}
type QueryResolver interface {
Users(ctx context.Context) ([]*models.User, error)
MyUser(ctx context.Context) (*models.User, error)
@ -1388,13 +1395,13 @@ func (ec *executionContext) _Photo_id(ctx context.Context, field graphql.Collect
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.ID, nil
return obj.ID(), nil
})
if err != nil {
ec.Error(ctx, err)
@ -1440,10 +1447,10 @@ func (ec *executionContext) _Photo_title(ctx context.Context, field graphql.Coll
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2string(ctx, field.Selections, res)
return ec.marshalOString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _Photo_path(ctx context.Context, field graphql.CollectedField, obj *models.Photo) (ret graphql.Marshaler) {
@ -1474,10 +1481,10 @@ func (ec *executionContext) _Photo_path(ctx context.Context, field graphql.Colle
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2string(ctx, field.Selections, res)
return ec.marshalOString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _Photo_original(ctx context.Context, field graphql.CollectedField, obj *models.Photo) (ret graphql.Marshaler) {
@ -1493,13 +1500,13 @@ func (ec *executionContext) _Photo_original(ctx context.Context, field graphql.C
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.Original, nil
return ec.resolvers.Photo().Original(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@ -1527,13 +1534,13 @@ func (ec *executionContext) _Photo_thumbnail(ctx context.Context, field graphql.
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.Thumbnail, nil
return ec.resolvers.Photo().Thumbnail(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@ -1561,13 +1568,13 @@ func (ec *executionContext) _Photo_album(ctx context.Context, field graphql.Coll
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.Album, nil
return ec.resolvers.Photo().Album(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@ -1598,13 +1605,13 @@ func (ec *executionContext) _Photo_exif(ctx context.Context, field graphql.Colle
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.Exif, nil
return ec.resolvers.Photo().Exif(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@ -2006,13 +2013,13 @@ func (ec *executionContext) _PhotoURL_url(ctx context.Context, field graphql.Col
Object: "PhotoURL",
Field: field,
Args: nil,
IsMethod: false,
IsMethod: true,
}
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.URL, nil
return obj.URL(), nil
})
if err != nil {
ec.Error(ctx, err)
@ -2021,10 +2028,10 @@ func (ec *executionContext) _PhotoURL_url(ctx context.Context, field graphql.Col
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2string(ctx, field.Selections, res)
return ec.marshalOString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoURL_width(ctx context.Context, field graphql.CollectedField, obj *models.PhotoURL) (ret graphql.Marshaler) {
@ -2055,10 +2062,10 @@ func (ec *executionContext) _PhotoURL_width(ctx context.Context, field graphql.C
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*int)
res := resTmp.(int)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOInt2int(ctx, field.Selections, res)
return ec.marshalOInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoURL_height(ctx context.Context, field graphql.CollectedField, obj *models.PhotoURL) (ret graphql.Marshaler) {
@ -2089,10 +2096,10 @@ func (ec *executionContext) _PhotoURL_height(ctx context.Context, field graphql.
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*int)
res := resTmp.(int)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOInt2int(ctx, field.Selections, res)
return ec.marshalOInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) _Query_users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@ -4016,23 +4023,59 @@ func (ec *executionContext) _Photo(ctx context.Context, sel ast.SelectionSet, ob
case "id":
out.Values[i] = ec._Photo_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
atomic.AddUint32(&invalids, 1)
}
case "title":
out.Values[i] = ec._Photo_title(ctx, field, obj)
case "path":
out.Values[i] = ec._Photo_path(ctx, field, obj)
case "original":
out.Values[i] = ec._Photo_original(ctx, field, obj)
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._Photo_original(ctx, field, obj)
return res
})
case "thumbnail":
out.Values[i] = ec._Photo_thumbnail(ctx, field, obj)
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._Photo_thumbnail(ctx, field, obj)
return res
})
case "album":
out.Values[i] = ec._Photo_album(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
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._Photo_album(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
return res
})
case "exif":
out.Values[i] = ec._Photo_exif(ctx, field, obj)
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._Photo_exif(ctx, field, obj)
return res
})
default:
panic("unknown field " + strconv.Quote(field.Name))
}

View File

@ -22,20 +22,6 @@ type AuthorizeResult struct {
Token *string `json:"token"`
}
type Photo struct {
ID string `json:"id"`
Title *string `json:"title"`
// Local filepath for the photo
Path *string `json:"path"`
// URL to display the photo in full resolution
Original *PhotoURL `json:"original"`
// URL to display the photo in a smaller resolution
Thumbnail *PhotoURL `json:"thumbnail"`
// The album that holds the photo
Album *Album `json:"album"`
Exif *PhotoExif `json:"exif"`
}
// EXIF metadata from the camera
type PhotoExif struct {
Photo *Photo `json:"photo"`
@ -60,15 +46,6 @@ type PhotoExif struct {
Flash *string `json:"flash"`
}
type PhotoURL struct {
// URL for previewing the image
URL *string `json:"url"`
// Width of the image in pixels
Width *int `json:"width"`
// Height of the image in pixels
Height *int `json:"height"`
}
type ScannerResult struct {
Finished bool `json:"finished"`
Success bool `json:"success"`

View File

@ -0,0 +1,41 @@
package models
import (
"database/sql"
"strconv"
)
type Photo struct {
PhotoID int
Title string
Path string
OriginalUrl int
ThumbnailUrl int
AlbumId int
ExifId *int
}
type PhotoURL struct {
UrlId int
Token string
Width int
Height int
}
func (p *Photo) ID() string {
return strconv.Itoa(p.PhotoID)
}
func NewPhotoFromRow(row *sql.Row) (*Photo, error) {
photo := Photo{}
if err := row.Scan(&photo.PhotoID, &photo.Title, &photo.Path, &photo.OriginalUrl, &photo.ThumbnailUrl, &photo.AlbumId, &photo.ExifId); err != nil {
return nil, err
}
return &photo, nil
}
func (p *PhotoURL) URL() string {
return "URL:" + p.Token
}

View File

@ -1,55 +0,0 @@
package api
import (
"context"
"database/sql"
"github.com/viktorstrate/photoview/api/graphql/models"
)
//go:generate go run github.com/99designs/gqlgen
type Resolver struct {
Database *sql.DB
}
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
}
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
func (r *queryResolver) Users(ctx context.Context) ([]*models.User, error) {
rows, err := r.Database.Query("SELECT * FROM users")
if err != nil {
return nil, err
}
defer rows.Close()
users, err := models.NewUsersFromRows(rows)
if err != nil {
return nil, err
}
return users, nil
}
func (r *queryResolver) MyAlbums(ctx context.Context) ([]*models.Album, error) {
panic("Not implemented")
}
func (r *queryResolver) Album(ctx context.Context, id *string) (*models.Album, error) {
panic("Not implemented")
}
func (r *queryResolver) MyPhotos(ctx context.Context) ([]*models.Photo, error) {
panic("Not implemented")
}
func (r *queryResolver) Photo(ctx context.Context, id string) (*models.Photo, error) {
panic("Not implemented")
}

View File

@ -0,0 +1,71 @@
package resolvers
import (
"context"
api "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/auth"
"github.com/viktorstrate/photoview/api/graphql/models"
)
func (r *queryResolver) MyPhotos(ctx context.Context) ([]*models.Photo, error) {
panic("Not implemented")
}
func (r *queryResolver) Photo(ctx context.Context, id string) (*models.Photo, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, auth.ErrUnauthorized
}
row := r.Database.QueryRow(`
SELECT photo.* FROM photo
LEFT JOIN album ON photo.album_id = album.album_id
WHERE photo.photo_id = ? AND album.owner_id = ?
`, id, user.UserID)
photo, err := models.NewPhotoFromRow(row)
if err != nil {
return nil, err
}
return photo, nil
}
type photoResolver struct {
*Resolver
}
func (r *Resolver) Photo() api.PhotoResolver {
return &photoResolver{r}
}
func (r *photoResolver) Original(ctx context.Context, obj *models.Photo) (*models.PhotoURL, error) {
row := r.Database.QueryRow("SELECT photo_url.* FROM photo, photo_url WHERE photo.photo_id = ? AND photo.original_url = photo_url.url_id", obj.PhotoID)
var photoUrl models.PhotoURL
if err := row.Scan(&photoUrl.UrlId, &photoUrl.Token, &photoUrl.Width, &photoUrl.Height); err != nil {
return nil, err
}
return &photoUrl, nil
}
func (r *photoResolver) Thumbnail(ctx context.Context, obj *models.Photo) (*models.PhotoURL, error) {
row := r.Database.QueryRow("SELECT photo_url.* FROM photo, photo_url WHERE photo.photo_id = ? AND photo.thumbnail_url = photo_url.url_id", obj.PhotoID)
var photoUrl models.PhotoURL
if err := row.Scan(&photoUrl.UrlId, &photoUrl.Token, &photoUrl.Width, &photoUrl.Height); err != nil {
return nil, err
}
return &photoUrl, nil
}
func (r *photoResolver) Album(ctx context.Context, obj *models.Photo) (*models.Album, error) {
panic("not implemented")
}
func (r *photoResolver) Exif(ctx context.Context, obj *models.Photo) (*models.PhotoExif, error) {
panic("not implemented")
}

View File

@ -0,0 +1,34 @@
package resolvers
import (
"context"
"database/sql"
api "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/models"
)
//go:generate go run github.com/99designs/gqlgen
type Resolver struct {
Database *sql.DB
}
func (r *Resolver) Mutation() api.MutationResolver {
return &mutationResolver{r}
}
func (r *Resolver) Query() api.QueryResolver {
return &queryResolver{r}
}
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
func (r *queryResolver) MyAlbums(ctx context.Context) ([]*models.Album, error) {
panic("Not implemented")
}
func (r *queryResolver) Album(ctx context.Context, id *string) (*models.Album, error) {
panic("Not implemented")
}

View File

@ -1,4 +1,4 @@
package api
package resolvers
import (
"context"

View File

@ -1,4 +1,4 @@
package api
package resolvers
import (
"context"
@ -13,6 +13,22 @@ import (
// type userResolver struct{ *Resolver }
func (r *queryResolver) Users(ctx context.Context) ([]*models.User, error) {
rows, err := r.Database.Query("SELECT * FROM users")
if err != nil {
return nil, err
}
defer rows.Close()
users, err := models.NewUsersFromRows(rows)
if err != nil {
return nil, err
}
return users, nil
}
func (r *queryResolver) MyUser(ctx context.Context) (*models.User, error) {
user := auth.UserFromContext(ctx)

View File

@ -6,14 +6,15 @@ import (
"os"
"github.com/go-chi/chi"
"github.com/joho/godotenv"
"github.com/go-chi/cors"
"github.com/joho/godotenv"
"github.com/viktorstrate/photoview/api/database"
"github.com/viktorstrate/photoview/api/graphql/auth"
"github.com/99designs/gqlgen/handler"
photoview_graphql "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/resolvers"
)
const defaultPort = "4001"
@ -45,10 +46,10 @@ func main() {
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"},
AllowCredentials: true,
Debug: true,
Debug: false,
}).Handler)
graphqlResolver := photoview_graphql.Resolver{Database: db}
graphqlResolver := resolvers.Resolver{Database: db}
graphqlDirective := photoview_graphql.DirectiveRoot{}
graphqlDirective.IsAdmin = photoview_graphql.IsAdmin(db)
@ -60,6 +61,6 @@ func main() {
router.Handle("/", handler.Playground("GraphQL playground", "/graphql"))
router.Handle("/graphql", handler.GraphQL(photoview_graphql.NewExecutableSchema(graphqlConfig)))
log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
log.Printf("🚀 Graphql playground ready at http://localhost:%s/", port)
log.Fatal(http.ListenAndServe(":"+port, router))
}