baublet/w8mngr

View on GitHub
api/config/schema.graphql

Summary

Maintainability
Test Coverage
scalar Date
scalar ID
scalar JSON

"Our root data resolver. Queries to access data should be RARE. All data is contextual, so start from the context and narrow from there."
type User {
  id: ID!
  verified: Boolean!
  preferredName: String!
  weightLog(day: String!): WeightLogConnection!
  weightLogSummary(input: WeightLogSummaryInput): WeightLogSummary!
  foodLog(day: String!): FoodLogConnection!
  foods(input: FoodQueryInput): FoodConnection!
  activities(input: ActivityQueryInput): ActivityConnection!
  activitySummary(input: ActivityVisualizationInput): [TileMapDataPoint!]!
  popularActivities: [Activity!]!
  popularFoods: [Food!]!
  foodLogStats: FoodLogStats!
  preferences: [UserPreference!]!
}

type Query {
  currentUser: User
  upload(input: UploadInput): Upload!
  "Fast, auto-complete ready search for foods"
  searchFoods(input: SearchFoodsInput!): [Food!]!
}

type Mutation {
  # Uploads
  getUploadTokens(input: UploadTokenInput!): UploadTokenMutationPayload!
  saveUploadData(input: UploadInput!): UploadMutationPayload!

  # Authentication
  login(input: LoginInput!): LoginMutationPayload!
  logout: LogoutMutationPayload!
  register(input: RegisterInput!): LoginMutationPayload!
  resetPassword(input: ResetPasswordInput!): ResetPasswordMutationPayload!
  requestPasswordResetToken(
    input: RequestPasswordResetTokenInput!
  ): RequestResetTokenMutationPayload!
  verifyEmail(input: VerifyEmailInput!): VerifyEmailMutationPayload!
  requestEmailLoginLink(
    input: RequestEmailLoginLinkInput!
  ): RequestEmailLoginLinkMutationPayload!
  loginWithToken(input: LoginWithTokenInput!): LoginWithTokenMutationPayload!

  # User
  saveUserPreferences(
    input: SaveUserPreferencesInput!
  ): UserPreferencesMutationPayload!

  # Food Log
  saveFoodLog(input: SaveFoodLogInput!): FoodLogMutationPayload!
  deleteFoodLog(input: DeleteFoodLogInput!): FoodLogMutationPayload!

  # Food
  saveFood(input: FoodInput!): FoodMutationPayload!
  deleteFoodMeasurement(input: FoodMeasurementInput!): FoodMutationPayload!

  # Activities
  saveActivity(input: ActivityInput!): ActivityMutationPayload!
  deleteActivity(input: DeleteActivityInput!): ActivityMutationPayload!

  # Activity Log
  saveActivityLog(input: SaveActivityLogInput!): ActivityLogMutationPayload!
  deleteActivityLog(input: DeleteActivityLogInput!): ActivityLogMutationPayload!

  # Weight Log
  saveWeightLog(input: SaveWeightLogInput!): WeightLogMutationPayload!
  deleteWeightLog(input: DeleteWeightLogInput!): WeightLogMutationPayload!
}

#################
# Enums         #
#################

enum UploadEntityType {
  FOOD_IMAGE
}

enum UploadUrlType {
  "384x384"
  MEDIUM_SQUARE
  "width: 64x64"
  SMALL
  "width: 24x24"
  PREVIEW
}

enum ActivityType {
  "Reps and weight (e.g., 3 reps at 50lbs)"
  WEIGHT
  "e.g., 20 minutes of running"
  TIMED
  "Exercise measured in distance (e.g., 5 miles)"
  DISTANCE
  "Exercise measured in the number of repetitions (e.g., push ups)"
  REPETITIVE
}

enum Muscle {
  ABS
  ADDUCTORS
  BICEPS
  CALVES
  DELTOIDS
  FOREARMS
  GLUTES
  HAMSTRINGS
  LATS
  OBLIQUES
  PECTORALS
  QUADS
  TRAPEZIUS
  TRICEPS
}

enum Unit {
  # Weight
  GRAMS # Default
  G
  KG
  KILOGRAMS
  LB
  LBS
  OUNCES
  OZ
  # Time
  MILLISECONDS
  MS
  SECONDS # Default
  MINUTES
  HOURS
  DAYS
  # Distance
  CENTIMETERS
  CM
  KILOMETERS
  KM
  K
  METERS
  MILES
  MI
  MILLIMETERS # Default
  MM
  FEET
  FT
  YARDS
  YDS
}

enum UserPreferenceType {
  BIRTHDAY
  HEIGHT
  DEFAULT_UNIT
  FATURDAYS
  FATURDAY_CALORIES
  FATURDAY_FAT
  FATURDAY_CARBS
  FATURDAY_PROTEIN
}

#################
# Inputs        #
#################

input SaveUserPreferencesInput {
  preferences: [UserPreferenceInput!]!
}

input UserPreferenceInput {
  key: UserPreferenceType!
  "The JSON.stringified value of the preference"
  value: String!
}

input SearchFoodsInput {
  searchTerm: String!
  page: Int
}

input RequestEmailLoginLinkInput {
  email: String!
}

input LoginWithTokenInput {
  loginToken: String!
}

input VerifyEmailInput {
  token: String!
}

input RequestPasswordResetTokenInput {
  email: String!
}

input ResetPasswordInput {
  password: String!
  passwordConfirmation: String!
  resetToken: String!
}

input ActivityInput {
  id: ID
  name: String
  description: String
  intensity: Int
  "Activity's ExRx.net link"
  exrx: String
  type: ActivityType
  "Muscle groups targeted with this exercise"
  muscleGroups: [Muscle!]
}

input DeleteActivityInput {
  id: ID!
}

input FoodMeasurementInput {
  id: String!
}

input UploadInput {
  id: String
  publicId: String
  entityId: String
  entityType: UploadEntityType
  extension: String
}

input UploadTokenInput {
  count: Int!
}

input LoginInput {
  email: String!
  password: String!
}

input RegisterInput {
  email: String!
  password: String!
  passwordConfirmation: String!
}

input FoodLogConnectionInput {
  before: String
  after: String
  first: Int
  last: Int
  day: String
}

input SaveFoodLogInput {
  day: String!
  foodLogs: [FoodLogInput!]!
}

input SaveActivityLogInput {
  day: String!
  activityId: ID!
  activityLogs: [ActivityLogInput!]!
}

input FoodLogInput {
  id: ID
  description: String!
  calories: Int
  fat: Int
  carbs: Int
  protein: Int
  foodId: ID
  measurementId: ID
}

input ActivityLogInput {
  id: ID
  reps: String
  work: String
}

input WeightLogInput {
  id: ID
  weight: String!
}

input SaveWeightLogInput {
  day: String!
  weightLogs: [WeightLogInput!]!
}

input DeleteWeightLogInput {
  id: ID!
}

input DeleteActivityLogInput {
  id: ID!
}

input DeleteFoodLogInput {
  id: ID!
}

input FoodInput {
  id: ID
  name: String
  description: String
  imageUploadId: String
  measurements: [MeasurementInput!]
}

input MeasurementInput {
  id: ID
  measurement: String
  amount: Int
  calories: Int
  fat: Int
  carbs: Int
  protein: Int
}

input FoodQueryInput {
  before: String
  after: String
  first: Int
  last: Int
  filter: FoodQueryFilters
}

input ActivityQueryInput {
  before: String
  after: String
  first: Int
  last: Int
  filter: ActivityQueryFilters
}

input FoodQueryFilters {
  id: ID
  searchString: String
}

input ActivityQueryFilters {
  id: ID
  muscleGroups: [Muscle!]
  searchString: String
}

input UploadUrlInput {
  type: UploadUrlType!
}

input ActivityVisualizationInput {
  from: Date
  to: Date
}

input WeightLogSummaryInput {
  from: Date
  to: Date
}

#################
# Types         #
#################

type RequestEmailLoginLinkMutationPayload {
  errors: [String!]!
}

type LoginWithTokenMutationPayload {
  currentUser: User
  errors: [String!]!
}

type ResetPasswordMutationPayload {
  currentUser: User
  errors: [String!]!
}

type RequestResetTokenMutationPayload {
  errors: [String!]!
}

type WeightLogVisualizationDataPoint {
  day: String!
  dayLabel: String!
  weight: Int!
  weightLabel: String!
}

type WeightLogSummary {
  currentWeight: Int
  currentWeightLabel: String
  dailyAverage: [WeightLogVisualizationDataPoint!]
}

type FoodLogMutationPayload {
  errors: [String!]!
  logs: FoodLogConnection!
}

type ActivityStats {
  personalRecord: ActivityPersonalRecord
  lastLog: ActivityLastLog
  visualizationData: ActivityVisualizationData!
}

type ActivityLastLog {
  logs: [ActivityLog!]!
  day: String!
  ago: String!
}

type TileMapDataPoint {
  day: String!
  labelData: JSON!
  intensity: Int!
}

type VerifyEmailMutationPayload {
  errors: [String!]!
}

type ActivityVisualizationData {
  maximumWork(
    input: ActivityVisualizationInput
  ): [ActivityVisualizationWorkDataPoint!]!
  averageWork(
    input: ActivityVisualizationInput
  ): [ActivityVisualizationWorkDataPoint!]!
  maximumReps(
    input: ActivityVisualizationInput
  ): [ActivityVisualizationRepsDataPoint!]!
  averageReps(
    input: ActivityVisualizationInput
  ): [ActivityVisualizationRepsDataPoint!]!
  scatterPlot(
    input: ActivityVisualizationInput
  ): [ActivityVisualizationDataPoint!]!
}

type ActivityVisualizationRepsDataPoint {
  day: String!
  reps: Int!
}

type ActivityVisualizationWorkDataPoint {
  day: String!
  dayLabel: String!
  work: Float!
  workLabel: String!
}

type ActivityVisualizationDataPoint {
  day: String!
  reps: Int!
  work: Float!
  workLabel: String!
}

type ActivityPersonalRecord {
  reps: Int
  work: String
  ago: String!
  link: String!
}

type ActivityLogConnection {
  pageInfo: PageInfo!
  day: String!
  edges: [ActivityLogEdge!]!
}

type ActivityLogEdge {
  cursor: String!
  node: ActivityLog!
}

type ActivityLog {
  id: ID!
  reps: Int
  work(unit: Unit): String
  activity: Activity!
  activityId: String!
}

type ActivityLogMutationPayload {
  errors: [String!]!
  logs: ActivityLogConnection!
}

type ActivityMutationPayload {
  errors: [String!]!
  activity: Activity
}

type WeightLogMutationPayload {
  errors: [String!]!
  logs: WeightLogConnection
}

type ActivityConnection {
  pageInfo: PageInfo!
  edges: [ActivityEdge!]!
}

type ActivityEdge {
  cursor: String!
  node: Activity!
}

type Activity {
  id: ID!
  createdAt: Date!
  updatedAt: Date!
  name: String!
  description: String
  "Activity's ExRx.net link"
  exrx: String
  type: ActivityType!
  "Muscle groups targeted with this exercise"
  muscleGroups: [Muscle!]!
  intensity: Int!
  logs(day: String): ActivityLogConnection!
  stats: ActivityStats!
  permissions: GenericObjectPermissions!
}

type GenericObjectPermissions {
  edit: Boolean!
  delete: Boolean!
}

type Upload {
  id: ID!
  publicId: String!
  entity: String!
  entityType: UploadEntityType!
  publicUrl(input: UploadUrlInput): String!
}

type UploadMutationPayload {
  upload: Upload!
}

type UploadTokenMutationPayload {
  tokens: [UploadTokenPayload!]!
  errors: [String!]!
}

type UploadTokenPayload {
  uploadId: String!
  postUrl: String!
  signature: String!
  publicId: String!
  apiKey: String!
  timestamp: String!
  folder: String!
}

type FoodMeasurementConnection {
  pageInfo: PageInfo!
  edges: [FoodMeasurementEdge!]!
}

type FoodMeasurementEdge {
  cursor: String!
  node: FoodMeasurement!
}

type FoodConnection {
  pageInfo: PageInfo!
  edges: [FoodEdge!]!
}

type FoodEdge {
  cursor: String!
  node: Food!
}

type FoodMutationPayload {
  errors: [String!]
  food: Food
}

type LogoutMutationPayload {
  expiredTokens: [String!]!
}

type LoginMutationPayload {
  token: String!
  rememberToken: String!
}

type WeightLogConnection {
  day: String!
  pageInfo: PageInfo!
  edges: [WeightLogEdge!]!
}

type WeightLogEdge {
  cursor: String!
  node: WeightLog!
}

type WeightLog {
  id: ID!
  ago: String!
  createdAt: Date!
  updatedAt: Date!
  weight(unit: Unit): Float!
  weightString(unit: Unit): String!
}

type FoodLogConnection {
  pageInfo: PageInfo!
  day: String!
  edges: [FoodLogEdge!]!
}

type FoodLogEdge {
  cursor: String!
  node: FoodLog!
}

type FoodLog {
  id: ID!
  createdAt: Date!
  updatedAt: Date!
  description: String!
  calories: Int
  fat: Int
  carbs: Int
  protein: Int
  food: Food
}

type PageInfo {
  totalCount: Int!
  hasPreviousPage: Boolean!
  hasNextPage: Boolean!
}

type Food {
  id: ID!
  createdAt: Date!
  updatedAt: Date!
  name: String!
  description: String
  measurements: FoodMeasurementConnection!
  image: Upload
}

type FoodMeasurement {
  id: ID!
  createdAt: Date!
  updatedAt: Date!
  measurement: String!
  amount: Float!
  calories: Int!
  fat: Int!
  carbs: Int!
  protein: Int!
}

type FoodLogStats {
  summary: FoodLogStatSummary!
  visualizationData: [FoodLogDataPoint!]!
}

type FoodLogStatSummary {
  totalFoodsLogged: Int!
  averageDailyCalories: Float!
  averageDailyFat: Float!
  averageDailyCarbs: Float!
  averageDailyProtein: Float!
}

type FoodLogDataPoint {
  day: Date!
  dayLabel: String!
  calories: Float
  fat: Float
  carbs: Float
  protein: Float
}

type UserPreference {
  id: ID!
}

type UserPreferencesMutationPayload {
  errors: [String!]!
  user: User!
}

type UserPreference {
  key: UserPreferenceType!
  "The JSON.parsed value of the preference"
  value: JSON
}