Sfoglia il codice sorgente

started to implement database transaction

Tomi Cvetic 5 anni fa
parent
commit
452a2ace8f

File diff suppressed because it is too large
+ 594 - 436
backend/database/generated/prisma-client/index.ts


+ 205 - 42
backend/database/generated/prisma-client/prisma-schema.ts

@@ -61,6 +61,7 @@ type Block {
   rest: Int
   tracks(where: TrackWhereInput, orderBy: TrackOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Track!]
   blocks(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance!]
+  links(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance!]
   exercises(where: ExerciseInstanceWhereInput, orderBy: ExerciseInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [ExerciseInstance!]
 }
 
@@ -80,7 +81,8 @@ input BlockCreateInput {
   format: FormatCreateOneInput!
   rest: Int
   tracks: TrackCreateManyInput
-  blocks: BlockInstanceCreateManyWithoutBlockInput
+  blocks: BlockInstanceCreateManyWithoutParentBlockInput
+  links: BlockInstanceCreateManyWithoutBlockInput
   exercises: ExerciseInstanceCreateManyInput
 }
 
@@ -89,6 +91,11 @@ input BlockCreateOneWithoutBlocksInput {
   connect: BlockWhereUniqueInput
 }
 
+input BlockCreateOneWithoutLinksInput {
+  create: BlockCreateWithoutLinksInput
+  connect: BlockWhereUniqueInput
+}
+
 input BlockCreatepicturesInput {
   set: [String!]
 }
@@ -107,6 +114,21 @@ input BlockCreateWithoutBlocksInput {
   format: FormatCreateOneInput!
   rest: Int
   tracks: TrackCreateManyInput
+  links: BlockInstanceCreateManyWithoutBlockInput
+  exercises: ExerciseInstanceCreateManyInput
+}
+
+input BlockCreateWithoutLinksInput {
+  id: ID
+  title: String!
+  description: String
+  videos: BlockCreatevideosInput
+  pictures: BlockCreatepicturesInput
+  duration: Int
+  format: FormatCreateOneInput!
+  rest: Int
+  tracks: TrackCreateManyInput
+  blocks: BlockInstanceCreateManyWithoutParentBlockInput
   exercises: ExerciseInstanceCreateManyInput
 }
 
@@ -118,6 +140,8 @@ type BlockEdge {
 type BlockInstance {
   id: ID!
   block: Block!
+  parentTraining: Training
+  parentBlock: Block
   order: Int!
   rounds: Int
   variation: String
@@ -131,24 +155,51 @@ type BlockInstanceConnection {
 
 input BlockInstanceCreateInput {
   id: ID
-  block: BlockCreateOneWithoutBlocksInput!
+  block: BlockCreateOneWithoutLinksInput!
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+  parentBlock: BlockCreateOneWithoutBlocksInput
   order: Int!
   rounds: Int
   variation: String
 }
 
-input BlockInstanceCreateManyInput {
-  create: [BlockInstanceCreateInput!]
+input BlockInstanceCreateManyWithoutBlockInput {
+  create: [BlockInstanceCreateWithoutBlockInput!]
+  connect: [BlockInstanceWhereUniqueInput!]
+}
+
+input BlockInstanceCreateManyWithoutParentBlockInput {
+  create: [BlockInstanceCreateWithoutParentBlockInput!]
   connect: [BlockInstanceWhereUniqueInput!]
 }
 
-input BlockInstanceCreateManyWithoutBlockInput {
-  create: [BlockInstanceCreateWithoutBlockInput!]
+input BlockInstanceCreateManyWithoutParentTrainingInput {
+  create: [BlockInstanceCreateWithoutParentTrainingInput!]
   connect: [BlockInstanceWhereUniqueInput!]
 }
 
 input BlockInstanceCreateWithoutBlockInput {
   id: ID
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+  parentBlock: BlockCreateOneWithoutBlocksInput
+  order: Int!
+  rounds: Int
+  variation: String
+}
+
+input BlockInstanceCreateWithoutParentBlockInput {
+  id: ID
+  block: BlockCreateOneWithoutLinksInput!
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+  order: Int!
+  rounds: Int
+  variation: String
+}
+
+input BlockInstanceCreateWithoutParentTrainingInput {
+  id: ID
+  block: BlockCreateOneWithoutLinksInput!
+  parentBlock: BlockCreateOneWithoutBlocksInput
   order: Int!
   rounds: Int
   variation: String
@@ -245,52 +296,59 @@ input BlockInstanceSubscriptionWhereInput {
   NOT: [BlockInstanceSubscriptionWhereInput!]
 }
 
-input BlockInstanceUpdateDataInput {
-  block: BlockUpdateOneRequiredWithoutBlocksInput
+input BlockInstanceUpdateInput {
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
   order: Int
   rounds: Int
   variation: String
 }
 
-input BlockInstanceUpdateInput {
-  block: BlockUpdateOneRequiredWithoutBlocksInput
+input BlockInstanceUpdateManyDataInput {
   order: Int
   rounds: Int
   variation: String
 }
 
-input BlockInstanceUpdateManyDataInput {
+input BlockInstanceUpdateManyMutationInput {
   order: Int
   rounds: Int
   variation: String
 }
 
-input BlockInstanceUpdateManyInput {
-  create: [BlockInstanceCreateInput!]
-  update: [BlockInstanceUpdateWithWhereUniqueNestedInput!]
-  upsert: [BlockInstanceUpsertWithWhereUniqueNestedInput!]
+input BlockInstanceUpdateManyWithoutBlockInput {
+  create: [BlockInstanceCreateWithoutBlockInput!]
   delete: [BlockInstanceWhereUniqueInput!]
   connect: [BlockInstanceWhereUniqueInput!]
   set: [BlockInstanceWhereUniqueInput!]
   disconnect: [BlockInstanceWhereUniqueInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutBlockInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutBlockInput!]
   deleteMany: [BlockInstanceScalarWhereInput!]
   updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
 }
 
-input BlockInstanceUpdateManyMutationInput {
-  order: Int
-  rounds: Int
-  variation: String
+input BlockInstanceUpdateManyWithoutParentBlockInput {
+  create: [BlockInstanceCreateWithoutParentBlockInput!]
+  delete: [BlockInstanceWhereUniqueInput!]
+  connect: [BlockInstanceWhereUniqueInput!]
+  set: [BlockInstanceWhereUniqueInput!]
+  disconnect: [BlockInstanceWhereUniqueInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutParentBlockInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutParentBlockInput!]
+  deleteMany: [BlockInstanceScalarWhereInput!]
+  updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
 }
 
-input BlockInstanceUpdateManyWithoutBlockInput {
-  create: [BlockInstanceCreateWithoutBlockInput!]
+input BlockInstanceUpdateManyWithoutParentTrainingInput {
+  create: [BlockInstanceCreateWithoutParentTrainingInput!]
   delete: [BlockInstanceWhereUniqueInput!]
   connect: [BlockInstanceWhereUniqueInput!]
   set: [BlockInstanceWhereUniqueInput!]
   disconnect: [BlockInstanceWhereUniqueInput!]
-  update: [BlockInstanceUpdateWithWhereUniqueWithoutBlockInput!]
-  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutBlockInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutParentTrainingInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutParentTrainingInput!]
   deleteMany: [BlockInstanceScalarWhereInput!]
   updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
 }
@@ -301,14 +359,27 @@ input BlockInstanceUpdateManyWithWhereNestedInput {
 }
 
 input BlockInstanceUpdateWithoutBlockDataInput {
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
   order: Int
   rounds: Int
   variation: String
 }
 
-input BlockInstanceUpdateWithWhereUniqueNestedInput {
-  where: BlockInstanceWhereUniqueInput!
-  data: BlockInstanceUpdateDataInput!
+input BlockInstanceUpdateWithoutParentBlockDataInput {
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+  order: Int
+  rounds: Int
+  variation: String
+}
+
+input BlockInstanceUpdateWithoutParentTrainingDataInput {
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
+  order: Int
+  rounds: Int
+  variation: String
 }
 
 input BlockInstanceUpdateWithWhereUniqueWithoutBlockInput {
@@ -316,10 +387,14 @@ input BlockInstanceUpdateWithWhereUniqueWithoutBlockInput {
   data: BlockInstanceUpdateWithoutBlockDataInput!
 }
 
-input BlockInstanceUpsertWithWhereUniqueNestedInput {
+input BlockInstanceUpdateWithWhereUniqueWithoutParentBlockInput {
+  where: BlockInstanceWhereUniqueInput!
+  data: BlockInstanceUpdateWithoutParentBlockDataInput!
+}
+
+input BlockInstanceUpdateWithWhereUniqueWithoutParentTrainingInput {
   where: BlockInstanceWhereUniqueInput!
-  update: BlockInstanceUpdateDataInput!
-  create: BlockInstanceCreateInput!
+  data: BlockInstanceUpdateWithoutParentTrainingDataInput!
 }
 
 input BlockInstanceUpsertWithWhereUniqueWithoutBlockInput {
@@ -328,6 +403,18 @@ input BlockInstanceUpsertWithWhereUniqueWithoutBlockInput {
   create: BlockInstanceCreateWithoutBlockInput!
 }
 
+input BlockInstanceUpsertWithWhereUniqueWithoutParentBlockInput {
+  where: BlockInstanceWhereUniqueInput!
+  update: BlockInstanceUpdateWithoutParentBlockDataInput!
+  create: BlockInstanceCreateWithoutParentBlockInput!
+}
+
+input BlockInstanceUpsertWithWhereUniqueWithoutParentTrainingInput {
+  where: BlockInstanceWhereUniqueInput!
+  update: BlockInstanceUpdateWithoutParentTrainingDataInput!
+  create: BlockInstanceCreateWithoutParentTrainingInput!
+}
+
 input BlockInstanceWhereInput {
   id: ID
   id_not: ID
@@ -344,6 +431,8 @@ input BlockInstanceWhereInput {
   id_ends_with: ID
   id_not_ends_with: ID
   block: BlockWhereInput
+  parentTraining: TrainingWhereInput
+  parentBlock: BlockWhereInput
   order: Int
   order_not: Int
   order_in: [Int!]
@@ -433,7 +522,8 @@ input BlockUpdateInput {
   format: FormatUpdateOneRequiredInput
   rest: Int
   tracks: TrackUpdateManyInput
-  blocks: BlockInstanceUpdateManyWithoutBlockInput
+  blocks: BlockInstanceUpdateManyWithoutParentBlockInput
+  links: BlockInstanceUpdateManyWithoutBlockInput
   exercises: ExerciseInstanceUpdateManyInput
 }
 
@@ -446,10 +536,19 @@ input BlockUpdateManyMutationInput {
   rest: Int
 }
 
-input BlockUpdateOneRequiredWithoutBlocksInput {
+input BlockUpdateOneRequiredWithoutLinksInput {
+  create: BlockCreateWithoutLinksInput
+  update: BlockUpdateWithoutLinksDataInput
+  upsert: BlockUpsertWithoutLinksInput
+  connect: BlockWhereUniqueInput
+}
+
+input BlockUpdateOneWithoutBlocksInput {
   create: BlockCreateWithoutBlocksInput
   update: BlockUpdateWithoutBlocksDataInput
   upsert: BlockUpsertWithoutBlocksInput
+  delete: Boolean
+  disconnect: Boolean
   connect: BlockWhereUniqueInput
 }
 
@@ -470,6 +569,20 @@ input BlockUpdateWithoutBlocksDataInput {
   format: FormatUpdateOneRequiredInput
   rest: Int
   tracks: TrackUpdateManyInput
+  links: BlockInstanceUpdateManyWithoutBlockInput
+  exercises: ExerciseInstanceUpdateManyInput
+}
+
+input BlockUpdateWithoutLinksDataInput {
+  title: String
+  description: String
+  videos: BlockUpdatevideosInput
+  pictures: BlockUpdatepicturesInput
+  duration: Int
+  format: FormatUpdateOneRequiredInput
+  rest: Int
+  tracks: TrackUpdateManyInput
+  blocks: BlockInstanceUpdateManyWithoutParentBlockInput
   exercises: ExerciseInstanceUpdateManyInput
 }
 
@@ -478,6 +591,11 @@ input BlockUpsertWithoutBlocksInput {
   create: BlockCreateWithoutBlocksInput!
 }
 
+input BlockUpsertWithoutLinksInput {
+  update: BlockUpdateWithoutLinksDataInput!
+  create: BlockCreateWithoutLinksInput!
+}
+
 input BlockWhereInput {
   id: ID
   id_not: ID
@@ -544,6 +662,9 @@ input BlockWhereInput {
   blocks_every: BlockInstanceWhereInput
   blocks_some: BlockInstanceWhereInput
   blocks_none: BlockInstanceWhereInput
+  links_every: BlockInstanceWhereInput
+  links_some: BlockInstanceWhereInput
+  links_none: BlockInstanceWhereInput
   exercises_every: ExerciseInstanceWhereInput
   exercises_some: ExerciseInstanceWhereInput
   exercises_none: ExerciseInstanceWhereInput
@@ -762,7 +883,7 @@ scalar DateTime
 type Exercise {
   id: ID!
   name: String!
-  description: String!
+  description: String
   videos: [String!]!
   pictures: [String!]!
   targets: [String!]!
@@ -782,7 +903,7 @@ input ExerciseCreatebaseExerciseInput {
 input ExerciseCreateInput {
   id: ID
   name: String!
-  description: String!
+  description: String
   videos: ExerciseCreatevideosInput
   pictures: ExerciseCreatepicturesInput
   targets: ExerciseCreatetargetsInput
@@ -1050,7 +1171,7 @@ enum ExerciseOrderByInput {
 type ExercisePreviousValues {
   id: ID!
   name: String!
-  description: String!
+  description: String
   videos: [String!]!
   pictures: [String!]!
   targets: [String!]!
@@ -2003,8 +2124,8 @@ type Training {
   title: String!
   type: TrainingType!
   createdAt: DateTime!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
   registrations(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User!]
   attendance: Int
   ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating!]
@@ -2022,13 +2143,30 @@ input TrainingCreateInput {
   id: ID
   title: String!
   type: TrainingTypeCreateOneInput!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
+  registrations: UserCreateManyInput
+  attendance: Int
+  ratings: RatingCreateManyInput
+  published: Boolean!
+  blocks: BlockInstanceCreateManyWithoutParentTrainingInput
+}
+
+input TrainingCreateOneWithoutBlocksInput {
+  create: TrainingCreateWithoutBlocksInput
+  connect: TrainingWhereUniqueInput
+}
+
+input TrainingCreateWithoutBlocksInput {
+  id: ID
+  title: String!
+  type: TrainingTypeCreateOneInput!
+  trainingDate: DateTime!
+  location: String!
   registrations: UserCreateManyInput
   attendance: Int
   ratings: RatingCreateManyInput
   published: Boolean!
-  blocks: BlockInstanceCreateManyInput
 }
 
 type TrainingEdge {
@@ -2057,8 +2195,8 @@ type TrainingPreviousValues {
   id: ID!
   title: String!
   createdAt: DateTime!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
   attendance: Int
   published: Boolean!
 }
@@ -2231,7 +2369,7 @@ input TrainingUpdateInput {
   attendance: Int
   ratings: RatingUpdateManyInput
   published: Boolean
-  blocks: BlockInstanceUpdateManyInput
+  blocks: BlockInstanceUpdateManyWithoutParentTrainingInput
 }
 
 input TrainingUpdateManyMutationInput {
@@ -2242,6 +2380,31 @@ input TrainingUpdateManyMutationInput {
   published: Boolean
 }
 
+input TrainingUpdateOneWithoutBlocksInput {
+  create: TrainingCreateWithoutBlocksInput
+  update: TrainingUpdateWithoutBlocksDataInput
+  upsert: TrainingUpsertWithoutBlocksInput
+  delete: Boolean
+  disconnect: Boolean
+  connect: TrainingWhereUniqueInput
+}
+
+input TrainingUpdateWithoutBlocksDataInput {
+  title: String
+  type: TrainingTypeUpdateOneRequiredInput
+  trainingDate: DateTime
+  location: String
+  registrations: UserUpdateManyInput
+  attendance: Int
+  ratings: RatingUpdateManyInput
+  published: Boolean
+}
+
+input TrainingUpsertWithoutBlocksInput {
+  update: TrainingUpdateWithoutBlocksDataInput!
+  create: TrainingCreateWithoutBlocksInput!
+}
+
 input TrainingWhereInput {
   id: ID
   id_not: ID

+ 216 - 53
backend/database/generated/prisma.graphql

@@ -1,5 +1,5 @@
 # source: http://prisma:4466
-# timestamp: Sun Apr 05 2020 15:33:34 GMT+0000 (Coordinated Universal Time)
+# timestamp: Wed Apr 08 2020 13:30:04 GMT+0000 (Coordinated Universal Time)
 
 type AggregateBlock {
   count: Int!
@@ -61,6 +61,7 @@ type Block implements Node {
   rest: Int
   tracks(where: TrackWhereInput, orderBy: TrackOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Track!]
   blocks(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance!]
+  links(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance!]
   exercises(where: ExerciseInstanceWhereInput, orderBy: ExerciseInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [ExerciseInstance!]
 }
 
@@ -84,7 +85,8 @@ input BlockCreateInput {
   pictures: BlockCreatepicturesInput
   format: FormatCreateOneInput!
   tracks: TrackCreateManyInput
-  blocks: BlockInstanceCreateManyWithoutBlockInput
+  blocks: BlockInstanceCreateManyWithoutParentBlockInput
+  links: BlockInstanceCreateManyWithoutBlockInput
   exercises: ExerciseInstanceCreateManyInput
 }
 
@@ -93,6 +95,11 @@ input BlockCreateOneWithoutBlocksInput {
   connect: BlockWhereUniqueInput
 }
 
+input BlockCreateOneWithoutLinksInput {
+  create: BlockCreateWithoutLinksInput
+  connect: BlockWhereUniqueInput
+}
+
 input BlockCreatepicturesInput {
   set: [String!]
 }
@@ -111,6 +118,21 @@ input BlockCreateWithoutBlocksInput {
   pictures: BlockCreatepicturesInput
   format: FormatCreateOneInput!
   tracks: TrackCreateManyInput
+  links: BlockInstanceCreateManyWithoutBlockInput
+  exercises: ExerciseInstanceCreateManyInput
+}
+
+input BlockCreateWithoutLinksInput {
+  id: ID
+  title: String!
+  description: String
+  duration: Int
+  rest: Int
+  videos: BlockCreatevideosInput
+  pictures: BlockCreatepicturesInput
+  format: FormatCreateOneInput!
+  tracks: TrackCreateManyInput
+  blocks: BlockInstanceCreateManyWithoutParentBlockInput
   exercises: ExerciseInstanceCreateManyInput
 }
 
@@ -126,6 +148,8 @@ type BlockEdge {
 type BlockInstance implements Node {
   id: ID!
   block: Block!
+  parentTraining: Training
+  parentBlock: Block
   order: Int!
   rounds: Int
   variation: String
@@ -146,16 +170,23 @@ input BlockInstanceCreateInput {
   order: Int!
   rounds: Int
   variation: String
-  block: BlockCreateOneWithoutBlocksInput!
+  block: BlockCreateOneWithoutLinksInput!
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+  parentBlock: BlockCreateOneWithoutBlocksInput
 }
 
-input BlockInstanceCreateManyInput {
-  create: [BlockInstanceCreateInput!]
+input BlockInstanceCreateManyWithoutBlockInput {
+  create: [BlockInstanceCreateWithoutBlockInput!]
   connect: [BlockInstanceWhereUniqueInput!]
 }
 
-input BlockInstanceCreateManyWithoutBlockInput {
-  create: [BlockInstanceCreateWithoutBlockInput!]
+input BlockInstanceCreateManyWithoutParentBlockInput {
+  create: [BlockInstanceCreateWithoutParentBlockInput!]
+  connect: [BlockInstanceWhereUniqueInput!]
+}
+
+input BlockInstanceCreateManyWithoutParentTrainingInput {
+  create: [BlockInstanceCreateWithoutParentTrainingInput!]
   connect: [BlockInstanceWhereUniqueInput!]
 }
 
@@ -164,6 +195,26 @@ input BlockInstanceCreateWithoutBlockInput {
   order: Int!
   rounds: Int
   variation: String
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+  parentBlock: BlockCreateOneWithoutBlocksInput
+}
+
+input BlockInstanceCreateWithoutParentBlockInput {
+  id: ID
+  order: Int!
+  rounds: Int
+  variation: String
+  block: BlockCreateOneWithoutLinksInput!
+  parentTraining: TrainingCreateOneWithoutBlocksInput
+}
+
+input BlockInstanceCreateWithoutParentTrainingInput {
+  id: ID
+  order: Int!
+  rounds: Int
+  variation: String
+  block: BlockCreateOneWithoutLinksInput!
+  parentBlock: BlockCreateOneWithoutBlocksInput
 }
 
 """An edge in a connection."""
@@ -365,54 +416,61 @@ input BlockInstanceSubscriptionWhereInput {
   node: BlockInstanceWhereInput
 }
 
-input BlockInstanceUpdateDataInput {
+input BlockInstanceUpdateInput {
   order: Int
   rounds: Int
   variation: String
-  block: BlockUpdateOneRequiredWithoutBlocksInput
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
 }
 
-input BlockInstanceUpdateInput {
+input BlockInstanceUpdateManyDataInput {
   order: Int
   rounds: Int
   variation: String
-  block: BlockUpdateOneRequiredWithoutBlocksInput
 }
 
-input BlockInstanceUpdateManyDataInput {
+input BlockInstanceUpdateManyMutationInput {
   order: Int
   rounds: Int
   variation: String
 }
 
-input BlockInstanceUpdateManyInput {
-  create: [BlockInstanceCreateInput!]
+input BlockInstanceUpdateManyWithoutBlockInput {
+  create: [BlockInstanceCreateWithoutBlockInput!]
   connect: [BlockInstanceWhereUniqueInput!]
   set: [BlockInstanceWhereUniqueInput!]
   disconnect: [BlockInstanceWhereUniqueInput!]
   delete: [BlockInstanceWhereUniqueInput!]
-  update: [BlockInstanceUpdateWithWhereUniqueNestedInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutBlockInput!]
   updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
   deleteMany: [BlockInstanceScalarWhereInput!]
-  upsert: [BlockInstanceUpsertWithWhereUniqueNestedInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutBlockInput!]
 }
 
-input BlockInstanceUpdateManyMutationInput {
-  order: Int
-  rounds: Int
-  variation: String
+input BlockInstanceUpdateManyWithoutParentBlockInput {
+  create: [BlockInstanceCreateWithoutParentBlockInput!]
+  connect: [BlockInstanceWhereUniqueInput!]
+  set: [BlockInstanceWhereUniqueInput!]
+  disconnect: [BlockInstanceWhereUniqueInput!]
+  delete: [BlockInstanceWhereUniqueInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutParentBlockInput!]
+  updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
+  deleteMany: [BlockInstanceScalarWhereInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutParentBlockInput!]
 }
 
-input BlockInstanceUpdateManyWithoutBlockInput {
-  create: [BlockInstanceCreateWithoutBlockInput!]
+input BlockInstanceUpdateManyWithoutParentTrainingInput {
+  create: [BlockInstanceCreateWithoutParentTrainingInput!]
   connect: [BlockInstanceWhereUniqueInput!]
   set: [BlockInstanceWhereUniqueInput!]
   disconnect: [BlockInstanceWhereUniqueInput!]
   delete: [BlockInstanceWhereUniqueInput!]
-  update: [BlockInstanceUpdateWithWhereUniqueWithoutBlockInput!]
+  update: [BlockInstanceUpdateWithWhereUniqueWithoutParentTrainingInput!]
   updateMany: [BlockInstanceUpdateManyWithWhereNestedInput!]
   deleteMany: [BlockInstanceScalarWhereInput!]
-  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutBlockInput!]
+  upsert: [BlockInstanceUpsertWithWhereUniqueWithoutParentTrainingInput!]
 }
 
 input BlockInstanceUpdateManyWithWhereNestedInput {
@@ -424,11 +482,24 @@ input BlockInstanceUpdateWithoutBlockDataInput {
   order: Int
   rounds: Int
   variation: String
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
 }
 
-input BlockInstanceUpdateWithWhereUniqueNestedInput {
-  where: BlockInstanceWhereUniqueInput!
-  data: BlockInstanceUpdateDataInput!
+input BlockInstanceUpdateWithoutParentBlockDataInput {
+  order: Int
+  rounds: Int
+  variation: String
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentTraining: TrainingUpdateOneWithoutBlocksInput
+}
+
+input BlockInstanceUpdateWithoutParentTrainingDataInput {
+  order: Int
+  rounds: Int
+  variation: String
+  block: BlockUpdateOneRequiredWithoutLinksInput
+  parentBlock: BlockUpdateOneWithoutBlocksInput
 }
 
 input BlockInstanceUpdateWithWhereUniqueWithoutBlockInput {
@@ -436,10 +507,14 @@ input BlockInstanceUpdateWithWhereUniqueWithoutBlockInput {
   data: BlockInstanceUpdateWithoutBlockDataInput!
 }
 
-input BlockInstanceUpsertWithWhereUniqueNestedInput {
+input BlockInstanceUpdateWithWhereUniqueWithoutParentBlockInput {
   where: BlockInstanceWhereUniqueInput!
-  update: BlockInstanceUpdateDataInput!
-  create: BlockInstanceCreateInput!
+  data: BlockInstanceUpdateWithoutParentBlockDataInput!
+}
+
+input BlockInstanceUpdateWithWhereUniqueWithoutParentTrainingInput {
+  where: BlockInstanceWhereUniqueInput!
+  data: BlockInstanceUpdateWithoutParentTrainingDataInput!
 }
 
 input BlockInstanceUpsertWithWhereUniqueWithoutBlockInput {
@@ -448,6 +523,18 @@ input BlockInstanceUpsertWithWhereUniqueWithoutBlockInput {
   create: BlockInstanceCreateWithoutBlockInput!
 }
 
+input BlockInstanceUpsertWithWhereUniqueWithoutParentBlockInput {
+  where: BlockInstanceWhereUniqueInput!
+  update: BlockInstanceUpdateWithoutParentBlockDataInput!
+  create: BlockInstanceCreateWithoutParentBlockInput!
+}
+
+input BlockInstanceUpsertWithWhereUniqueWithoutParentTrainingInput {
+  where: BlockInstanceWhereUniqueInput!
+  update: BlockInstanceUpdateWithoutParentTrainingDataInput!
+  create: BlockInstanceCreateWithoutParentTrainingInput!
+}
+
 input BlockInstanceWhereInput {
   """Logical AND on all given filters."""
   AND: [BlockInstanceWhereInput!]
@@ -582,6 +669,8 @@ input BlockInstanceWhereInput {
   """All values not ending with the given string."""
   variation_not_ends_with: String
   block: BlockWhereInput
+  parentTraining: TrainingWhereInput
+  parentBlock: BlockWhereInput
 }
 
 input BlockInstanceWhereUniqueInput {
@@ -657,7 +746,8 @@ input BlockUpdateInput {
   pictures: BlockUpdatepicturesInput
   format: FormatUpdateOneRequiredInput
   tracks: TrackUpdateManyInput
-  blocks: BlockInstanceUpdateManyWithoutBlockInput
+  blocks: BlockInstanceUpdateManyWithoutParentBlockInput
+  links: BlockInstanceUpdateManyWithoutBlockInput
   exercises: ExerciseInstanceUpdateManyInput
 }
 
@@ -670,9 +760,18 @@ input BlockUpdateManyMutationInput {
   pictures: BlockUpdatepicturesInput
 }
 
-input BlockUpdateOneRequiredWithoutBlocksInput {
+input BlockUpdateOneRequiredWithoutLinksInput {
+  create: BlockCreateWithoutLinksInput
+  connect: BlockWhereUniqueInput
+  update: BlockUpdateWithoutLinksDataInput
+  upsert: BlockUpsertWithoutLinksInput
+}
+
+input BlockUpdateOneWithoutBlocksInput {
   create: BlockCreateWithoutBlocksInput
   connect: BlockWhereUniqueInput
+  disconnect: Boolean
+  delete: Boolean
   update: BlockUpdateWithoutBlocksDataInput
   upsert: BlockUpsertWithoutBlocksInput
 }
@@ -694,6 +793,20 @@ input BlockUpdateWithoutBlocksDataInput {
   pictures: BlockUpdatepicturesInput
   format: FormatUpdateOneRequiredInput
   tracks: TrackUpdateManyInput
+  links: BlockInstanceUpdateManyWithoutBlockInput
+  exercises: ExerciseInstanceUpdateManyInput
+}
+
+input BlockUpdateWithoutLinksDataInput {
+  title: String
+  description: String
+  duration: Int
+  rest: Int
+  videos: BlockUpdatevideosInput
+  pictures: BlockUpdatepicturesInput
+  format: FormatUpdateOneRequiredInput
+  tracks: TrackUpdateManyInput
+  blocks: BlockInstanceUpdateManyWithoutParentBlockInput
   exercises: ExerciseInstanceUpdateManyInput
 }
 
@@ -702,6 +815,11 @@ input BlockUpsertWithoutBlocksInput {
   create: BlockCreateWithoutBlocksInput!
 }
 
+input BlockUpsertWithoutLinksInput {
+  update: BlockUpdateWithoutLinksDataInput!
+  create: BlockCreateWithoutLinksInput!
+}
+
 input BlockWhereInput {
   """Logical AND on all given filters."""
   AND: [BlockWhereInput!]
@@ -882,6 +1000,9 @@ input BlockWhereInput {
   blocks_every: BlockInstanceWhereInput
   blocks_some: BlockInstanceWhereInput
   blocks_none: BlockInstanceWhereInput
+  links_every: BlockInstanceWhereInput
+  links_some: BlockInstanceWhereInput
+  links_none: BlockInstanceWhereInput
   exercises_every: ExerciseInstanceWhereInput
   exercises_some: ExerciseInstanceWhereInput
   exercises_none: ExerciseInstanceWhereInput
@@ -1266,7 +1387,7 @@ scalar DateTime
 type Exercise implements Node {
   id: ID!
   name: String!
-  description: String!
+  description: String
   videos: [String!]!
   pictures: [String!]!
   targets: [String!]!
@@ -1290,7 +1411,7 @@ input ExerciseCreatebaseExerciseInput {
 input ExerciseCreateInput {
   id: ID
   name: String!
-  description: String!
+  description: String
   videos: ExerciseCreatevideosInput
   pictures: ExerciseCreatepicturesInput
   targets: ExerciseCreatetargetsInput
@@ -1759,7 +1880,7 @@ enum ExerciseOrderByInput {
 type ExercisePreviousValues {
   id: ID!
   name: String!
-  description: String!
+  description: String
   videos: [String!]!
   pictures: [String!]!
   targets: [String!]!
@@ -2252,67 +2373,67 @@ scalar Long
 type Mutation {
   createTraining(data: TrainingCreateInput!): Training!
   createBlock(data: BlockCreateInput!): Block!
+  createBlockInstance(data: BlockInstanceCreateInput!): BlockInstance!
   createComment(data: CommentCreateInput!): Comment!
   createUser(data: UserCreateInput!): User!
   createTrainingType(data: TrainingTypeCreateInput!): TrainingType!
   createTrack(data: TrackCreateInput!): Track!
   createExercise(data: ExerciseCreateInput!): Exercise!
-  createBlockInstance(data: BlockInstanceCreateInput!): BlockInstance!
   createFormat(data: FormatCreateInput!): Format!
   createExerciseInstance(data: ExerciseInstanceCreateInput!): ExerciseInstance!
   createRating(data: RatingCreateInput!): Rating!
   updateTraining(data: TrainingUpdateInput!, where: TrainingWhereUniqueInput!): Training
   updateBlock(data: BlockUpdateInput!, where: BlockWhereUniqueInput!): Block
+  updateBlockInstance(data: BlockInstanceUpdateInput!, where: BlockInstanceWhereUniqueInput!): BlockInstance
   updateComment(data: CommentUpdateInput!, where: CommentWhereUniqueInput!): Comment
   updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User
   updateTrainingType(data: TrainingTypeUpdateInput!, where: TrainingTypeWhereUniqueInput!): TrainingType
   updateTrack(data: TrackUpdateInput!, where: TrackWhereUniqueInput!): Track
   updateExercise(data: ExerciseUpdateInput!, where: ExerciseWhereUniqueInput!): Exercise
-  updateBlockInstance(data: BlockInstanceUpdateInput!, where: BlockInstanceWhereUniqueInput!): BlockInstance
   updateFormat(data: FormatUpdateInput!, where: FormatWhereUniqueInput!): Format
   updateExerciseInstance(data: ExerciseInstanceUpdateInput!, where: ExerciseInstanceWhereUniqueInput!): ExerciseInstance
   updateRating(data: RatingUpdateInput!, where: RatingWhereUniqueInput!): Rating
   deleteTraining(where: TrainingWhereUniqueInput!): Training
   deleteBlock(where: BlockWhereUniqueInput!): Block
+  deleteBlockInstance(where: BlockInstanceWhereUniqueInput!): BlockInstance
   deleteComment(where: CommentWhereUniqueInput!): Comment
   deleteUser(where: UserWhereUniqueInput!): User
   deleteTrainingType(where: TrainingTypeWhereUniqueInput!): TrainingType
   deleteTrack(where: TrackWhereUniqueInput!): Track
   deleteExercise(where: ExerciseWhereUniqueInput!): Exercise
-  deleteBlockInstance(where: BlockInstanceWhereUniqueInput!): BlockInstance
   deleteFormat(where: FormatWhereUniqueInput!): Format
   deleteExerciseInstance(where: ExerciseInstanceWhereUniqueInput!): ExerciseInstance
   deleteRating(where: RatingWhereUniqueInput!): Rating
   upsertTraining(where: TrainingWhereUniqueInput!, create: TrainingCreateInput!, update: TrainingUpdateInput!): Training!
   upsertBlock(where: BlockWhereUniqueInput!, create: BlockCreateInput!, update: BlockUpdateInput!): Block!
+  upsertBlockInstance(where: BlockInstanceWhereUniqueInput!, create: BlockInstanceCreateInput!, update: BlockInstanceUpdateInput!): BlockInstance!
   upsertComment(where: CommentWhereUniqueInput!, create: CommentCreateInput!, update: CommentUpdateInput!): Comment!
   upsertUser(where: UserWhereUniqueInput!, create: UserCreateInput!, update: UserUpdateInput!): User!
   upsertTrainingType(where: TrainingTypeWhereUniqueInput!, create: TrainingTypeCreateInput!, update: TrainingTypeUpdateInput!): TrainingType!
   upsertTrack(where: TrackWhereUniqueInput!, create: TrackCreateInput!, update: TrackUpdateInput!): Track!
   upsertExercise(where: ExerciseWhereUniqueInput!, create: ExerciseCreateInput!, update: ExerciseUpdateInput!): Exercise!
-  upsertBlockInstance(where: BlockInstanceWhereUniqueInput!, create: BlockInstanceCreateInput!, update: BlockInstanceUpdateInput!): BlockInstance!
   upsertFormat(where: FormatWhereUniqueInput!, create: FormatCreateInput!, update: FormatUpdateInput!): Format!
   upsertExerciseInstance(where: ExerciseInstanceWhereUniqueInput!, create: ExerciseInstanceCreateInput!, update: ExerciseInstanceUpdateInput!): ExerciseInstance!
   upsertRating(where: RatingWhereUniqueInput!, create: RatingCreateInput!, update: RatingUpdateInput!): Rating!
   updateManyTrainings(data: TrainingUpdateManyMutationInput!, where: TrainingWhereInput): BatchPayload!
   updateManyBlocks(data: BlockUpdateManyMutationInput!, where: BlockWhereInput): BatchPayload!
+  updateManyBlockInstances(data: BlockInstanceUpdateManyMutationInput!, where: BlockInstanceWhereInput): BatchPayload!
   updateManyComments(data: CommentUpdateManyMutationInput!, where: CommentWhereInput): BatchPayload!
   updateManyUsers(data: UserUpdateManyMutationInput!, where: UserWhereInput): BatchPayload!
   updateManyTrainingTypes(data: TrainingTypeUpdateManyMutationInput!, where: TrainingTypeWhereInput): BatchPayload!
   updateManyTracks(data: TrackUpdateManyMutationInput!, where: TrackWhereInput): BatchPayload!
   updateManyExercises(data: ExerciseUpdateManyMutationInput!, where: ExerciseWhereInput): BatchPayload!
-  updateManyBlockInstances(data: BlockInstanceUpdateManyMutationInput!, where: BlockInstanceWhereInput): BatchPayload!
   updateManyFormats(data: FormatUpdateManyMutationInput!, where: FormatWhereInput): BatchPayload!
   updateManyExerciseInstances(data: ExerciseInstanceUpdateManyMutationInput!, where: ExerciseInstanceWhereInput): BatchPayload!
   updateManyRatings(data: RatingUpdateManyMutationInput!, where: RatingWhereInput): BatchPayload!
   deleteManyTrainings(where: TrainingWhereInput): BatchPayload!
   deleteManyBlocks(where: BlockWhereInput): BatchPayload!
+  deleteManyBlockInstances(where: BlockInstanceWhereInput): BatchPayload!
   deleteManyComments(where: CommentWhereInput): BatchPayload!
   deleteManyUsers(where: UserWhereInput): BatchPayload!
   deleteManyTrainingTypes(where: TrainingTypeWhereInput): BatchPayload!
   deleteManyTracks(where: TrackWhereInput): BatchPayload!
   deleteManyExercises(where: ExerciseWhereInput): BatchPayload!
-  deleteManyBlockInstances(where: BlockInstanceWhereInput): BatchPayload!
   deleteManyFormats(where: FormatWhereInput): BatchPayload!
   deleteManyExerciseInstances(where: ExerciseInstanceWhereInput): BatchPayload!
   deleteManyRatings(where: RatingWhereInput): BatchPayload!
@@ -2353,34 +2474,34 @@ enum Permission {
 type Query {
   trainings(where: TrainingWhereInput, orderBy: TrainingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Training]!
   blocks(where: BlockWhereInput, orderBy: BlockOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Block]!
+  blockInstances(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance]!
   comments(where: CommentWhereInput, orderBy: CommentOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Comment]!
   users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]!
   trainingTypes(where: TrainingTypeWhereInput, orderBy: TrainingTypeOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TrainingType]!
   tracks(where: TrackWhereInput, orderBy: TrackOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Track]!
   exercises(where: ExerciseWhereInput, orderBy: ExerciseOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Exercise]!
-  blockInstances(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [BlockInstance]!
   formats(where: FormatWhereInput, orderBy: FormatOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Format]!
   exerciseInstances(where: ExerciseInstanceWhereInput, orderBy: ExerciseInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [ExerciseInstance]!
   ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating]!
   training(where: TrainingWhereUniqueInput!): Training
   block(where: BlockWhereUniqueInput!): Block
+  blockInstance(where: BlockInstanceWhereUniqueInput!): BlockInstance
   comment(where: CommentWhereUniqueInput!): Comment
   user(where: UserWhereUniqueInput!): User
   trainingType(where: TrainingTypeWhereUniqueInput!): TrainingType
   track(where: TrackWhereUniqueInput!): Track
   exercise(where: ExerciseWhereUniqueInput!): Exercise
-  blockInstance(where: BlockInstanceWhereUniqueInput!): BlockInstance
   format(where: FormatWhereUniqueInput!): Format
   exerciseInstance(where: ExerciseInstanceWhereUniqueInput!): ExerciseInstance
   rating(where: RatingWhereUniqueInput!): Rating
   trainingsConnection(where: TrainingWhereInput, orderBy: TrainingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TrainingConnection!
   blocksConnection(where: BlockWhereInput, orderBy: BlockOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): BlockConnection!
+  blockInstancesConnection(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): BlockInstanceConnection!
   commentsConnection(where: CommentWhereInput, orderBy: CommentOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): CommentConnection!
   usersConnection(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): UserConnection!
   trainingTypesConnection(where: TrainingTypeWhereInput, orderBy: TrainingTypeOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TrainingTypeConnection!
   tracksConnection(where: TrackWhereInput, orderBy: TrackOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TrackConnection!
   exercisesConnection(where: ExerciseWhereInput, orderBy: ExerciseOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): ExerciseConnection!
-  blockInstancesConnection(where: BlockInstanceWhereInput, orderBy: BlockInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): BlockInstanceConnection!
   formatsConnection(where: FormatWhereInput, orderBy: FormatOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): FormatConnection!
   exerciseInstancesConnection(where: ExerciseInstanceWhereInput, orderBy: ExerciseInstanceOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): ExerciseInstanceConnection!
   ratingsConnection(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): RatingConnection!
@@ -2853,12 +2974,12 @@ input RatingWhereUniqueInput {
 type Subscription {
   training(where: TrainingSubscriptionWhereInput): TrainingSubscriptionPayload
   block(where: BlockSubscriptionWhereInput): BlockSubscriptionPayload
+  blockInstance(where: BlockInstanceSubscriptionWhereInput): BlockInstanceSubscriptionPayload
   comment(where: CommentSubscriptionWhereInput): CommentSubscriptionPayload
   user(where: UserSubscriptionWhereInput): UserSubscriptionPayload
   trainingType(where: TrainingTypeSubscriptionWhereInput): TrainingTypeSubscriptionPayload
   track(where: TrackSubscriptionWhereInput): TrackSubscriptionPayload
   exercise(where: ExerciseSubscriptionWhereInput): ExerciseSubscriptionPayload
-  blockInstance(where: BlockInstanceSubscriptionWhereInput): BlockInstanceSubscriptionPayload
   format(where: FormatSubscriptionWhereInput): FormatSubscriptionPayload
   exerciseInstance(where: ExerciseInstanceSubscriptionWhereInput): ExerciseInstanceSubscriptionPayload
   rating(where: RatingSubscriptionWhereInput): RatingSubscriptionPayload
@@ -3413,8 +3534,8 @@ type Training implements Node {
   title: String!
   type: TrainingType!
   createdAt: DateTime!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
   registrations(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User!]
   attendance: Int
   ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating!]
@@ -3435,14 +3556,31 @@ type TrainingConnection {
 input TrainingCreateInput {
   id: ID
   title: String!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
+  attendance: Int
+  published: Boolean!
+  type: TrainingTypeCreateOneInput!
+  registrations: UserCreateManyInput
+  ratings: RatingCreateManyInput
+  blocks: BlockInstanceCreateManyWithoutParentTrainingInput
+}
+
+input TrainingCreateOneWithoutBlocksInput {
+  create: TrainingCreateWithoutBlocksInput
+  connect: TrainingWhereUniqueInput
+}
+
+input TrainingCreateWithoutBlocksInput {
+  id: ID
+  title: String!
+  trainingDate: DateTime!
+  location: String!
   attendance: Int
   published: Boolean!
   type: TrainingTypeCreateOneInput!
   registrations: UserCreateManyInput
   ratings: RatingCreateManyInput
-  blocks: BlockInstanceCreateManyInput
 }
 
 """An edge in a connection."""
@@ -3475,8 +3613,8 @@ type TrainingPreviousValues {
   id: ID!
   title: String!
   createdAt: DateTime!
-  trainingDate: DateTime
-  location: String
+  trainingDate: DateTime!
+  location: String!
   attendance: Int
   published: Boolean!
 }
@@ -3778,7 +3916,7 @@ input TrainingUpdateInput {
   type: TrainingTypeUpdateOneRequiredInput
   registrations: UserUpdateManyInput
   ratings: RatingUpdateManyInput
-  blocks: BlockInstanceUpdateManyInput
+  blocks: BlockInstanceUpdateManyWithoutParentTrainingInput
 }
 
 input TrainingUpdateManyMutationInput {
@@ -3789,6 +3927,31 @@ input TrainingUpdateManyMutationInput {
   published: Boolean
 }
 
+input TrainingUpdateOneWithoutBlocksInput {
+  create: TrainingCreateWithoutBlocksInput
+  connect: TrainingWhereUniqueInput
+  disconnect: Boolean
+  delete: Boolean
+  update: TrainingUpdateWithoutBlocksDataInput
+  upsert: TrainingUpsertWithoutBlocksInput
+}
+
+input TrainingUpdateWithoutBlocksDataInput {
+  title: String
+  trainingDate: DateTime
+  location: String
+  attendance: Int
+  published: Boolean
+  type: TrainingTypeUpdateOneRequiredInput
+  registrations: UserUpdateManyInput
+  ratings: RatingUpdateManyInput
+}
+
+input TrainingUpsertWithoutBlocksInput {
+  update: TrainingUpdateWithoutBlocksDataInput!
+  create: TrainingCreateWithoutBlocksInput!
+}
+
 input TrainingWhereInput {
   """Logical AND on all given filters."""
   AND: [TrainingWhereInput!]

+ 10 - 7
backend/datamodel.prisma

@@ -23,12 +23,12 @@ type Training {
     type: TrainingType!
     createdAt: DateTime! @createdAt
     trainingDate: DateTime!
-    location: String
+    location: String!
     registrations: [User!]!
     attendance: Int
     ratings: [Rating!]!
     published: Boolean!
-    blocks: [BlockInstance!]!
+    blocks: [BlockInstance!]! @relation(onDelete: CASCADE)
 }
 
 type TrainingType {
@@ -47,13 +47,16 @@ type Block {
     format: Format!
     rest: Int
     tracks: [Track!]!
-    blocks: [BlockInstance!]!
-    exercises: [ExerciseInstance!]!
+    blocks: [BlockInstance!] @relation(name: "Instances", onDelete: CASCADE)
+    links: [BlockInstance!]! @relation(name: "ParentChild", onDelete: CASCADE)
+    exercises: [ExerciseInstance!]! @relation(onDelete: CASCADE)
 }
 
 type BlockInstance {
     id: ID! @id
-    block: Block!
+    block: Block! @relation(name: "ParentChild", onDelete: SET_NULL)
+    parentTraining: Training @relation(link: INLINE)
+    parentBlock: Block @relation(name: "Instances")
     order: Int!
     rounds: Int
     variation: String
@@ -76,7 +79,7 @@ type Track {
 type Exercise {
     id: ID! @id
     name: String!
-    description: String!
+    description: String
     videos: [String!]! @scalarList(strategy: RELATION)
     pictures: [String!]! @scalarList(strategy: RELATION)
     targets: [String!]! @scalarList(strategy: RELATION)
@@ -85,7 +88,7 @@ type Exercise {
 
 type ExerciseInstance {
     id: ID! @id
-    exercise: Exercise!
+    exercise: Exercise! @relation(link: INLINE)
     order: Int!
     repetitions: Int
     variation: String

+ 13 - 13
backend/schema.graphql

@@ -75,21 +75,21 @@ type Mutation {
     location: String
     attendance: Int
     published: Boolean!
-    blocks: BlockInstanceCreateManyInput
+    blocks: BlockInstanceCreateManyWithoutParentTrainingInput
   ): Training!
   createTrainingType(name: String!, description: String!): TrainingType!
-  createBlock(
-    title: String!
-    description: String
-    videos: [String!]
-    pictures: [String!]
-    duration: Int
-    format: FormatCreateOneInput!
-    rest: Int
-    tracks: TrackCreateManyInput
-    blocks: BlockInstanceCreateManyWithoutBlockInput
-    exercises: ExerciseInstanceCreateManyInput
-  ): Block!
+  # createBlock(
+  #   title: String!
+  #   description: String
+  #   videos: [String!]
+  #   pictures: [String!]
+  #   duration: Int
+  #   format: FormatCreateOneInput!
+  #   rest: Int
+  #   tracks: TrackCreateManyInput
+  #   blocks: BlockInstanceCreateManyInput
+  #   exercises: ExerciseInstanceCreateManyInput
+  # ): Block!
   createFormat(name: String!, description: String!): Format!
   userLogin(email: String!, password: String!): User!
   userLogout: String!

+ 7 - 6
backend/src/training/resolvers.ts

@@ -2,7 +2,7 @@
 
 import { IResolvers } from 'apollo-server-express'
 import { checkPermission } from '../user/resolvers'
-
+import { inspect } from 'util'
 //const LoginError = new Error('You must be logged in.')
 //const PermissionError = new Error('Insufficient permissions.')
 
@@ -33,6 +33,7 @@ export const resolvers: IResolvers = {
   Mutation: {
     createTraining: async (parent, args, context, info) => {
       checkPermission(context, ['INSTRUCTOR', 'ADMIN'])
+      console.log(inspect(args, false, null, true))
       const training = await context.db.mutation.createTraining(
         { data: args },
         info
@@ -47,11 +48,11 @@ export const resolvers: IResolvers = {
       )
       return trainingType
     },
-    createBlock: async (parent, args, context, info) => {
-      checkPermission(context, ['INSTRUCTOR', 'ADMIN'])
-      const block = await context.db.mutation.createBlock({ data: args }, info)
-      return block
-    },
+    // createBlock: async (parent, args, context, info) => {
+    //   checkPermission(context, ['INSTRUCTOR', 'ADMIN'])
+    //   const block = await context.db.mutation.createBlock({ data: args }, info)
+    //   return block
+    // },
     createFormat: async (parent, args, context, info) => {
       checkPermission(context, ['INSTRUCTOR', 'ADMIN'])
       const block = await context.db.mutation.createFormat({ data: args }, info)

+ 2 - 0
frontend/src/form/components/TextInput.tsx

@@ -14,6 +14,7 @@ const TextInput = ({
   id,
   type,
   onChange,
+  value,
   ...props
 }: ITextInput) => {
   function handleChange(event: ChangeEvent<HTMLInputElement>) {
@@ -35,6 +36,7 @@ const TextInput = ({
       <input
         id={id || name}
         name={name}
+        value={value ?? ''}
         type={type}
         onChange={handleChange}
         {...props}

+ 128 - 32
frontend/src/gql/index.tsx

@@ -25,6 +25,7 @@ export type Block = Node & {
   rest?: Maybe<Scalars['Int']>,
   tracks?: Maybe<Array<Track>>,
   blocks?: Maybe<Array<BlockInstance>>,
+  links?: Maybe<Array<BlockInstance>>,
   exercises?: Maybe<Array<ExerciseInstance>>,
 };
 
@@ -51,6 +52,17 @@ export type BlockBlocksArgs = {
 };
 
 
+export type BlockLinksArgs = {
+  where?: Maybe<BlockInstanceWhereInput>,
+  orderBy?: Maybe<BlockInstanceOrderByInput>,
+  skip?: Maybe<Scalars['Int']>,
+  after?: Maybe<Scalars['String']>,
+  before?: Maybe<Scalars['String']>,
+  first?: Maybe<Scalars['Int']>,
+  last?: Maybe<Scalars['Int']>
+};
+
+
 export type BlockExercisesArgs = {
   where?: Maybe<ExerciseInstanceWhereInput>,
   orderBy?: Maybe<ExerciseInstanceOrderByInput>,
@@ -66,6 +78,11 @@ export type BlockCreateOneWithoutBlocksInput = {
   connect?: Maybe<BlockWhereUniqueInput>,
 };
 
+export type BlockCreateOneWithoutLinksInput = {
+  create?: Maybe<BlockCreateWithoutLinksInput>,
+  connect?: Maybe<BlockWhereUniqueInput>,
+};
+
 export type BlockCreatepicturesInput = {
   set?: Maybe<Array<Scalars['String']>>,
 };
@@ -84,32 +101,46 @@ export type BlockCreateWithoutBlocksInput = {
   pictures?: Maybe<BlockCreatepicturesInput>,
   format: FormatCreateOneInput,
   tracks?: Maybe<TrackCreateManyInput>,
+  links?: Maybe<BlockInstanceCreateManyWithoutBlockInput>,
+  exercises?: Maybe<ExerciseInstanceCreateManyInput>,
+};
+
+export type BlockCreateWithoutLinksInput = {
+  id?: Maybe<Scalars['ID']>,
+  title: Scalars['String'],
+  description?: Maybe<Scalars['String']>,
+  duration?: Maybe<Scalars['Int']>,
+  rest?: Maybe<Scalars['Int']>,
+  videos?: Maybe<BlockCreatevideosInput>,
+  pictures?: Maybe<BlockCreatepicturesInput>,
+  format: FormatCreateOneInput,
+  tracks?: Maybe<TrackCreateManyInput>,
+  blocks?: Maybe<BlockInstanceCreateManyWithoutParentBlockInput>,
   exercises?: Maybe<ExerciseInstanceCreateManyInput>,
 };
 
 export type BlockInstance = Node & {
   id: Scalars['ID'],
   block: Block,
+  parentTraining?: Maybe<Training>,
+  parentBlock?: Maybe<Block>,
   order: Scalars['Int'],
   rounds?: Maybe<Scalars['Int']>,
   variation?: Maybe<Scalars['String']>,
 };
 
-export type BlockInstanceCreateInput = {
-  id?: Maybe<Scalars['ID']>,
-  order: Scalars['Int'],
-  rounds?: Maybe<Scalars['Int']>,
-  variation?: Maybe<Scalars['String']>,
-  block: BlockCreateOneWithoutBlocksInput,
+export type BlockInstanceCreateManyWithoutBlockInput = {
+  create?: Maybe<Array<BlockInstanceCreateWithoutBlockInput>>,
+  connect?: Maybe<Array<BlockInstanceWhereUniqueInput>>,
 };
 
-export type BlockInstanceCreateManyInput = {
-  create?: Maybe<Array<BlockInstanceCreateInput>>,
+export type BlockInstanceCreateManyWithoutParentBlockInput = {
+  create?: Maybe<Array<BlockInstanceCreateWithoutParentBlockInput>>,
   connect?: Maybe<Array<BlockInstanceWhereUniqueInput>>,
 };
 
-export type BlockInstanceCreateManyWithoutBlockInput = {
-  create?: Maybe<Array<BlockInstanceCreateWithoutBlockInput>>,
+export type BlockInstanceCreateManyWithoutParentTrainingInput = {
+  create?: Maybe<Array<BlockInstanceCreateWithoutParentTrainingInput>>,
   connect?: Maybe<Array<BlockInstanceWhereUniqueInput>>,
 };
 
@@ -118,6 +149,26 @@ export type BlockInstanceCreateWithoutBlockInput = {
   order: Scalars['Int'],
   rounds?: Maybe<Scalars['Int']>,
   variation?: Maybe<Scalars['String']>,
+  parentTraining?: Maybe<TrainingCreateOneWithoutBlocksInput>,
+  parentBlock?: Maybe<BlockCreateOneWithoutBlocksInput>,
+};
+
+export type BlockInstanceCreateWithoutParentBlockInput = {
+  id?: Maybe<Scalars['ID']>,
+  order: Scalars['Int'],
+  rounds?: Maybe<Scalars['Int']>,
+  variation?: Maybe<Scalars['String']>,
+  block: BlockCreateOneWithoutLinksInput,
+  parentTraining?: Maybe<TrainingCreateOneWithoutBlocksInput>,
+};
+
+export type BlockInstanceCreateWithoutParentTrainingInput = {
+  id?: Maybe<Scalars['ID']>,
+  order: Scalars['Int'],
+  rounds?: Maybe<Scalars['Int']>,
+  variation?: Maybe<Scalars['String']>,
+  block: BlockCreateOneWithoutLinksInput,
+  parentBlock?: Maybe<BlockCreateOneWithoutBlocksInput>,
 };
 
 export enum BlockInstanceOrderByInput {
@@ -223,6 +274,8 @@ export type BlockInstanceWhereInput = {
   /** All values not ending with the given string. */
   variation_not_ends_with?: Maybe<Scalars['String']>,
   block?: Maybe<BlockWhereInput>,
+  parentTraining?: Maybe<TrainingWhereInput>,
+  parentBlock?: Maybe<BlockWhereInput>,
 };
 
 export type BlockInstanceWhereUniqueInput = {
@@ -367,6 +420,9 @@ export type BlockWhereInput = {
   blocks_every?: Maybe<BlockInstanceWhereInput>,
   blocks_some?: Maybe<BlockInstanceWhereInput>,
   blocks_none?: Maybe<BlockInstanceWhereInput>,
+  links_every?: Maybe<BlockInstanceWhereInput>,
+  links_some?: Maybe<BlockInstanceWhereInput>,
+  links_none?: Maybe<BlockInstanceWhereInput>,
   exercises_every?: Maybe<ExerciseInstanceWhereInput>,
   exercises_some?: Maybe<ExerciseInstanceWhereInput>,
   exercises_none?: Maybe<ExerciseInstanceWhereInput>,
@@ -603,7 +659,7 @@ export type CommentWhereUniqueInput = {
 export type Exercise = Node & {
   id: Scalars['ID'],
   name: Scalars['String'],
-  description: Scalars['String'],
+  description?: Maybe<Scalars['String']>,
   videos: Array<Scalars['String']>,
   pictures: Array<Scalars['String']>,
   targets: Array<Scalars['String']>,
@@ -617,7 +673,7 @@ export type ExerciseCreatebaseExerciseInput = {
 export type ExerciseCreateInput = {
   id?: Maybe<Scalars['ID']>,
   name: Scalars['String'],
-  description: Scalars['String'],
+  description?: Maybe<Scalars['String']>,
   videos?: Maybe<ExerciseCreatevideosInput>,
   pictures?: Maybe<ExerciseCreatepicturesInput>,
   targets?: Maybe<ExerciseCreatetargetsInput>,
@@ -1000,7 +1056,6 @@ export type Mutation = {
   deleteUser?: Maybe<User>,
   createTraining: Training,
   createTrainingType: TrainingType,
-  createBlock: Block,
   createFormat: Format,
   userLogin: User,
   userLogout: Scalars['String'],
@@ -1033,7 +1088,7 @@ export type MutationCreateTrainingArgs = {
   location?: Maybe<Scalars['String']>,
   attendance?: Maybe<Scalars['Int']>,
   published: Scalars['Boolean'],
-  blocks?: Maybe<BlockInstanceCreateManyInput>
+  blocks?: Maybe<BlockInstanceCreateManyWithoutParentTrainingInput>
 };
 
 
@@ -1043,20 +1098,6 @@ export type MutationCreateTrainingTypeArgs = {
 };
 
 
-export type MutationCreateBlockArgs = {
-  title: Scalars['String'],
-  description?: Maybe<Scalars['String']>,
-  videos?: Maybe<Array<Scalars['String']>>,
-  pictures?: Maybe<Array<Scalars['String']>>,
-  duration?: Maybe<Scalars['Int']>,
-  format: FormatCreateOneInput,
-  rest?: Maybe<Scalars['Int']>,
-  tracks?: Maybe<TrackCreateManyInput>,
-  blocks?: Maybe<BlockInstanceCreateManyWithoutBlockInput>,
-  exercises?: Maybe<ExerciseInstanceCreateManyInput>
-};
-
-
 export type MutationCreateFormatArgs = {
   name: Scalars['String'],
   description: Scalars['String']
@@ -1217,6 +1258,18 @@ export type Rating = Node & {
   createdAt: Scalars['DateTime'],
 };
 
+export type RatingCreateInput = {
+  id?: Maybe<Scalars['ID']>,
+  value: Scalars['Int'],
+  comment: Scalars['String'],
+  user: UserCreateOneWithoutRatingsInput,
+};
+
+export type RatingCreateManyInput = {
+  create?: Maybe<Array<RatingCreateInput>>,
+  connect?: Maybe<Array<RatingWhereUniqueInput>>,
+};
+
 export type RatingCreateManyWithoutUserInput = {
   create?: Maybe<Array<RatingCreateWithoutUserInput>>,
   connect?: Maybe<Array<RatingWhereUniqueInput>>,
@@ -1643,8 +1696,8 @@ export type Training = Node & {
   title: Scalars['String'],
   type: TrainingType,
   createdAt: Scalars['DateTime'],
-  trainingDate?: Maybe<Scalars['DateTime']>,
-  location?: Maybe<Scalars['String']>,
+  trainingDate: Scalars['DateTime'],
+  location: Scalars['String'],
   registrations?: Maybe<Array<User>>,
   attendance?: Maybe<Scalars['Int']>,
   ratings?: Maybe<Array<Rating>>,
@@ -1685,6 +1738,23 @@ export type TrainingBlocksArgs = {
   last?: Maybe<Scalars['Int']>
 };
 
+export type TrainingCreateOneWithoutBlocksInput = {
+  create?: Maybe<TrainingCreateWithoutBlocksInput>,
+  connect?: Maybe<TrainingWhereUniqueInput>,
+};
+
+export type TrainingCreateWithoutBlocksInput = {
+  id?: Maybe<Scalars['ID']>,
+  title: Scalars['String'],
+  trainingDate: Scalars['DateTime'],
+  location: Scalars['String'],
+  attendance?: Maybe<Scalars['Int']>,
+  published: Scalars['Boolean'],
+  type: TrainingTypeCreateOneInput,
+  registrations?: Maybe<UserCreateManyInput>,
+  ratings?: Maybe<RatingCreateManyInput>,
+};
+
 export enum TrainingOrderByInput {
   IdAsc = 'id_ASC',
   IdDesc = 'id_DESC',
@@ -1971,6 +2041,10 @@ export type TrainingWhereInput = {
   blocks_none?: Maybe<BlockInstanceWhereInput>,
 };
 
+export type TrainingWhereUniqueInput = {
+  id?: Maybe<Scalars['ID']>,
+};
+
 export type User = Node & {
   id: Scalars['ID'],
   email: Scalars['String'],
@@ -2024,10 +2098,32 @@ export type UserCreateinterestsInput = {
   set?: Maybe<Array<Scalars['String']>>,
 };
 
+export type UserCreateManyInput = {
+  create?: Maybe<Array<UserCreateInput>>,
+  connect?: Maybe<Array<UserWhereUniqueInput>>,
+};
+
+export type UserCreateOneWithoutRatingsInput = {
+  create?: Maybe<UserCreateWithoutRatingsInput>,
+  connect?: Maybe<UserWhereUniqueInput>,
+};
+
 export type UserCreatepermissionsInput = {
   set?: Maybe<Array<Permission>>,
 };
 
+export type UserCreateWithoutRatingsInput = {
+  id?: Maybe<Scalars['ID']>,
+  email: Scalars['String'],
+  name: Scalars['String'],
+  password: Scalars['String'],
+  resetToken?: Maybe<Scalars['String']>,
+  resetTokenExpiry?: Maybe<Scalars['Float']>,
+  permissions?: Maybe<UserCreatepermissionsInput>,
+  interests?: Maybe<UserCreateinterestsInput>,
+  comments?: Maybe<CommentCreateManyWithoutAuthorInput>,
+};
+
 export enum UserOrderByInput {
   IdAsc = 'id_ASC',
   IdDesc = 'id_DESC',
@@ -2313,7 +2409,7 @@ export type CreateTrainingMutationVariables = {
   location: Scalars['String'],
   attendance: Scalars['Int'],
   published: Scalars['Boolean'],
-  blocks?: Maybe<BlockInstanceCreateManyInput>
+  blocks?: Maybe<BlockInstanceCreateManyWithoutParentTrainingInput>
 };
 
 
@@ -2647,7 +2743,7 @@ export type FormatsQueryHookResult = ReturnType<typeof useFormatsQuery>;
 export type FormatsLazyQueryHookResult = ReturnType<typeof useFormatsLazyQuery>;
 export type FormatsQueryResult = ApolloReactCommon.QueryResult<FormatsQuery, FormatsQueryVariables>;
 export const CreateTrainingDocument = gql`
-    mutation createTraining($title: String!, $type: TrainingTypeCreateOneInput!, $trainingDate: DateTime!, $location: String!, $attendance: Int!, $published: Boolean!, $blocks: BlockInstanceCreateManyInput) {
+    mutation createTraining($title: String!, $type: TrainingTypeCreateOneInput!, $trainingDate: DateTime!, $location: String!, $attendance: Int!, $published: Boolean!, $blocks: BlockInstanceCreateManyWithoutParentTrainingInput) {
   createTraining(title: $title, type: $type, trainingDate: $trainingDate, location: $location, attendance: $attendance, published: $published, blocks: $blocks) {
     id
   }

+ 4 - 1
frontend/src/training/components/BlockInputs.tsx

@@ -22,7 +22,10 @@ const BlockInputs = ({ onChange, value, name }: IBlockInputs) => {
       <FormatSelector
         name={`${name}.format`}
         value={value.format}
-        onChange={onChange}
+        onChange={data => {
+          console.log({ data })
+          onChange(data)
+        }}
       />
       <TextInput
         name={`${name}.description`}

+ 6 - 10
frontend/src/training/components/BlockInstanceInputs.tsx

@@ -45,12 +45,6 @@ const BlockInstanceInputs = ({
     const stateWithoutRemovedItems = state.filter(stateId =>
       value.find(item => stateId === item.id)
     )
-    console.log('filtered!', {
-      value,
-      state,
-      missingIds,
-      stateWithoutRemovedItems
-    })
     setState([...stateWithoutRemovedItems, ...missingIds])
   }, [value])
 
@@ -64,14 +58,17 @@ const BlockInstanceInputs = ({
           {item.order} {item.id}
         </p>
         <TextInput
-          name='rounds'
+          name={`${name}.${itemIndex}.rounds`}
           label='Rounds'
           value={item.rounds}
           type='number'
-          onChange={onChange}
+          onChange={data => {
+            console.log(data)
+            onChange(data)
+          }}
         />
         <TextInput
-          name='variation'
+          name={`${name}.${itemIndex}.variation`}
           label='Variation'
           value={item.variation}
           onChange={onChange}
@@ -87,7 +84,6 @@ const BlockInstanceInputs = ({
     )
   })
 
-  console.log({ name, items, value, state })
   return (
     <SortableList
       items={items}

+ 2 - 2
frontend/src/training/components/AddFormat.tsx → frontend/src/training/components/CreateFormat.tsx

@@ -6,7 +6,7 @@ import {
 } from '../../gql'
 import { FetchResult } from '@apollo/client'
 
-const AddFormat = ({
+const CreateFormat = ({
   onSuccess
 }: {
   onSuccess: (
@@ -57,4 +57,4 @@ const AddFormat = ({
   )
 }
 
-export default AddFormat
+export default CreateFormat

+ 58 - 3
frontend/src/training/components/EditTraining.tsx

@@ -3,18 +3,71 @@ import { useForm, TextInput, DateTimeInput, Checkbox } from '../../form'
 import { emptyTraining, emptyBlockInstance } from '../utils'
 import TrainingTypeSelector from './TrainingTypeSelector'
 import BlockInstanceInputs from './BlockInstanceInputs'
+import { TTraining } from '../types'
+import { transform, isArray } from 'lodash'
 
-const EditTraining = ({ training }: { training?: Partial<Training> }) => {
+const EditTraining = ({ training }: { training?: TTraining }) => {
   const { values, touched, onChange, loadData } = useForm(
     training || emptyTraining()
   )
   const [createTraining, createData] = useCreateTrainingMutation()
+  //const [updateTraining, updateDate] = useUpdateTrainingMutation()
 
   return (
     <form
       onSubmit={ev => {
         ev.preventDefault()
-        //createTraining({ variables: values })
+        function collect(arr: any[]) {
+          const create: any[] = []
+          const connect: any[] = []
+          arr.forEach(val => {
+            if (typeof val === 'object' && val['connect']) {
+              connect.push(val['connect'])
+            }
+            if (typeof val === 'object' && val['create']) {
+              create.push(val['create'])
+            }
+          })
+          if (create.length > 0 || connect.length > 0) {
+            return { connect }
+          } else {
+            return arr
+          }
+        }
+        function magic(acc: any, val: any, key: any, object: any) {
+          if (key === '__typename') {
+            // remove the typename from the database
+            return
+          } else if (
+            key === 'id' &&
+            typeof val === 'string' &&
+            val.startsWith('__')
+          ) {
+            // remove placeholder IDs
+            return
+          } else if (isArray(val)) {
+            // collect 'create' and 'connect' statements
+            acc[key] = collect(transform(val, magic))
+          } else if (typeof val === 'object' && !!val) {
+            // we found an object!
+            if (
+              !!val['id'] &&
+              typeof val['id'] === 'string' &&
+              val['id'].startsWith('__')
+            ) {
+              // values with placeholder IDs are preserved
+              acc[key] = { create: transform(val, magic) }
+            } else {
+              // values with real IDs are just connected
+              acc[key] = { connect: { id: val['id'] } }
+            }
+          } else {
+            // copy the value
+            acc[key] = val
+          }
+        }
+        const newValues = transform(values, magic)
+        createTraining({ variables: newValues })
       }}
     >
       <TextInput
@@ -64,7 +117,9 @@ const EditTraining = ({ training }: { training?: Partial<Training> }) => {
       <button
         onClick={event => {
           event.preventDefault()
-          const newBlock = emptyBlockInstance()
+          const newBlock = emptyBlockInstance({
+            order: values.blocks ? values.blocks.length : 0
+          })
           onChange({
             target: {
               type: 'custom',

+ 8 - 7
frontend/src/training/components/FormatSelector.tsx

@@ -1,6 +1,6 @@
 import { useFormatsQuery, FormatCreateOneInput, Format } from '../../gql'
 import { useEffect, useState } from 'react'
-import AddFormat from './AddFormat'
+import CreateFormat from './CreateFormat'
 import { Modal } from '../../modal'
 
 interface IFormatSelector {
@@ -40,14 +40,14 @@ const FormatSelector = ({
         name={name}
         value={id}
         onChange={event => {
-          const copy: CustomChangeEvent = {
+          const changeEvent: CustomChangeEvent = {
             target: {
               type: 'custom',
               value: { connect: { id: event.target.value } },
               name
             }
           }
-          onChange(copy)
+          onChange(changeEvent)
         }}
       >
         {formats.loading && 'loading formats...'}
@@ -68,18 +68,19 @@ const FormatSelector = ({
         Add format
       </button>
       <Modal state={[modalState, setModalState]}>
-        <AddFormat
+        <CreateFormat
           onSuccess={result => {
-            setModalState(false)
             if (result.data) {
-              onChange({
+              const changeEvent: CustomChangeEvent = {
                 target: {
                   type: 'custom',
                   value: { connect: { id: result.data.createFormat.id } },
                   name
                 }
-              })
+              }
+              onChange(changeEvent)
             }
+            setModalState(false)
           }}
         />
       </Modal>

+ 2 - 2
frontend/src/training/components/TrainingTypeSelector.tsx

@@ -47,7 +47,7 @@ const TrainingTypeSelector = ({
           const copy: CustomChangeEvent = {
             target: {
               type: 'custom',
-              value: { connect: { id: event.target.value } },
+              value: { id: event.target.value },
               name
             }
           }
@@ -79,7 +79,7 @@ const TrainingTypeSelector = ({
               onChange({
                 target: {
                   type: 'custom',
-                  value: { connect: { id: result.data.createTrainingType.id } },
+                  value: { id: result.data.createTrainingType.id },
                   name
                 }
               })

+ 1 - 1
frontend/src/training/training.graphql

@@ -145,7 +145,7 @@ mutation createTraining(
   $location: String!
   $attendance: Int!
   $published: Boolean!
-  $blocks: BlockInstanceCreateManyInput
+  $blocks: BlockInstanceCreateManyWithoutParentTrainingInput
 ) {
   createTraining(
     title: $title

+ 2 - 2
frontend/src/training/utils.ts

@@ -1,5 +1,5 @@
 import { parse } from 'date-fns'
-import { IBlock, IExercise, IRating } from './types'
+import { IBlock, IExercise, IRating, TTraining } from './types'
 import {
   TrainingQuery,
   SubBlockFragment,
@@ -134,7 +134,7 @@ export function emptyBlockInstance(input?: Partial<SubBlockFragment>) {
   return { ...emptyBlockInstance, ...input }
 }
 
-export function emptyTraining(input?: Partial<Training>) {
+export function emptyTraining(input?: TTraining) {
   const emptyTraining: Partial<Training> = {
     id: randomID(),
     title: '',

Some files were not shown because too many files changed in this diff