GraphQL Framework

This commit is contained in:
2021-02-02 15:34:10 -05:00
parent ecf981495e
commit 7e6454c593
28 changed files with 10764 additions and 616 deletions

9341
graph/generated/generated.go Normal file

File diff suppressed because it is too large Load Diff

397
graph/model/models_gen.go Normal file
View File

@@ -0,0 +1,397 @@
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package model
import (
"fmt"
"io"
"strconv"
"time"
"github.com/99designs/gqlgen/graphql"
)
type Album struct {
ID *string `json:"id" gorm:"primarykey;not null"`
CreatedAt *time.Time `json:"createdAt" `
UpdatedAt *time.Time `json:"updatedAt" `
Name string `json:"name" gorm:"unique;not null"`
}
type AlbumFilter struct {
ID *IDFilter `json:"id" `
CreatedAt *TimeFilter `json:"createdAt" `
UpdatedAt *TimeFilter `json:"updatedAt" `
Name *StringFilter `json:"name" `
And *MediaItemFilter `json:"and" `
Or *MediaItemFilter `json:"or" `
}
type AlbumResponse struct {
Data []*Album `json:"data" `
PageInfo *PageInfo `json:"pageInfo" `
}
type AuthTypeFilter struct {
EqualTo *AuthType `json:"equalTo" `
NotEqualTo *AuthType `json:"notEqualTo" `
In []AuthType `json:"in" `
NotIn []AuthType `json:"notIn" `
}
type BooleanFilter struct {
EqualTo *bool `json:"equalTo" `
NotEqualTo *bool `json:"notEqualTo" `
}
type Device struct {
ID *string `json:"id" gorm:"primarykey;not null"`
CreatedAt *time.Time `json:"createdAt" `
UpdatedAt *time.Time `json:"updatedAt" `
Name string `json:"name" gorm:"not null"`
Type DeviceType `json:"type" gorm:"default:Unknown;not null"`
User *User `json:"user" gorm:"ForeignKey:ID;not null"`
RefreshKey *string `json:"refreshKey" `
}
type DeviceFilter struct {
ID *IDFilter `json:"id" `
CreatedAt *TimeFilter `json:"createdAt" `
UpdatedAt *TimeFilter `json:"updatedAt" `
Name *StringFilter `json:"name" `
Type *DeviceTypeFilter `json:"type" `
And *MediaItemFilter `json:"and" `
Or *MediaItemFilter `json:"or" `
}
type DeviceResponse struct {
Data []*Device `json:"data" `
PageInfo *PageInfo `json:"pageInfo" `
}
type DeviceTypeFilter struct {
EqualTo *DeviceType `json:"equalTo" `
NotEqualTo *DeviceType `json:"notEqualTo" `
In []DeviceType `json:"in" `
NotIn []DeviceType `json:"notIn" `
}
type FloatFilter struct {
EqualTo *float64 `json:"equalTo" `
NotEqualTo *float64 `json:"notEqualTo" `
LessThan *float64 `json:"lessThan" `
LessThanOrEqualTo *float64 `json:"lessThanOrEqualTo" `
MoreThan *float64 `json:"moreThan" `
MoreThanOrEqualTo *float64 `json:"moreThanOrEqualTo" `
In []float64 `json:"in" `
NotIn []float64 `json:"notIn" `
}
type IDFilter struct {
EqualTo *string `json:"equalTo" `
NotEqualTo *string `json:"notEqualTo" `
In []string `json:"in" `
NotIn []string `json:"notIn" `
}
type IntFilter struct {
EqualTo *int `json:"equalTo" `
NotEqualTo *int `json:"notEqualTo" `
LessThan *int `json:"lessThan" `
LessThanOrEqualTo *int `json:"lessThanOrEqualTo" `
MoreThan *int `json:"moreThan" `
MoreThanOrEqualTo *int `json:"moreThanOrEqualTo" `
In []int `json:"in" `
NotIn []int `json:"notIn" `
}
type MediaItem struct {
ID *string `json:"id" gorm:"primarykey;not null"`
CreatedAt *time.Time `json:"createdAt" `
UpdatedAt *time.Time `json:"updatedAt" `
ExifDate *time.Time `json:"exifDate" `
Latitude *float64 `json:"latitude" `
Longitude *float64 `json:"longitude" `
IsVideo bool `json:"isVideo" gorm:"default:false;not null"`
FileName string `json:"fileName" gorm:"not null"`
OrigName string `json:"origName" gorm:"not null"`
Tags []*Tag `json:"tags" gorm:"many2many:media_tags"`
Albums []*Album `json:"albums" gorm:"many2many:media_albums"`
User *User `json:"user" gorm:"ForeignKey:ID;not null"`
}
type MediaItemFilter struct {
ID *IDFilter `json:"id" `
CreatedAt *TimeFilter `json:"createdAt" `
UpdatedAt *TimeFilter `json:"updatedAt" `
ExifDate *TimeFilter `json:"exifDate" `
Latitude *FloatFilter `json:"latitude" `
Longitude *FloatFilter `json:"longitude" `
IsVideo *BooleanFilter `json:"isVideo" `
OrigName *StringFilter `json:"origName" `
Tags *TagFilter `json:"tags" `
Albums *AlbumFilter `json:"albums" `
And *MediaItemFilter `json:"and" `
Or *MediaItemFilter `json:"or" `
}
type MediaItemResponse struct {
Data []*MediaItem `json:"data" `
PageInfo *PageInfo `json:"pageInfo" `
}
type NewAlbum struct {
Name string `json:"name" `
}
type NewDevice struct {
Name string `json:"name" `
}
type NewMediaItem struct {
File graphql.Upload `json:"file" `
Tags []string `json:"tags" `
Albums []string `json:"albums" `
}
type NewTag struct {
Name string `json:"name" `
}
type NewUser struct {
Email string `json:"email" `
Username string `json:"username" `
FirstName *string `json:"firstName" `
LastName *string `json:"lastName" `
Role Role `json:"role" `
AuthType AuthType `json:"authType" `
Password *string `json:"password" `
}
type PageInfo struct {
Count int `json:"count" `
Page int `json:"page" `
Total int `json:"total" `
}
type RoleFilter struct {
EqualTo *Role `json:"equalTo" `
NotEqualTo *Role `json:"notEqualTo" `
In []Role `json:"in" `
NotIn []Role `json:"notIn" `
}
type StringFilter struct {
EqualTo *string `json:"equalTo" `
NotEqualTo *string `json:"notEqualTo" `
StartWith *string `json:"startWith" `
NotStartWith *string `json:"notStartWith" `
EndWith *string `json:"endWith" `
NotEndWith *string `json:"notEndWith" `
Contain *string `json:"contain" `
NotContain *string `json:"notContain" `
In []string `json:"in" `
NotIn []string `json:"notIn" `
StartWithStrict *string `json:"startWithStrict" `
NotStartWithStrict *string `json:"notStartWithStrict" `
EndWithStrict *string `json:"endWithStrict" `
NotEndWithStrict *string `json:"notEndWithStrict" `
ContainStrict *string `json:"containStrict" `
NotContainStrict *string `json:"notContainStrict" `
}
type Tag struct {
ID *string `json:"id" gorm:"primarykey;not null"`
CreatedAt *time.Time `json:"createdAt" `
UpdatedAt *time.Time `json:"updatedAt" `
Name string `json:"name" gorm:"unique;not null"`
}
type TagFilter struct {
ID *IDFilter `json:"id" `
CreatedAt *TimeFilter `json:"createdAt" `
UpdatedAt *TimeFilter `json:"updatedAt" `
Name *StringFilter `json:"name" `
And *MediaItemFilter `json:"and" `
Or *MediaItemFilter `json:"or" `
}
type TagResponse struct {
Data []*Tag `json:"data" `
PageInfo *PageInfo `json:"pageInfo" `
}
type TimeFilter struct {
EqualTo *time.Time `json:"equalTo" `
NotEqualTo *time.Time `json:"notEqualTo" `
LessThan *time.Time `json:"lessThan" `
LessThanOrEqualTo *time.Time `json:"lessThanOrEqualTo" `
MoreThan *time.Time `json:"moreThan" `
MoreThanOrEqualTo *time.Time `json:"moreThanOrEqualTo" `
}
type User struct {
ID *string `json:"id" gorm:"primarykey;not null"`
CreatedAt *time.Time `json:"createdAt" `
UpdatedAt *time.Time `json:"updatedAt" `
Email string `json:"email" gorm:"not null;unique"`
Username string `json:"username" gorm:"not null;unique"`
FirstName *string `json:"firstName" `
LastName *string `json:"lastName" `
Role Role `json:"role" gorm:"default:User;not null"`
AuthType AuthType `json:"authType" gorm:"default:Local;not null"`
Password *string `json:"password" `
}
type UserFilter struct {
ID *IDFilter `json:"id" `
CreatedAt *TimeFilter `json:"createdAt" `
UpdatedAt *TimeFilter `json:"updatedAt" `
Username *StringFilter `json:"username" `
FirstName *StringFilter `json:"firstName" `
LastName *StringFilter `json:"lastName" `
Role *RoleFilter `json:"role" `
AuthType *AuthTypeFilter `json:"authType" `
And *UserFilter `json:"and" `
Or *UserFilter `json:"or" `
}
type UserResponse struct {
Data []*User `json:"data" `
PageInfo *PageInfo `json:"pageInfo" `
}
type AuthType string
const (
AuthTypeLocal AuthType = "Local"
AuthTypeLdap AuthType = "LDAP"
)
var AllAuthType = []AuthType{
AuthTypeLocal,
AuthTypeLdap,
}
func (e AuthType) IsValid() bool {
switch e {
case AuthTypeLocal, AuthTypeLdap:
return true
}
return false
}
func (e AuthType) String() string {
return string(e)
}
func (e *AuthType) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = AuthType(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid AuthType", str)
}
return nil
}
func (e AuthType) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type DeviceType string
const (
DeviceTypeIOs DeviceType = "iOS"
DeviceTypeAndroid DeviceType = "Android"
DeviceTypeChrome DeviceType = "Chrome"
DeviceTypeFirefox DeviceType = "Firefox"
DeviceTypeInternetExplorer DeviceType = "InternetExplorer"
DeviceTypeEdge DeviceType = "Edge"
DeviceTypeSafari DeviceType = "Safari"
DeviceTypeUnknown DeviceType = "Unknown"
)
var AllDeviceType = []DeviceType{
DeviceTypeIOs,
DeviceTypeAndroid,
DeviceTypeChrome,
DeviceTypeFirefox,
DeviceTypeInternetExplorer,
DeviceTypeEdge,
DeviceTypeSafari,
DeviceTypeUnknown,
}
func (e DeviceType) IsValid() bool {
switch e {
case DeviceTypeIOs, DeviceTypeAndroid, DeviceTypeChrome, DeviceTypeFirefox, DeviceTypeInternetExplorer, DeviceTypeEdge, DeviceTypeSafari, DeviceTypeUnknown:
return true
}
return false
}
func (e DeviceType) String() string {
return string(e)
}
func (e *DeviceType) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = DeviceType(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid DeviceType", str)
}
return nil
}
func (e DeviceType) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type Role string
const (
RoleAdmin Role = "Admin"
RoleUser Role = "User"
)
var AllRole = []Role{
RoleAdmin,
RoleUser,
}
func (e Role) IsValid() bool {
switch e {
case RoleAdmin, RoleUser:
return true
}
return false
}
func (e Role) String() string {
return string(e)
}
func (e *Role) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = Role(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid Role", str)
}
return nil
}
func (e Role) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}

13
graph/resolver.go Normal file
View File

@@ -0,0 +1,13 @@
package graph
import (
"reichard.io/imagini/internal/db"
)
// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.
type Resolver struct{
DB *db.DBManager
}

356
graph/schema.graphqls Normal file
View File

@@ -0,0 +1,356 @@
# https://gqlgen.com/reference/scalars/
scalar Time
scalar Upload
# https://gqlgen.com/reference/directives/
directive @hasRole(role: Role!) on FIELD_DEFINITION
directive @meta(
gorm: String,
) on OBJECT | FIELD_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION | ENUM | INPUT_OBJECT | ARGUMENT_DEFINITION
enum Role {
Admin
User
}
enum DeviceType {
iOS
Android
Chrome
Firefox
InternetExplorer
Edge
Safari
Unknown
}
enum AuthType {
Local
LDAP
}
# ------------------------------------------------------------
# ----------------------- Type Filters -----------------------
# ------------------------------------------------------------
input TimeFilter {
equalTo: Time
notEqualTo: Time
lessThan: Time
lessThanOrEqualTo: Time
moreThan: Time
moreThanOrEqualTo: Time
}
input IntFilter {
equalTo: Int
notEqualTo: Int
lessThan: Int
lessThanOrEqualTo: Int
moreThan: Int
moreThanOrEqualTo: Int
in: [Int!]
notIn: [Int!]
}
input FloatFilter {
equalTo: Float
notEqualTo: Float
lessThan: Float
lessThanOrEqualTo: Float
moreThan: Float
moreThanOrEqualTo: Float
in: [Float!]
notIn: [Float!]
}
input BooleanFilter {
equalTo: Boolean
notEqualTo: Boolean
}
input IDFilter {
equalTo: ID
notEqualTo: ID
in: [ID!]
notIn: [ID!]
}
input StringFilter {
equalTo: String
notEqualTo: String
startWith: String
notStartWith: String
endWith: String
notEndWith: String
contain: String
notContain: String
in: [String!]
notIn: [String!]
startWithStrict: String
notStartWithStrict: String
endWithStrict: String
notEndWithStrict: String
containStrict: String
notContainStrict: String
}
input RoleFilter {
equalTo: Role
notEqualTo: Role
in: [Role!]
notIn: [Role!]
}
input DeviceTypeFilter {
equalTo: DeviceType
notEqualTo: DeviceType
in: [DeviceType!]
notIn: [DeviceType!]
}
input AuthTypeFilter {
equalTo: AuthType
notEqualTo: AuthType
in: [AuthType!]
notIn: [AuthType!]
}
# ------------------------------------------------------------
# -------------------- Object Definitions --------------------
# ------------------------------------------------------------
type Device {
id: ID @meta(gorm: "primarykey;not null")
createdAt: Time
updatedAt: Time
name: String! @meta(gorm: "not null")
type: DeviceType! @meta(gorm: "default:Unknown;not null")
user: User @meta(gorm: "ForeignKey:ID;not null")
refreshKey: String
}
type User {
id: ID @meta(gorm: "primarykey;not null")
createdAt: Time
updatedAt: Time
email: String! @meta(gorm: "not null;unique")
username: String! @meta(gorm: "not null;unique")
firstName: String
lastName: String
role: Role! @meta(gorm: "default:User;not null")
authType: AuthType! @meta(gorm: "default:Local;not null")
password: String
}
type MediaItem {
id: ID @meta(gorm: "primarykey;not null")
createdAt: Time
updatedAt: Time
exifDate: Time
latitude: Float
longitude: Float
isVideo: Boolean! @meta(gorm: "default:false;not null")
fileName: String! @meta(gorm: "not null")
origName: String! @meta(gorm: "not null")
tags: [Tag] @meta(gorm: "many2many:media_tags")
albums: [Album] @meta(gorm: "many2many:media_albums")
user: User @meta(gorm: "ForeignKey:ID;not null")
}
type Tag {
id: ID @meta(gorm: "primarykey;not null")
createdAt: Time
updatedAt: Time
name: String! @meta(gorm: "unique;not null")
}
type Album {
id: ID @meta(gorm: "primarykey;not null")
createdAt: Time
updatedAt: Time
name: String! @meta(gorm: "unique;not null")
}
# ------------------------------------------------------------
# ---------------------- Object Filters ----------------------
# ------------------------------------------------------------
input UserFilter {
id: IDFilter
createdAt: TimeFilter
updatedAt: TimeFilter
username: StringFilter
firstName: StringFilter
lastName: StringFilter
role: RoleFilter
authType: AuthTypeFilter
and: UserFilter
or: UserFilter
}
input MediaItemFilter {
id: IDFilter
createdAt: TimeFilter
updatedAt: TimeFilter
exifDate: TimeFilter
latitude: FloatFilter
longitude: FloatFilter
isVideo: BooleanFilter
origName: StringFilter
tags: TagFilter
albums: AlbumFilter
and: MediaItemFilter
or: MediaItemFilter
}
input DeviceFilter {
id: IDFilter
createdAt: TimeFilter
updatedAt: TimeFilter
name: StringFilter
type: DeviceTypeFilter
and: MediaItemFilter
or: MediaItemFilter
}
input TagFilter {
id: IDFilter
createdAt: TimeFilter
updatedAt: TimeFilter
name: StringFilter
and: MediaItemFilter
or: MediaItemFilter
}
input AlbumFilter {
id: IDFilter
createdAt: TimeFilter
updatedAt: TimeFilter
name: StringFilter
and: MediaItemFilter
or: MediaItemFilter
}
# ------------------------------------------------------------
# -------------------------- Inputs --------------------------
# ------------------------------------------------------------
input NewUser {
email: String!
username: String!
firstName: String
lastName: String
role: Role!
authType: AuthType!
password: String
}
input NewDevice {
name: String!
}
input NewMediaItem {
file: Upload!
tags: [ID!]
albums: [ID!]
}
input NewTag {
name: String!
}
input NewAlbum {
name: String!
}
# ------------------------------------------------------------
# ------------------------ Responses -------------------------
# ------------------------------------------------------------
type PageInfo {
count: Int!
page: Int!
total: Int!
}
type MediaItemResponse {
data: [MediaItem]
pageInfo: PageInfo!
}
type UserResponse {
data: [User]
pageInfo: PageInfo!
}
type DeviceResponse {
data: [Device]
pageInfo: PageInfo!
}
type TagResponse {
data: [Tag]
pageInfo: PageInfo!
}
type AlbumResponse {
data: [Album]
pageInfo: PageInfo!
}
# ------------------------------------------------------------
# --------------------- Query & Mutations --------------------
# ------------------------------------------------------------
type Query {
# Single Item
mediaItem(id: ID!): MediaItem! @hasRole(role: User)
device(id: ID!): Device! @hasRole(role: User)
album(id: ID!): Album! @hasRole(role: User)
tag(id: ID!): Tag! @hasRole(role: User)
user(id: ID!): User! @hasRole(role: Admin)
# All
mediaItems(
filter: MediaItemFilter
count: Int
page: Int
): MediaItemResponse! @hasRole(role: User)
devices(
filter: DeviceFilter
count: Int
page: Int
): DeviceResponse! @hasRole(role: User)
albums(
filter: AlbumFilter
count: Int
page: Int
): AlbumResponse! @hasRole(role: User)
tags(
filter: TagFilter
count: Int
page: Int
): TagResponse! @hasRole(role: User)
users(
filter: UserFilter
count: Int
page: Int
): UserResponse! @hasRole(role: Admin)
}
type Mutation {
createMediaItem(input: NewMediaItem!): MediaItem! @hasRole(role: User)
createDevice(input: NewDevice!): Device! @hasRole(role: User)
createAlbum(input: NewAlbum!): Album! @hasRole(role: User)
createTag(input: NewTag!): Tag! @hasRole(role: User)
createUser(input: NewUser!): User! @hasRole(role: Admin)
}

81
graph/schema.resolvers.go Normal file
View File

@@ -0,0 +1,81 @@
package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"reichard.io/imagini/graph/generated"
"reichard.io/imagini/graph/model"
)
func (r *mutationResolver) CreateMediaItem(ctx context.Context, input model.NewMediaItem) (*model.MediaItem, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) CreateDevice(ctx context.Context, input model.NewDevice) (*model.Device, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) CreateAlbum(ctx context.Context, input model.NewAlbum) (*model.Album, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) CreateTag(ctx context.Context, input model.NewTag) (*model.Tag, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) CreateUser(ctx context.Context, input model.NewUser) (*model.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) MediaItem(ctx context.Context, id string) (*model.MediaItem, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Device(ctx context.Context, id string) (*model.Device, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Album(ctx context.Context, id string) (*model.Album, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Tag(ctx context.Context, id string) (*model.Tag, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) MediaItems(ctx context.Context, filter *model.MediaItemFilter, count *int, page *int) (*model.MediaItemResponse, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Devices(ctx context.Context, filter *model.DeviceFilter, count *int, page *int) (*model.DeviceResponse, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Albums(ctx context.Context, filter *model.AlbumFilter, count *int, page *int) (*model.AlbumResponse, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Tags(ctx context.Context, filter *model.TagFilter, count *int, page *int) (*model.TagResponse, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Users(ctx context.Context, filter *model.UserFilter, count *int, page *int) (*model.UserResponse, error) {
panic(fmt.Errorf("not implemented"))
}
// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }