type Query { getAggregatedShotMetrics( aggregateInput: AggregateInputGQL! ): [AggregateResultGQL!]! getUser(userId: Int!): UserGQL getLoggedInUser: UserGQL getDeployedConfig: DeployedConfigGQL! getVideo(videoId: Int!): VideoGQL! getShots(filterInput: FilterInput = null): [ShotGQL!]! getBucketSet(keyName: String!): BucketSetGQL getVideoFeedForUser(limit: Int! = 5, after: String = null): VideoFeedGQL! getVideoMakePercentageIntervals( videoId: ID! intervalDuration: Int! = 300 ): [MakePercentageIntervalGQL!]! } type AggregateResultGQL { featureBuckets: [BucketGQL!]! targetMetrics: TargetMetricGQL! } type BucketGQL { rangeKey: String! lowerBound: Float! } type TargetMetricGQL { count: Int makePercentage: Float floatFeature: TargetFloatFeatureGQL } type TargetFloatFeatureGQL { featureName: String! average: Float median: Float } input AggregateInputGQL { bucketSets: [BucketSetInputGQL!]! filterInput: FilterInput } input BucketSetInputGQL { feature: String! buckets: [BucketInputGQL!]! } input BucketInputGQL { rangeKey: String! lowerBound: Float! } input FilterInput { andFilters: AndFilter = null orFilters: OrFilter = null cueObjectDistance: CueObjectDistanceInput = null targetPocketDistance: TargetPocketDistanceInput = null cueObjectAngle: CueObjectAngleInput = null cueBallSpeed: CueBallSpeedInput = null intendedPocketType: IntendedPocketTypeInput = null shotDirection: ShotDirectionInput = null videoId: [Int!] = null userId: [Int!] = null make: MakeInputGQL = null gameType: GameTypeInputGQL = null } input AndFilter { filters: [FilterInput!]! } input OrFilter { filters: [FilterInput!]! } input CueObjectDistanceInput { value: RangeFilter! } input RangeFilter { lessThan: Float = null greaterThanEqualTo: Float = null } input TargetPocketDistanceInput { value: RangeFilter! } input CueObjectAngleInput { value: RangeFilter! } input CueBallSpeedInput { value: RangeFilter! } input IntendedPocketTypeInput { value: ValueFilterString! } input ValueFilterString { equals: String = null } input ShotDirectionInput { value: ValueFilterString! } input MakeInputGQL { value: ValueFilterBool! } input ValueFilterBool { equals: String = null } input GameTypeInputGQL { value: ValueFilterString! } type UserGQL { id: Int! firebaseUid: String! username: String! profileImageUri: String createdAt: DateTime updatedAt: DateTime statistics: UserStatisticsGQL! } """ Date with time (isoformat) """ scalar DateTime type UserStatisticsGQL { totalShots: Int! totalShotsMade: Int! makePercentage: Decimal! averageTimeBetweenShots: Decimal! timeSpentPlaying: Decimal! medianRun: Decimal } """ Decimal (fixed-point) """ scalar Decimal type DeployedConfigGQL { allowNewUsers: Boolean! } type VideoGQL { id: Int! owner: UserGQL name: String totalShotsMade: Int! totalShots: Int! makePercentage: Float! medianRun: Float averageTimeBetweenShots: Float createdAt: DateTime updatedAt: DateTime shots: [ShotGQL!]! startTime: DateTime endTime: DateTime elapsedTime: Float framesPerSecond: Int! stream: UploadStreamGQL } type ShotGQL { id: Int videoId: Int startFrame: Int endFrame: Int createdAt: DateTime updatedAt: DateTime features: ShotFeaturesGQL cueObjectFeatures: CueObjectFeaturesGQL pocketingIntentionFeatures: PocketingIntentionFeaturesGQL } type ShotFeaturesGQL { cueObjectAngle: Float cueObjectDistance: Float targetPocketDistance: Float intendedPocket: PocketEnum cueBallSpeed: Float shotDirection: ShotDirectionEnum bank: BankFeaturesGQL } enum PocketEnum { CORNER SIDE } enum ShotDirectionEnum { LEFT RIGHT STRAIGHT } type BankFeaturesGQL { wallsHit: [WallTypeEnum!]! bankAngle: Float! distance: Float! } enum WallTypeEnum { LONG SHORT } type CueObjectFeaturesGQL { cueObjectDistance: Float cueObjectAngle: Float cueBallSpeed: Float shotDirection: ShotDirectionEnum } type PocketingIntentionFeaturesGQL { targetPocketDistance: Float make: Boolean intendedPocketType: PocketEnum } type UploadStreamGQL { id: ID! linksRequested: Int! uploadsCompleted: Int! segmentProcessingCursor: Int! isCompleted: Boolean! homographyHistory: [HomographyInfoGQL!]! errors: [StreamErrorGQL!]! createdAt: DateTime! updatedAt: DateTime! } type HomographyInfoGQL { crop: BoundingBoxGQL! pockets: [BoundingBoxGQL!]! sourcePoints: PocketPointsGQL! destPoints: PocketPointsGQL! } type BoundingBoxGQL { left: Int! top: Int! width: Int! height: Int! } type PocketPointsGQL { topLeft: IntPoint2D! topSide: IntPoint2D! topRight: IntPoint2D! bottomLeft: IntPoint2D! bottomSide: IntPoint2D! bottomRight: IntPoint2D! } type IntPoint2D { x: Int! y: Int! } type StreamErrorGQL { message: String! } type BucketSetGQL { keyName: String! feature: String! buckets: [BucketGQL!]! } type VideoFeedGQL { videos: [VideoGQL!]! pageInfo: PageInfoGQL! } type PageInfoGQL { hasNextPage: Boolean! endCursor: String } type MakePercentageIntervalGQL { makePercentage: Float! elapsedTime: Float! } type Mutation { createBucketSet(params: CreateBucketSetInput!): BucketSetGQL! createUploadStream( videoMetadata: VideoMetadataInput! ): CreateUploadStreamReturn! getUploadLink(videoId: Int!, segmentIndex: Int!): GetUploadLinkReturn! terminateUploadStream( videoId: Int! videoMetadata: VideoMetadataInput! ): Boolean! deleteVideo(videoId: Int!): Boolean! getProfileImageUploadLink(fileExt: String = ".png"): GetUploadLinkReturn! editProfileImageUri(profileImageUri: String!): UserGQL! } input CreateBucketSetInput { keyName: String! feature: String! buckets: [BucketInputGQL!]! } type CreateUploadStreamReturn { videoId: Int! } input VideoMetadataInput { videoName: String = null startTime: DateTime = null endTime: DateTime = null gameType: String = null tableSize: String = null uploadStreamMetadataInput: UploadStreamMetadataInput = null } input UploadStreamMetadataInput { deviceType: DeviceTypeEnum = null osVersion: String = null appVersion: String = null browserName: String = null browserVersion: String = null locale: String = null timezone: String = null networkType: String = null ipAddress: String = null } enum DeviceTypeEnum { IOS ANDROID BROWSER } type GetUploadLinkReturn { uploadUrl: String! headers: [Header]! } type Header { key: String! value: String! }