Browse Source

Merge branch 'query_node_mappings' into sumer-new-substrate-update-apps

Mokhtar Naamani 3 years ago
parent
commit
c2b0c729d9
100 changed files with 19030 additions and 176 deletions
  1. 0 1
      .dockerignore
  2. 1 0
      build-npm-packages.sh
  3. 4 1
      docker-compose.yml
  4. 19 19
      pioneer/packages/joy-roles/src/elements.tsx
  5. 20 23
      pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx
  6. 36 11
      pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx
  7. 4 0
      pioneer/packages/joy-roles/src/transport.mock.ts
  8. 12 54
      pioneer/packages/joy-roles/src/transport.substrate.ts
  9. 1 0
      pioneer/packages/joy-roles/src/transport.ts
  10. 6 3
      pioneer/packages/joy-roles/src/working_groups.ts
  11. 2 1
      query-node/.gitignore
  12. 20 0
      query-node/README.md
  13. 5 3
      query-node/build.sh
  14. 21 0
      query-node/generated/graphql-server/.env
  15. 6 0
      query-node/generated/graphql-server/.gitignore
  16. 46 0
      query-node/generated/graphql-server/db/migrations/channelCategoriesByName.migration.ts
  17. 46 0
      query-node/generated/graphql-server/db/migrations/membersByHandle.migration.ts
  18. 73 0
      query-node/generated/graphql-server/db/migrations/search.migration.ts
  19. 46 0
      query-node/generated/graphql-server/db/migrations/videoCategoriesByName.migration.ts
  20. 42 0
      query-node/generated/graphql-server/env.yml
  21. 1987 0
      query-node/generated/graphql-server/generated/binding.ts
  22. 3801 0
      query-node/generated/graphql-server/generated/classes.ts
  23. 1 0
      query-node/generated/graphql-server/generated/index.ts
  24. 3 0
      query-node/generated/graphql-server/generated/ormconfig.ts
  25. 2053 0
      query-node/generated/graphql-server/generated/schema.graphql
  26. 47 0
      query-node/generated/graphql-server/model/index.ts
  27. 105 0
      query-node/generated/graphql-server/package.json
  28. 7 0
      query-node/generated/graphql-server/src/config.ts
  29. 45 0
      query-node/generated/graphql-server/src/index.ts
  30. 35 0
      query-node/generated/graphql-server/src/logger.ts
  31. 23 0
      query-node/generated/graphql-server/src/modules/channel-category/channel-category.model.ts
  32. 142 0
      query-node/generated/graphql-server/src/modules/channel-category/channel-category.resolver.ts
  33. 28 0
      query-node/generated/graphql-server/src/modules/channel-category/channel-category.service.ts
  34. 116 0
      query-node/generated/graphql-server/src/modules/channel/channel.model.ts
  35. 213 0
      query-node/generated/graphql-server/src/modules/channel/channel.resolver.ts
  36. 28 0
      query-node/generated/graphql-server/src/modules/channel/channel.service.ts
  37. 25 0
      query-node/generated/graphql-server/src/modules/curator-group/curator-group.model.ts
  38. 142 0
      query-node/generated/graphql-server/src/modules/curator-group/curator-group.resolver.ts
  39. 28 0
      query-node/generated/graphql-server/src/modules/curator-group/curator-group.service.ts
  40. 76 0
      query-node/generated/graphql-server/src/modules/data-object/data-object.model.ts
  41. 176 0
      query-node/generated/graphql-server/src/modules/data-object/data-object.resolver.ts
  42. 31 0
      query-node/generated/graphql-server/src/modules/data-object/data-object.service.ts
  43. 19 0
      query-node/generated/graphql-server/src/modules/enums/enums.ts
  44. 14 0
      query-node/generated/graphql-server/src/modules/featured-video/featured-video.model.ts
  45. 142 0
      query-node/generated/graphql-server/src/modules/featured-video/featured-video.resolver.ts
  46. 28 0
      query-node/generated/graphql-server/src/modules/featured-video/featured-video.service.ts
  47. 26 0
      query-node/generated/graphql-server/src/modules/language/language.model.ts
  48. 154 0
      query-node/generated/graphql-server/src/modules/language/language.resolver.ts
  49. 28 0
      query-node/generated/graphql-server/src/modules/language/language.service.ts
  50. 32 0
      query-node/generated/graphql-server/src/modules/license/license.model.ts
  51. 142 0
      query-node/generated/graphql-server/src/modules/license/license.resolver.ts
  52. 28 0
      query-node/generated/graphql-server/src/modules/license/license.service.ts
  53. 61 0
      query-node/generated/graphql-server/src/modules/membership/membership.model.ts
  54. 142 0
      query-node/generated/graphql-server/src/modules/membership/membership.resolver.ts
  55. 28 0
      query-node/generated/graphql-server/src/modules/membership/membership.service.ts
  56. 46 0
      query-node/generated/graphql-server/src/modules/queries/channelCategoriesByName.resolver.ts
  57. 170 0
      query-node/generated/graphql-server/src/modules/queries/channelCategoriesByName.service.ts
  58. 46 0
      query-node/generated/graphql-server/src/modules/queries/membersByHandle.resolver.ts
  59. 170 0
      query-node/generated/graphql-server/src/modules/queries/membersByHandle.service.ts
  60. 49 0
      query-node/generated/graphql-server/src/modules/queries/search.resolver.ts
  61. 175 0
      query-node/generated/graphql-server/src/modules/queries/search.service.ts
  62. 46 0
      query-node/generated/graphql-server/src/modules/queries/videoCategoriesByName.resolver.ts
  63. 170 0
      query-node/generated/graphql-server/src/modules/queries/videoCategoriesByName.service.ts
  64. 85 0
      query-node/generated/graphql-server/src/modules/variants/variants.model.ts
  65. 23 0
      query-node/generated/graphql-server/src/modules/video-category/video-category.model.ts
  66. 142 0
      query-node/generated/graphql-server/src/modules/video-category/video-category.resolver.ts
  67. 28 0
      query-node/generated/graphql-server/src/modules/video-category/video-category.service.ts
  68. 32 0
      query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model.ts
  69. 142 0
      query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.resolver.ts
  70. 28 0
      query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.service.ts
  71. 43 0
      query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.model.ts
  72. 154 0
      query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.resolver.ts
  73. 28 0
      query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.service.ts
  74. 141 0
      query-node/generated/graphql-server/src/modules/video/video.model.ts
  75. 225 0
      query-node/generated/graphql-server/src/modules/video/video.resolver.ts
  76. 28 0
      query-node/generated/graphql-server/src/modules/video/video.service.ts
  77. 38 0
      query-node/generated/graphql-server/src/processor.resolver.ts
  78. 52 0
      query-node/generated/graphql-server/src/pubsub.ts
  79. 53 0
      query-node/generated/graphql-server/src/server.ts
  80. 26 0
      query-node/generated/graphql-server/tsconfig.json
  81. 3 0
      query-node/generated/graphql-server/warthog.config.js
  82. 2477 0
      query-node/generated/types/content.ts
  83. 459 0
      query-node/generated/types/data-directory.ts
  84. 14 0
      query-node/generated/types/index.ts
  85. 616 0
      query-node/generated/types/members.ts
  86. 832 0
      query-node/generated/types/typedefs.json
  87. 161 29
      query-node/manifest.yml
  88. 0 1
      query-node/mappings/index.ts
  89. 0 26
      query-node/mappings/mappings.ts
  90. 10 4
      query-node/mappings/package.json
  91. 83 0
      query-node/mappings/src/common.ts
  92. 323 0
      query-node/mappings/src/content/channel.ts
  93. 126 0
      query-node/mappings/src/content/curatorGroup.ts
  94. 3 0
      query-node/mappings/src/content/index.ts
  95. 613 0
      query-node/mappings/src/content/utils.ts
  96. 394 0
      query-node/mappings/src/content/video.ts
  97. 6 0
      query-node/mappings/src/eventFix.ts
  98. 3 0
      query-node/mappings/src/index.ts
  99. 209 0
      query-node/mappings/src/membership.ts
  100. 192 0
      query-node/mappings/src/storage.ts

+ 0 - 1
.dockerignore

@@ -2,7 +2,6 @@ target/
 **node_modules*
 .tmp/
 .vscode/
-query-node/generated
 query-node/**/dist
 query-node/lib
 cli/

+ 1 - 0
build-npm-packages.sh

@@ -4,6 +4,7 @@ set -e
 
 yarn
 yarn workspace @joystream/types build
+yarn workspace @joystream/content-metadata-protobuf build
 yarn workspace query-node-root build
 # For now cli build is broken.. proceed anyway
 yarn workspace @joystream/cli build || :

+ 4 - 1
docker-compose.yml

@@ -92,13 +92,16 @@ services:
       # relative to working directory where docker-compose was run from
       - .env
     environment:
-      - INDEXER_ENDPOINT_URL=http://indexer-api-gateway:${WARTHOG_APP_PORT}/graphql
+      - INDEXER_ENDPOINT_URL=http://hydra-indexer-gateway:${WARTHOG_APP_PORT}/graphql
       - TYPEORM_HOST=db
       - TYPEORM_DATABASE=${DB_NAME}
       - DEBUG=index-builder:*
       - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
       - PROCESSOR_POLL_INTERVAL=1000 # refresh every second
+    volumes:
+      - ${TYPES_JSON}:/joystream/query-node/mappings/lib/generated/types/typedefs.json
     depends_on:
+      - graphql-server
       - hydra-indexer-gateway
     command: ["workspace", "query-node-root", "processor:start"]
 

+ 19 - 19
pioneer/packages/joy-roles/src/elements.tsx

@@ -1,6 +1,6 @@
 import React, { useEffect, useState } from 'react';
 import moment from 'moment';
-import { Card, Icon, Image, Label, Statistic, Button } from 'semantic-ui-react';
+import { Card, Icon, Image, Label, Statistic, Button, Transition } from 'semantic-ui-react';
 import { Link } from 'react-router-dom';
 
 import { Balance } from '@polkadot/types/interfaces';
@@ -8,7 +8,6 @@ import { formatBalance } from '@polkadot/util';
 import Identicon from '@polkadot/react-identicon';
 import { IMembership, MemberId } from '@joystream/types/members';
 import { GenericAccountId } from '@polkadot/types';
-import { WorkerId } from '@joystream/types/working-group';
 import { WorkingGroups } from './working_groups';
 import { RewardRelationship } from '@joystream/types/recurring-rewards';
 import { formatReward } from '@polkadot/joy-utils/functions/format';
@@ -49,26 +48,17 @@ export type GroupMember = {
   title: string;
   stake?: Balance;
   rewardRelationship?: RewardRelationship;
+  storage?: string;
 }
 
-export type GroupLead = {
-  memberId: MemberId;
-  workerId?: WorkerId; // In case of "working-group" module
-  roleAccount: GenericAccountId;
-  profile: IMembership;
-  title: string;
-  stake?: Balance;
-  rewardRelationship?: RewardRelationship;
-}
-
-export function GroupLeadView (props: GroupLead) {
+export function GroupLeadView (props: GroupMember) {
   let avatar = <Identicon value={props.roleAccount.toString()} size={50} />;
 
   if (typeof props.profile.avatar_uri !== 'undefined' && props.profile.avatar_uri.toString() !== '') {
     avatar = <Image src={props.profile.avatar_uri.toString()} circular className='avatar' />;
   }
 
-  const { stake, rewardRelationship } = props;
+  const { stake, rewardRelationship, storage } = props;
 
   return (
     <Card color='grey' className='staked-card'>
@@ -91,7 +81,7 @@ export function GroupLeadView (props: GroupLead) {
           </Label>
         </Card.Description>
       </Card.Content>
-      <GroupMemberDetails {...{ stake, rewardRelationship }} />
+      <GroupMemberDetails {...{ stake, rewardRelationship, storage }} />
     </Card>
   );
 }
@@ -106,6 +96,7 @@ const StakeAndReward = styled.div`
 type GroupMemberDetailsProps = {
   rewardRelationship?: RewardRelationship;
   stake?: Balance;
+  storage?: string
 }
 
 export function GroupMemberDetails (props: GroupMemberDetailsProps) {
@@ -150,15 +141,24 @@ export function GroupMemberDetails (props: GroupMemberDetailsProps) {
     );
   }
 
+  if (props.storage) {
+    details.push(
+      <Label>
+        Worker Storage
+        <Label.Detail style={{ marginTop: '5px', marginLeft: 0, display: 'block', wordBreak: 'break-word', wordWrap: 'break-word' }}>{props.storage}</Label.Detail>
+      </Label>
+    );
+  }
+
   return (
     <Card.Content extra>
-      { showDetails && (
+      <Transition visible={showDetails} animation='fade down' duration={500}>
         <Card.Description>
           <StakeAndReward>
             {details.map((detail, index) => <div key={index}>{detail}</div>)}
           </StakeAndReward>
         </Card.Description>
-      ) }
+      </Transition>
       <Button onClick={ () => setShowDetails((v) => !v) } size='tiny' fluid>
         { showDetails ? 'Hide' : 'Show'} details
       </Button>
@@ -173,7 +173,7 @@ export function GroupMemberView (props: GroupMember) {
     avatar = <Image src={props.profile.avatar_uri.toString()} circular className='avatar' />;
   }
 
-  const { stake, rewardRelationship } = props;
+  const { stake, rewardRelationship, storage } = props;
 
   return (
     <Card color='grey' className='staked-card'>
@@ -189,7 +189,7 @@ export function GroupMemberView (props: GroupMember) {
           </Label>
         </Card.Meta>
       </Card.Content>
-      <GroupMemberDetails {...{ stake, rewardRelationship }} />
+      <GroupMemberDetails {...{ stake, rewardRelationship, storage }} />
     </Card>
   );
 }

+ 20 - 23
pioneer/packages/joy-roles/src/tabs/WorkingGroup.controller.tsx

@@ -4,45 +4,41 @@ import { Controller } from '@polkadot/joy-utils/react/helpers';
 import { View } from '@polkadot/joy-utils/react/hocs';
 
 import { ITransport } from '../transport';
+import { AvailableGroups } from '../working_groups';
 
-import { ContentCurators,
-  WorkingGroupMembership,
-  StorageProviders } from './WorkingGroup';
+import { WorkingGroupMembership,
+  ContentCurators,
+  StorageProviders,
+  OperationsGroup } from './WorkingGroup';
 
 import styled from 'styled-components';
-import { normalizeError } from '@polkadot/joy-utils/functions/misc';
 
 type State = {
-  contentCurators?: WorkingGroupMembership;
+  curators?: WorkingGroupMembership;
   storageProviders?: WorkingGroupMembership;
+  operationsGroup?: WorkingGroupMembership;
 }
 
 export class WorkingGroupsController extends Controller<State, ITransport> {
-  constructor (transport: ITransport, initialState: State = {}) {
+  constructor (transport: ITransport) {
     super(transport, {});
   }
 
   refreshState () {
-    this.getCurationGroup();
-    this.getStorageGroup();
+    void this.getGroups();
   }
 
-  getCurationGroup () {
-    this.transport.curationGroup()
-      .then((value: WorkingGroupMembership) => {
-        this.setState({ contentCurators: value });
-        this.dispatch();
-      })
-      .catch((e) => this.onError(normalizeError(e)));
-  }
+  async getGroups () {
+    const newState: Partial<State> = {};
 
-  getStorageGroup () {
-    this.transport.storageGroup()
-      .then((value: WorkingGroupMembership) => {
-        this.setState({ storageProviders: value });
-        this.dispatch();
+    await Promise.all(
+      AvailableGroups.map(async (group) => {
+        newState[group] = await this.transport.groupOverview(group);
       })
-      .catch((e) => this.onError(normalizeError(e)));
+    );
+
+    this.setState(newState);
+    this.dispatch();
   }
 }
 
@@ -58,8 +54,9 @@ const WorkingGroupsOverview = styled.div`
 export const WorkingGroupsView = View<WorkingGroupsController, State>(
   ({ state }) => (
     <WorkingGroupsOverview>
-      <ContentCurators {...state.contentCurators}/>
+      <ContentCurators {...state.curators}/>
       <StorageProviders {...state.storageProviders}/>
+      <OperationsGroup {...state.operationsGroup}/>
     </WorkingGroupsOverview>
   )
 );

+ 36 - 11
pioneer/packages/joy-roles/src/tabs/WorkingGroup.tsx

@@ -1,8 +1,8 @@
-import React from 'react';
-import { Button, Card, Icon, Message, SemanticICONS } from 'semantic-ui-react';
+import React, { useState } from 'react';
+import { Button, Card, Icon, Message, SemanticICONS, Transition } from 'semantic-ui-react';
 import { Link } from 'react-router-dom';
 
-import { GroupLeadView, GroupMember, GroupMemberView, GroupLead } from '../elements';
+import { GroupLeadView, GroupMember, GroupMemberView } from '../elements';
 import { Loadable } from '@polkadot/joy-utils/react/hocs';
 
 import { WorkingGroups } from '../working_groups';
@@ -65,7 +65,7 @@ type GroupOverviewOuterProps = Partial<WorkingGroupMembership> & {
 
 type GroupOverviewProps = GroupOverviewOuterProps & {
   group: WorkingGroups;
-  description: string;
+  description: string | JSX.Element;
   customGroupName?: string;
   customJoinTitle?: string;
   customJoinDesc?: string;
@@ -93,20 +93,28 @@ const GroupOverview = Loadable<GroupOverviewProps>(
     const joinDesc = customJoinDesc || `There are openings for new ${groupName}. This is a great way to support Joystream!`;
     const becomeLeadTitle = customBecomeLeadTitle || `Become ${groupName} Lead!`;
     const becomeLeadDesc = customBecomeLeadDesc || `An opportunity to become ${groupName} Leader is currently available! This is a great way to support Joystream!`;
+    const [showMembers, setShowMembers] = useState(false);
 
     return (
       <GroupOverviewSection>
         <h2>{ groupName }</h2>
         <p>{ description }</p>
-        <Card.Group style={{ alignItems: 'flex-start' }}>
-          { workers!.map((worker, key) => (
-            <GroupMemberView key={key} {...worker} />
-          )) }
-        </Card.Group>
+        <Button onClick={() => setShowMembers((v) => !v)}>
+          { showMembers ? 'Hide' : 'Show' } members
+        </Button>
+        <Transition visible={showMembers} animation='fade down' duration={500}>
+          <span>
+            <Card.Group style={{ alignItems: 'flex-start' }}>
+              { workers!.map((worker, key) => (
+                <GroupMemberView key={key} {...worker} />
+              )) }
+            </Card.Group>
+            { leadStatus && <CurrentLead groupName={groupName} {...leadStatus}/> }
+          </span>
+        </Transition>
         { workerRolesAvailable
           ? <JoinRole group={group} title={joinTitle} description={joinDesc} />
           : <NoRolesAvailable /> }
-        { leadStatus && <CurrentLead groupName={groupName} {...leadStatus}/> }
         { leadRolesAvailable && <JoinRole group={group} lead title={becomeLeadTitle} description={becomeLeadDesc} /> }
       </GroupOverviewSection>
     );
@@ -134,12 +142,29 @@ export const StorageProviders = (props: GroupOverviewOuterProps) => (
   />
 );
 
+export const OperationsGroup = (props: GroupOverviewOuterProps) => (
+  <GroupOverview
+    group={WorkingGroups.Operations}
+    description={
+      <span>
+        {"Operations Working Group encompases all the activites that don't require privilages on chain, for example:"}
+        <ul>
+          <li>Development</li>
+          <li>Management</li>
+          <li>Marketing</li>
+        </ul>
+      </span>
+    }
+    {...props}
+  />
+);
+
 const LeadSection = styled.div`
   margin-top: 1rem;
 `;
 
 export type GroupLeadStatus = {
-  lead?: GroupLead;
+  lead?: GroupMember;
   loaded: boolean;
 }
 

+ 4 - 0
pioneer/packages/joy-roles/src/transport.mock.ts

@@ -117,6 +117,10 @@ export class Transport extends MockTransportBase implements ITransport {
     });
   }
 
+  groupOverview (group: WorkingGroups): Promise<WorkingGroupMembership> {
+    return this.storageGroup();
+  }
+
   currentOpportunities (): Promise<Array<WorkingGroupOpening>> {
     return this.simulateApiResponse<Array<WorkingGroupOpening>>(
       [

+ 12 - 54
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -49,15 +49,10 @@ type StakePair<T = Balance> = {
   role: T;
 }
 
-type GroupLeadWithMemberId = {
-  lead: Worker;
-  memberId: MemberId;
-  workerId: WorkerId;
-}
-
 const apiModuleByGroup = {
   [WorkingGroups.StorageProviders]: 'storageWorkingGroup',
-  [WorkingGroups.ContentCurators]: 'contentDirectoryWorkingGroup'
+  [WorkingGroups.ContentCurators]: 'contentDirectoryWorkingGroup',
+  [WorkingGroups.Operations]: 'operationsWorkingGroup'
 } as const;
 
 export class Transport extends BaseTransport implements ITransport {
@@ -142,6 +137,8 @@ export class Transport extends BaseTransport implements ITransport {
 
     const rewardRelationship = await this.workerRewardRelationship(worker);
 
+    const storage = await this.queryCachedByGroup(group).workerStorage(id);
+
     return ({
       roleAccount,
       group,
@@ -150,7 +147,8 @@ export class Transport extends BaseTransport implements ITransport {
       profile,
       title: workerRoleNameByGroup[group],
       stake: stakeValue,
-      rewardRelationship
+      rewardRelationship,
+      storage: this.api.createType('Text', storage).toString()
     });
   }
 
@@ -177,55 +175,15 @@ export class Transport extends BaseTransport implements ITransport {
     return false;
   }
 
-  protected async groupLead (group: WorkingGroups): Promise <GroupLeadWithMemberId | null> {
-    const optLeadId = (await this.queryCachedByGroup(group).currentLead()) as Option<WorkerId>;
-
-    if (!optLeadId.isSome) {
-      return null;
-    }
-
-    const leadWorkerId = optLeadId.unwrap();
-    const leadWorker = await this.queryCachedByGroup(group).workerById(leadWorkerId) as Worker;
-
-    if (leadWorker.isEmpty) {
-      return null;
-    }
-
-    return {
-      lead: leadWorker,
-      memberId: leadWorker.member_id,
-      workerId: leadWorkerId
-    };
-  }
-
   async groupLeadStatus (group: WorkingGroups = WorkingGroups.ContentCurators): Promise<GroupLeadStatus> {
-    const currentLead = await this.groupLead(group);
-
-    if (currentLead !== null) {
-      const profile = await this.cacheApi.query.members.membershipById(currentLead.memberId) as Membership;
-
-      if (profile.handle.isEmpty) {
-        throw new Error(`${group} lead profile not found!`);
-      }
+    const optLeadId = await this.queryCachedByGroup(group).currentLead() as Option<WorkerId>;
 
-      const rewardRelationshipId = currentLead.lead.reward_relationship;
-      const rewardRelationship = rewardRelationshipId.isSome
-        ? await this.rewardRelationshipById(rewardRelationshipId.unwrap())
-        : undefined;
-      const stake = currentLead.lead.role_stake_profile.isSome
-        ? await this.workerStake(currentLead.lead.role_stake_profile.unwrap())
-        : undefined;
+    if (optLeadId.isSome) {
+      const leadId = optLeadId.unwrap();
+      const leadWorker = await this.queryCachedByGroup(group).workerById(leadId) as Worker;
 
       return {
-        lead: {
-          memberId: currentLead.memberId,
-          workerId: currentLead.workerId,
-          roleAccount: currentLead.lead.role_account_id,
-          profile,
-          title: _.startCase(group) + ' Lead',
-          stake,
-          rewardRelationship
-        },
+        lead: await this.groupMember(group, leadId, leadWorker),
         loaded: true
       };
     } else {
@@ -540,7 +498,7 @@ export class Transport extends BaseTransport implements ITransport {
 
           return {
             workerId: id,
-            name: (groupLead?.workerId && groupLead.workerId.eq(id))
+            name: (groupLead?.workerId && groupLead.workerId === id.toNumber())
               ? _.startCase(group) + ' Lead'
               : workerRoleNameByGroup[group],
             reward: earnedValue,

+ 1 - 0
pioneer/packages/joy-roles/src/transport.ts

@@ -9,6 +9,7 @@ import { WorkingGroups } from './working_groups';
 
 export interface ITransport {
   groupLeadStatus: (group: WorkingGroups) => Promise<GroupLeadStatus>;
+  groupOverview: (group: WorkingGroups) => Promise<WorkingGroupMembership>;
   curationGroup: () => Promise<WorkingGroupMembership>;
   storageGroup: () => Promise<WorkingGroupMembership>;
   currentOpportunities: () => Promise<Array<WorkingGroupOpening>>;

+ 6 - 3
pioneer/packages/joy-roles/src/working_groups.ts

@@ -1,14 +1,17 @@
 export enum WorkingGroups {
   ContentCurators = 'curators',
-  StorageProviders = 'storageProviders'
+  StorageProviders = 'storageProviders',
+  Operations = 'operationsGroup'
 }
 
 export const AvailableGroups: readonly WorkingGroups[] = [
   WorkingGroups.ContentCurators,
-  WorkingGroups.StorageProviders
+  WorkingGroups.StorageProviders,
+  WorkingGroups.Operations
 ] as const;
 
 export const workerRoleNameByGroup: { [key in WorkingGroups]: string } = {
   [WorkingGroups.ContentCurators]: 'Content Curator',
-  [WorkingGroups.StorageProviders]: 'Storage Provider'
+  [WorkingGroups.StorageProviders]: 'Storage Provider',
+  [WorkingGroups.Operations]: 'Operations Group Worker'
 };

+ 2 - 1
query-node/.gitignore

@@ -1,2 +1,3 @@
 lib
-generated
+dist
+.env

+ 20 - 0
query-node/README.md

@@ -59,3 +59,23 @@ The simplest way to run an indexer locally is to run `docker-compose-indexer.yml
 - If non-standard types are being used by the Substrate runtime, map type definitions in the json format as an external volume
 
 Follow the links for more information about the [indexer](https://github.com/Joystream/hydra/tree/master/packages/hydra-indexer/README.md) service and [indexer-api-gateway](https://github.com/Joystream/hydra/tree/master/packages/hydra-indexer-gateway/README.md).
+
+
+
+# Tmp command order
+TODO: remove after integration tests are finished and query node runs without any issues
+```
+# build everything
+yarn
+yarn build
+
+```
+
+running the processor:
+```
+cp types/augment/all/defs.json query-node/mappings/lib/generated/types/typedefs.json
+docker-compose up -d db
+yarn workspace query-node-root db:create
+yarn workspace query-node-root db:migrate
+
+```

+ 5 - 3
query-node/build.sh

@@ -9,10 +9,12 @@ set -a
 . ../.env
 set +a
 
-yarn clean
-
-yarn codegen:noinstall
+# only use this when new Hydra releases and contents of `generated/` folder needs to be refreshed
+#yarn clean
+#yarn codegen:noinstall
+#yarn codegen:typegen # if this fails try to run this command outside of yarn workspaces
 
+yarn query-node:build
 yarn mappings:build
 
 # We run yarn again to ensure graphql-server dependencies are installed

+ 21 - 0
query-node/generated/graphql-server/.env

@@ -0,0 +1,21 @@
+WARTHOG_INTROSPECTION=true
+WARTHOG_SUBSCRIPTIONS=true
+WARTHOG_PLAYGROUND=true
+WARTHOG_DB_SYNCHRONIZE=false
+WARTHOG_DB_OVERRIDE=false
+WARTHOG_DB_DATABASE=query_node_processor
+WARTHOG_DB_USERNAME=postgres
+WARTHOG_DB_PASSWORD=postgres
+WARTHOG_DB_HOST=localhost
+WARTHOG_DB_PORT=5432
+WARTHOG_APP_PORT=4002
+WARTHOG_APP_HOST=localhost
+GRAPHQL_SERVER_PORT=4002
+GRAPHQL_SERVER_HOST=localhost
+PGDATABASE=query_node_processor
+PGUSER=postgres
+PGPASSWORD=postgres
+PGHOST=localhost
+PGPORT=5432
+DEBUG=qnode-cli:*
+NODE_ENV=development

+ 6 - 0
query-node/generated/graphql-server/.gitignore

@@ -0,0 +1,6 @@
+# Dependencies
+node_modules
+
+# OS metadata
+.DS_Store
+Thumbs.db

+ 46 - 0
query-node/generated/graphql-server/db/migrations/channelCategoriesByName.migration.ts

@@ -0,0 +1,46 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class ChannelCategoriesByNameMigration1617981663820 implements MigrationInterface {
+    name = 'channelCategoriesByNameMigration1617981663820'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        // TODO: escape 
+        await queryRunner.query(`
+            ALTER TABLE channel_category 
+            ADD COLUMN channel_categories_by_name_tsv tsvector 
+            GENERATED ALWAYS AS (  
+                    setweight(to_tsvector('english', coalesce("name", '')), 'A') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`
+            ALTER TABLE channel_category 
+            ADD COLUMN channel_categories_by_name_doc text 
+            GENERATED ALWAYS AS (  
+                    coalesce("name", '') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`CREATE INDEX channel_categories_by_name_channel_category_idx ON channel_category USING GIN (channel_categories_by_name_tsv)`);
+        await queryRunner.query(`CREATE INDEX channel_category_id_idx ON channel_category (('channel_category' || '_' || id))`);
+
+        await queryRunner.query(`
+            CREATE VIEW channel_categories_by_name_view AS
+            SELECT 
+                text 'channel_category' AS origin_table, 'channel_category' || '_' || id AS unique_id, id, channel_categories_by_name_tsv AS tsv, channel_categories_by_name_doc AS document 
+            FROM
+                channel_category
+        `);
+
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`DROP VIEW channel_categories_by_name_view`);
+        await queryRunner.query(`DROP INDEX channel_categories_by_name_channel_category_idx`);
+        await queryRunner.query(`DROP INDEX channel_category_id_idx`);
+        await queryRunner.query(`ALTER TABLE channel_category DROP COLUMN channel_categories_by_name_tsv`);
+        await queryRunner.query(`ALTER TABLE channel_category DROP COLUMN channel_categories_by_name_doc`);
+    }
+
+
+}

+ 46 - 0
query-node/generated/graphql-server/db/migrations/membersByHandle.migration.ts

@@ -0,0 +1,46 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class MembersByHandleMigration1617981663821 implements MigrationInterface {
+    name = 'membersByHandleMigration1617981663821'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        // TODO: escape 
+        await queryRunner.query(`
+            ALTER TABLE membership 
+            ADD COLUMN members_by_handle_tsv tsvector 
+            GENERATED ALWAYS AS (  
+                    setweight(to_tsvector('english', coalesce("handle", '')), 'A') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`
+            ALTER TABLE membership 
+            ADD COLUMN members_by_handle_doc text 
+            GENERATED ALWAYS AS (  
+                    coalesce("handle", '') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`CREATE INDEX members_by_handle_membership_idx ON membership USING GIN (members_by_handle_tsv)`);
+        await queryRunner.query(`CREATE INDEX membership_id_idx ON membership (('membership' || '_' || id))`);
+
+        await queryRunner.query(`
+            CREATE VIEW members_by_handle_view AS
+            SELECT 
+                text 'membership' AS origin_table, 'membership' || '_' || id AS unique_id, id, members_by_handle_tsv AS tsv, members_by_handle_doc AS document 
+            FROM
+                membership
+        `);
+
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`DROP VIEW members_by_handle_view`);
+        await queryRunner.query(`DROP INDEX members_by_handle_membership_idx`);
+        await queryRunner.query(`DROP INDEX membership_id_idx`);
+        await queryRunner.query(`ALTER TABLE membership DROP COLUMN members_by_handle_tsv`);
+        await queryRunner.query(`ALTER TABLE membership DROP COLUMN members_by_handle_doc`);
+    }
+
+
+}

+ 73 - 0
query-node/generated/graphql-server/db/migrations/search.migration.ts

@@ -0,0 +1,73 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class SearchMigration1617981663819 implements MigrationInterface {
+    name = 'searchMigration1617981663819'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        // TODO: escape 
+        await queryRunner.query(`
+            ALTER TABLE channel 
+            ADD COLUMN search_tsv tsvector 
+            GENERATED ALWAYS AS (  
+                    setweight(to_tsvector('english', coalesce("title", '')), 'A') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`
+            ALTER TABLE channel 
+            ADD COLUMN search_doc text 
+            GENERATED ALWAYS AS (  
+                    coalesce("title", '') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`CREATE INDEX search_channel_idx ON channel USING GIN (search_tsv)`);
+        await queryRunner.query(`CREATE INDEX channel_id_idx ON channel (('channel' || '_' || id))`);
+        await queryRunner.query(`
+            ALTER TABLE video 
+            ADD COLUMN search_tsv tsvector 
+            GENERATED ALWAYS AS (  
+                    setweight(to_tsvector('english', coalesce("title", '')), 'A') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`
+            ALTER TABLE video 
+            ADD COLUMN search_doc text 
+            GENERATED ALWAYS AS (  
+                    coalesce("title", '') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`CREATE INDEX search_video_idx ON video USING GIN (search_tsv)`);
+        await queryRunner.query(`CREATE INDEX video_id_idx ON video (('video' || '_' || id))`);
+
+        await queryRunner.query(`
+            CREATE VIEW search_view AS
+            SELECT 
+                text 'channel' AS origin_table, 'channel' || '_' || id AS unique_id, id, search_tsv AS tsv, search_doc AS document 
+            FROM
+                channel
+            UNION ALL
+            SELECT 
+                text 'video' AS origin_table, 'video' || '_' || id AS unique_id, id, search_tsv AS tsv, search_doc AS document 
+            FROM
+                video
+        `);
+
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`DROP VIEW search_view`);
+        await queryRunner.query(`DROP INDEX search_channel_idx`);
+        await queryRunner.query(`DROP INDEX channel_id_idx`);
+        await queryRunner.query(`ALTER TABLE channel DROP COLUMN search_tsv`);
+        await queryRunner.query(`ALTER TABLE channel DROP COLUMN search_doc`);
+        await queryRunner.query(`DROP INDEX search_video_idx`);
+        await queryRunner.query(`DROP INDEX video_id_idx`);
+        await queryRunner.query(`ALTER TABLE video DROP COLUMN search_tsv`);
+        await queryRunner.query(`ALTER TABLE video DROP COLUMN search_doc`);
+    }
+
+
+}

+ 46 - 0
query-node/generated/graphql-server/db/migrations/videoCategoriesByName.migration.ts

@@ -0,0 +1,46 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class VideoCategoriesByNameMigration1617981663821 implements MigrationInterface {
+    name = 'videoCategoriesByNameMigration1617981663821'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        // TODO: escape 
+        await queryRunner.query(`
+            ALTER TABLE video_category 
+            ADD COLUMN video_categories_by_name_tsv tsvector 
+            GENERATED ALWAYS AS (  
+                    setweight(to_tsvector('english', coalesce("name", '')), 'A') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`
+            ALTER TABLE video_category 
+            ADD COLUMN video_categories_by_name_doc text 
+            GENERATED ALWAYS AS (  
+                    coalesce("name", '') 
+                ) 
+            STORED;
+        `);
+        await queryRunner.query(`CREATE INDEX video_categories_by_name_video_category_idx ON video_category USING GIN (video_categories_by_name_tsv)`);
+        await queryRunner.query(`CREATE INDEX video_category_id_idx ON video_category (('video_category' || '_' || id))`);
+
+        await queryRunner.query(`
+            CREATE VIEW video_categories_by_name_view AS
+            SELECT 
+                text 'video_category' AS origin_table, 'video_category' || '_' || id AS unique_id, id, video_categories_by_name_tsv AS tsv, video_categories_by_name_doc AS document 
+            FROM
+                video_category
+        `);
+
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`DROP VIEW video_categories_by_name_view`);
+        await queryRunner.query(`DROP INDEX video_categories_by_name_video_category_idx`);
+        await queryRunner.query(`DROP INDEX video_category_id_idx`);
+        await queryRunner.query(`ALTER TABLE video_category DROP COLUMN video_categories_by_name_tsv`);
+        await queryRunner.query(`ALTER TABLE video_category DROP COLUMN video_categories_by_name_doc`);
+    }
+
+
+}

+ 42 - 0
query-node/generated/graphql-server/env.yml

@@ -0,0 +1,42 @@
+default_env: &default_env
+    WARTHOG_INTROSPECTION: true
+    WARTHOG_SUBSCRIPTIONS: true
+    WARTHOG_PLAYGROUND: true
+    WARTHOG_DB_SYNCHRONIZE: false  
+    ## if the DB is synced, the new columns 
+    ## created by migrations are dropped, no good
+    ## one should run `WARTHOG_DB_SYNCHRONIZE=true yarn sync` manually instead
+    WARTHOG_DB_OVERRIDE: false
+    WARTHOG_DB_DATABASE: ${env:DB_NAME}
+    WARTHOG_DB_USERNAME: ${env:DB_USER}
+    WARTHOG_DB_PASSWORD: ${env:DB_PASS}
+    WARTHOG_DB_HOST: ${env:DB_HOST}
+    WARTHOG_DB_PORT: ${env:DB_PORT}
+    WARTHOG_APP_PORT: ${env:GRAPHQL_SERVER_PORT}
+    WARTHOG_APP_HOST: ${env:GRAPHQL_SERVER_HOST}
+    GRAPHQL_SERVER_PORT: ${env:GRAPHQL_SERVER_PORT}
+    GRAPHQL_SERVER_HOST: ${env:GRAPHQL_SERVER_HOST}
+    
+    PGDATABASE: ${env:DB_NAME}
+    PGUSER: ${env:DB_USER}
+    PGPASSWORD: ${env:DB_PASS}
+    PGHOST: ${env:DB_HOST}
+    PGPORT: ${env:DB_PORT}
+
+development:
+    <<: *default_env
+    DEBUG: 'qnode-cli:*'
+    NODE_ENV: development
+
+staging:
+    <<: *default_env
+
+production:
+    NODE_ENV: production
+    WARTHOG_DB_ENTITIES: dist/src/**/*.model.js  
+    WARTHOG_DB_SUBSCRIBERS: dist/src/**/*.model.js
+    WARTHOG_RESOLVERS_PATH: dist/src/**/*.resolver.js
+    WARTHOG_DB_MIGRATIONS: dist/db/migrations/**/*.js
+    DEBUG: 'qnode-cli:*'
+    <<: *default_env
+  

+ 1987 - 0
query-node/generated/graphql-server/generated/binding.ts

@@ -0,0 +1,1987 @@
+import 'graphql-import-node'; // Needed so you can import *.graphql files 
+
+import { makeBindingClass, Options } from 'graphql-binding'
+import { GraphQLResolveInfo, GraphQLSchema } from 'graphql'
+import { IResolvers } from 'graphql-tools/dist/Interfaces'
+import * as schema from  './schema.graphql'
+
+export interface Query {
+    channelCategories: <T = Array<ChannelCategory>>(args: { offset?: Int | null, limit?: Int | null, where?: ChannelCategoryWhereInput | null, orderBy?: ChannelCategoryOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    channelCategoryByUniqueInput: <T = ChannelCategory | null>(args: { where: ChannelCategoryWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    channelCategoriesConnection: <T = ChannelCategoryConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: ChannelCategoryWhereInput | null, orderBy?: ChannelCategoryOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    channels: <T = Array<Channel>>(args: { offset?: Int | null, limit?: Int | null, where?: ChannelWhereInput | null, orderBy?: ChannelOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    channelByUniqueInput: <T = Channel | null>(args: { where: ChannelWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    channelsConnection: <T = ChannelConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: ChannelWhereInput | null, orderBy?: ChannelOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    curatorGroups: <T = Array<CuratorGroup>>(args: { offset?: Int | null, limit?: Int | null, where?: CuratorGroupWhereInput | null, orderBy?: CuratorGroupOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    curatorGroupByUniqueInput: <T = CuratorGroup | null>(args: { where: CuratorGroupWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    curatorGroupsConnection: <T = CuratorGroupConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: CuratorGroupWhereInput | null, orderBy?: CuratorGroupOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    dataObjects: <T = Array<DataObject>>(args: { offset?: Int | null, limit?: Int | null, where?: DataObjectWhereInput | null, orderBy?: DataObjectOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    dataObjectByUniqueInput: <T = DataObject | null>(args: { where: DataObjectWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    dataObjectsConnection: <T = DataObjectConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: DataObjectWhereInput | null, orderBy?: DataObjectOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    featuredVideos: <T = Array<FeaturedVideo>>(args: { offset?: Int | null, limit?: Int | null, where?: FeaturedVideoWhereInput | null, orderBy?: FeaturedVideoOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    featuredVideoByUniqueInput: <T = FeaturedVideo | null>(args: { where: FeaturedVideoWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    featuredVideosConnection: <T = FeaturedVideoConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: FeaturedVideoWhereInput | null, orderBy?: FeaturedVideoOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    languages: <T = Array<Language>>(args: { offset?: Int | null, limit?: Int | null, where?: LanguageWhereInput | null, orderBy?: LanguageOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    languageByUniqueInput: <T = Language | null>(args: { where: LanguageWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    languagesConnection: <T = LanguageConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: LanguageWhereInput | null, orderBy?: LanguageOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    licenses: <T = Array<License>>(args: { offset?: Int | null, limit?: Int | null, where?: LicenseWhereInput | null, orderBy?: LicenseOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    licenseByUniqueInput: <T = License | null>(args: { where: LicenseWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    licensesConnection: <T = LicenseConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: LicenseWhereInput | null, orderBy?: LicenseOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    memberships: <T = Array<Membership>>(args: { offset?: Int | null, limit?: Int | null, where?: MembershipWhereInput | null, orderBy?: MembershipOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    membershipByUniqueInput: <T = Membership | null>(args: { where: MembershipWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    membershipsConnection: <T = MembershipConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: MembershipWhereInput | null, orderBy?: MembershipOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    channelCategoriesByName: <T = Array<ChannelCategoriesByNameFTSOutput>>(args: { whereChannelCategory?: ChannelCategoryWhereInput | null, skip?: Int | null, limit?: Int | null, text: String }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    membersByHandle: <T = Array<MembersByHandleFTSOutput>>(args: { whereMembership?: MembershipWhereInput | null, skip?: Int | null, limit?: Int | null, text: String }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    search: <T = Array<SearchFTSOutput>>(args: { whereVideo?: VideoWhereInput | null, whereChannel?: ChannelWhereInput | null, skip?: Int | null, limit?: Int | null, text: String }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoCategoriesByName: <T = Array<VideoCategoriesByNameFTSOutput>>(args: { whereVideoCategory?: VideoCategoryWhereInput | null, skip?: Int | null, limit?: Int | null, text: String }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoCategories: <T = Array<VideoCategory>>(args: { offset?: Int | null, limit?: Int | null, where?: VideoCategoryWhereInput | null, orderBy?: VideoCategoryOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoCategoryByUniqueInput: <T = VideoCategory | null>(args: { where: VideoCategoryWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    videoCategoriesConnection: <T = VideoCategoryConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: VideoCategoryWhereInput | null, orderBy?: VideoCategoryOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoMediaEncodings: <T = Array<VideoMediaEncoding>>(args: { offset?: Int | null, limit?: Int | null, where?: VideoMediaEncodingWhereInput | null, orderBy?: VideoMediaEncodingOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoMediaEncodingByUniqueInput: <T = VideoMediaEncoding | null>(args: { where: VideoMediaEncodingWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    videoMediaEncodingsConnection: <T = VideoMediaEncodingConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: VideoMediaEncodingWhereInput | null, orderBy?: VideoMediaEncodingOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoMediaMetadata: <T = Array<VideoMediaMetadata>>(args: { offset?: Int | null, limit?: Int | null, where?: VideoMediaMetadataWhereInput | null, orderBy?: VideoMediaMetadataOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoMediaMetadataByUniqueInput: <T = VideoMediaMetadata | null>(args: { where: VideoMediaMetadataWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    videoMediaMetadataConnection: <T = VideoMediaMetadataConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: VideoMediaMetadataWhereInput | null, orderBy?: VideoMediaMetadataOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videos: <T = Array<Video>>(args: { offset?: Int | null, limit?: Int | null, where?: VideoWhereInput | null, orderBy?: VideoOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> ,
+    videoByUniqueInput: <T = Video | null>(args: { where: VideoWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T | null> ,
+    videosConnection: <T = VideoConnection>(args: { first?: Int | null, after?: String | null, last?: Int | null, before?: String | null, where?: VideoWhereInput | null, orderBy?: VideoOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise<T> 
+  }
+
+export interface Mutation {}
+
+export interface Subscription {
+    stateSubscription: <T = ProcessorState>(args?: {}, info?: GraphQLResolveInfo | string, options?: Options) => Promise<AsyncIterator<T>> 
+  }
+
+export interface Binding {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+  request: <T = any>(query: string, variables?: {[key: string]: any}) => Promise<T>
+  delegate(operation: 'query' | 'mutation', fieldName: string, args: {
+      [key: string]: any;
+  }, infoOrQuery?: GraphQLResolveInfo | string, options?: Options): Promise<any>;
+  delegateSubscription(fieldName: string, args?: {
+      [key: string]: any;
+  }, infoOrQuery?: GraphQLResolveInfo | string, options?: Options): Promise<AsyncIterator<any>>;
+  getAbstractResolvers(filterSchema?: GraphQLSchema | string): IResolvers;
+}
+
+export interface BindingConstructor<T> {
+  new(...args: any[]): T
+}
+
+export const Binding = makeBindingClass<BindingConstructor<Binding>>({ schema: schema as any })
+
+/**
+ * Types
+*/
+
+export type AssetAvailability =   'ACCEPTED' |
+  'PENDING' |
+  'INVALID'
+
+export type ChannelCategoryOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'name_ASC' |
+  'name_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC'
+
+export type ChannelOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'ownerMemberId_ASC' |
+  'ownerMemberId_DESC' |
+  'ownerCuratorGroupId_ASC' |
+  'ownerCuratorGroupId_DESC' |
+  'categoryId_ASC' |
+  'categoryId_DESC' |
+  'rewardAccount_ASC' |
+  'rewardAccount_DESC' |
+  'title_ASC' |
+  'title_DESC' |
+  'description_ASC' |
+  'description_DESC' |
+  'coverPhotoDataObjectId_ASC' |
+  'coverPhotoDataObjectId_DESC' |
+  'coverPhotoAvailability_ASC' |
+  'coverPhotoAvailability_DESC' |
+  'avatarPhotoDataObjectId_ASC' |
+  'avatarPhotoDataObjectId_DESC' |
+  'avatarPhotoAvailability_ASC' |
+  'avatarPhotoAvailability_DESC' |
+  'isPublic_ASC' |
+  'isPublic_DESC' |
+  'isCensored_ASC' |
+  'isCensored_DESC' |
+  'languageId_ASC' |
+  'languageId_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC'
+
+export type CuratorGroupOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'isActive_ASC' |
+  'isActive_DESC'
+
+export type DataObjectOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'addedAt_ASC' |
+  'addedAt_DESC' |
+  'typeId_ASC' |
+  'typeId_DESC' |
+  'size_ASC' |
+  'size_DESC' |
+  'liaisonId_ASC' |
+  'liaisonId_DESC' |
+  'liaisonJudgement_ASC' |
+  'liaisonJudgement_DESC' |
+  'ipfsContentId_ASC' |
+  'ipfsContentId_DESC' |
+  'joystreamContentId_ASC' |
+  'joystreamContentId_DESC'
+
+export type FeaturedVideoOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'videoId_ASC' |
+  'videoId_DESC'
+
+export type LanguageOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'iso_ASC' |
+  'iso_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC'
+
+export type LiaisonJudgement =   'PENDING' |
+  'ACCEPTED' |
+  'REJECTED'
+
+export type LicenseOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'code_ASC' |
+  'code_DESC' |
+  'attribution_ASC' |
+  'attribution_DESC' |
+  'customText_ASC' |
+  'customText_DESC'
+
+export type MembershipEntryMethod =   'PAID' |
+  'SCREENING' |
+  'GENESIS'
+
+export type MembershipOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'handle_ASC' |
+  'handle_DESC' |
+  'avatarUri_ASC' |
+  'avatarUri_DESC' |
+  'about_ASC' |
+  'about_DESC' |
+  'controllerAccount_ASC' |
+  'controllerAccount_DESC' |
+  'rootAccount_ASC' |
+  'rootAccount_DESC' |
+  'registeredAtBlock_ASC' |
+  'registeredAtBlock_DESC' |
+  'registeredAtTime_ASC' |
+  'registeredAtTime_DESC' |
+  'entry_ASC' |
+  'entry_DESC' |
+  'subscription_ASC' |
+  'subscription_DESC'
+
+export type VideoCategoryOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'name_ASC' |
+  'name_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC'
+
+export type VideoMediaEncodingOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'codecName_ASC' |
+  'codecName_DESC' |
+  'container_ASC' |
+  'container_DESC' |
+  'mimeMediaType_ASC' |
+  'mimeMediaType_DESC'
+
+export type VideoMediaMetadataOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'encodingId_ASC' |
+  'encodingId_DESC' |
+  'pixelWidth_ASC' |
+  'pixelWidth_DESC' |
+  'pixelHeight_ASC' |
+  'pixelHeight_DESC' |
+  'size_ASC' |
+  'size_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC'
+
+export type VideoOrderByInput =   'createdAt_ASC' |
+  'createdAt_DESC' |
+  'updatedAt_ASC' |
+  'updatedAt_DESC' |
+  'deletedAt_ASC' |
+  'deletedAt_DESC' |
+  'channelId_ASC' |
+  'channelId_DESC' |
+  'categoryId_ASC' |
+  'categoryId_DESC' |
+  'title_ASC' |
+  'title_DESC' |
+  'description_ASC' |
+  'description_DESC' |
+  'duration_ASC' |
+  'duration_DESC' |
+  'thumbnailPhotoDataObjectId_ASC' |
+  'thumbnailPhotoDataObjectId_DESC' |
+  'thumbnailPhotoAvailability_ASC' |
+  'thumbnailPhotoAvailability_DESC' |
+  'languageId_ASC' |
+  'languageId_DESC' |
+  'hasMarketing_ASC' |
+  'hasMarketing_DESC' |
+  'publishedBeforeJoystream_ASC' |
+  'publishedBeforeJoystream_DESC' |
+  'isPublic_ASC' |
+  'isPublic_DESC' |
+  'isCensored_ASC' |
+  'isCensored_DESC' |
+  'isExplicit_ASC' |
+  'isExplicit_DESC' |
+  'licenseId_ASC' |
+  'licenseId_DESC' |
+  'mediaDataObjectId_ASC' |
+  'mediaDataObjectId_DESC' |
+  'mediaAvailability_ASC' |
+  'mediaAvailability_DESC' |
+  'mediaMetadataId_ASC' |
+  'mediaMetadataId_DESC' |
+  'happenedIn_ASC' |
+  'happenedIn_DESC' |
+  'isFeatured_ASC' |
+  'isFeatured_DESC'
+
+export interface BaseWhereInput {
+  id_eq?: String | null
+  id_in?: String[] | String | null
+  createdAt_eq?: String | null
+  createdAt_lt?: String | null
+  createdAt_lte?: String | null
+  createdAt_gt?: String | null
+  createdAt_gte?: String | null
+  createdById_eq?: String | null
+  updatedAt_eq?: String | null
+  updatedAt_lt?: String | null
+  updatedAt_lte?: String | null
+  updatedAt_gt?: String | null
+  updatedAt_gte?: String | null
+  updatedById_eq?: String | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: String | null
+  deletedAt_lt?: String | null
+  deletedAt_lte?: String | null
+  deletedAt_gt?: String | null
+  deletedAt_gte?: String | null
+  deletedById_eq?: String | null
+}
+
+export interface ChannelCategoryCreateInput {
+  name?: String | null
+  happenedIn: Float
+}
+
+export interface ChannelCategoryUpdateInput {
+  name?: String | null
+  happenedIn?: Float | null
+}
+
+export interface ChannelCategoryWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  name_eq?: String | null
+  name_contains?: String | null
+  name_startsWith?: String | null
+  name_endsWith?: String | null
+  name_in?: String[] | String | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+}
+
+export interface ChannelCategoryWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface ChannelCreateInput {
+  ownerMemberId?: ID_Input | null
+  ownerCuratorGroupId?: ID_Input | null
+  categoryId?: ID_Input | null
+  rewardAccount?: String | null
+  title?: String | null
+  description?: String | null
+  coverPhotoDataObjectId?: ID_Input | null
+  coverPhotoUrls: Array<String>
+  coverPhotoAvailability: AssetAvailability
+  avatarPhotoDataObjectId?: ID_Input | null
+  avatarPhotoUrls: Array<String>
+  avatarPhotoAvailability: AssetAvailability
+  isPublic?: Boolean | null
+  isCensored: Boolean
+  languageId?: ID_Input | null
+  happenedIn: Float
+}
+
+export interface ChannelUpdateInput {
+  ownerMemberId?: ID_Input | null
+  ownerCuratorGroupId?: ID_Input | null
+  categoryId?: ID_Input | null
+  rewardAccount?: String | null
+  title?: String | null
+  description?: String | null
+  coverPhotoDataObjectId?: ID_Input | null
+  coverPhotoUrls?: String[] | String | null
+  coverPhotoAvailability?: AssetAvailability | null
+  avatarPhotoDataObjectId?: ID_Input | null
+  avatarPhotoUrls?: String[] | String | null
+  avatarPhotoAvailability?: AssetAvailability | null
+  isPublic?: Boolean | null
+  isCensored?: Boolean | null
+  languageId?: ID_Input | null
+  happenedIn?: Float | null
+}
+
+export interface ChannelWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  ownerMemberId_eq?: ID_Input | null
+  ownerMemberId_in?: ID_Output[] | ID_Output | null
+  ownerCuratorGroupId_eq?: ID_Input | null
+  ownerCuratorGroupId_in?: ID_Output[] | ID_Output | null
+  categoryId_eq?: ID_Input | null
+  categoryId_in?: ID_Output[] | ID_Output | null
+  rewardAccount_eq?: String | null
+  rewardAccount_contains?: String | null
+  rewardAccount_startsWith?: String | null
+  rewardAccount_endsWith?: String | null
+  rewardAccount_in?: String[] | String | null
+  title_eq?: String | null
+  title_contains?: String | null
+  title_startsWith?: String | null
+  title_endsWith?: String | null
+  title_in?: String[] | String | null
+  description_eq?: String | null
+  description_contains?: String | null
+  description_startsWith?: String | null
+  description_endsWith?: String | null
+  description_in?: String[] | String | null
+  coverPhotoDataObjectId_eq?: ID_Input | null
+  coverPhotoDataObjectId_in?: ID_Output[] | ID_Output | null
+  coverPhotoAvailability_eq?: AssetAvailability | null
+  coverPhotoAvailability_in?: AssetAvailability[] | AssetAvailability | null
+  avatarPhotoDataObjectId_eq?: ID_Input | null
+  avatarPhotoDataObjectId_in?: ID_Output[] | ID_Output | null
+  avatarPhotoAvailability_eq?: AssetAvailability | null
+  avatarPhotoAvailability_in?: AssetAvailability[] | AssetAvailability | null
+  isPublic_eq?: Boolean | null
+  isPublic_in?: Boolean[] | Boolean | null
+  isCensored_eq?: Boolean | null
+  isCensored_in?: Boolean[] | Boolean | null
+  languageId_eq?: ID_Input | null
+  languageId_in?: ID_Output[] | ID_Output | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+}
+
+export interface ChannelWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface CuratorGroupCreateInput {
+  curatorIds: Array<BigInt>
+  isActive: Boolean
+}
+
+export interface CuratorGroupUpdateInput {
+  curatorIds?: BigInt[] | BigInt | null
+  isActive?: Boolean | null
+}
+
+export interface CuratorGroupWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  isActive_eq?: Boolean | null
+  isActive_in?: Boolean[] | Boolean | null
+}
+
+export interface CuratorGroupWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectCreateInput {
+  owner: JSONObject
+  addedAt: Float
+  typeId: Float
+  size: BigInt
+  liaisonId: BigInt
+  liaisonJudgement: LiaisonJudgement
+  ipfsContentId: String
+  joystreamContentId: String
+}
+
+export interface DataObjectOwnerChannelCreateInput {
+  channel: BigInt
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerChannelUpdateInput {
+  channel?: BigInt | null
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerChannelWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  channel_eq?: BigInt | null
+  channel_gt?: BigInt | null
+  channel_gte?: BigInt | null
+  channel_lt?: BigInt | null
+  channel_lte?: BigInt | null
+  channel_in?: BigInt[] | BigInt | null
+  dummy_eq?: Int | null
+  dummy_gt?: Int | null
+  dummy_gte?: Int | null
+  dummy_lt?: Int | null
+  dummy_lte?: Int | null
+  dummy_in?: Int[] | Int | null
+}
+
+export interface DataObjectOwnerChannelWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectOwnerCouncilCreateInput {
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerCouncilUpdateInput {
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerCouncilWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  dummy_eq?: Int | null
+  dummy_gt?: Int | null
+  dummy_gte?: Int | null
+  dummy_lt?: Int | null
+  dummy_lte?: Int | null
+  dummy_in?: Int[] | Int | null
+}
+
+export interface DataObjectOwnerCouncilWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectOwnerDaoCreateInput {
+  dao: BigInt
+}
+
+export interface DataObjectOwnerDaoUpdateInput {
+  dao?: BigInt | null
+}
+
+export interface DataObjectOwnerDaoWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  dao_eq?: BigInt | null
+  dao_gt?: BigInt | null
+  dao_gte?: BigInt | null
+  dao_lt?: BigInt | null
+  dao_lte?: BigInt | null
+  dao_in?: BigInt[] | BigInt | null
+}
+
+export interface DataObjectOwnerDaoWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectOwnerMemberCreateInput {
+  member: BigInt
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerMemberUpdateInput {
+  member?: BigInt | null
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerMemberWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  member_eq?: BigInt | null
+  member_gt?: BigInt | null
+  member_gte?: BigInt | null
+  member_lt?: BigInt | null
+  member_lte?: BigInt | null
+  member_in?: BigInt[] | BigInt | null
+  dummy_eq?: Int | null
+  dummy_gt?: Int | null
+  dummy_gte?: Int | null
+  dummy_lt?: Int | null
+  dummy_lte?: Int | null
+  dummy_in?: Int[] | Int | null
+}
+
+export interface DataObjectOwnerMemberWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectOwnerWorkingGroupCreateInput {
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerWorkingGroupUpdateInput {
+  dummy?: Float | null
+}
+
+export interface DataObjectOwnerWorkingGroupWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  dummy_eq?: Int | null
+  dummy_gt?: Int | null
+  dummy_gte?: Int | null
+  dummy_lt?: Int | null
+  dummy_lte?: Int | null
+  dummy_in?: Int[] | Int | null
+}
+
+export interface DataObjectOwnerWorkingGroupWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface DataObjectUpdateInput {
+  owner?: JSONObject | null
+  addedAt?: Float | null
+  typeId?: Float | null
+  size?: BigInt | null
+  liaisonId?: BigInt | null
+  liaisonJudgement?: LiaisonJudgement | null
+  ipfsContentId?: String | null
+  joystreamContentId?: String | null
+}
+
+export interface DataObjectWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  owner_json?: JSONObject | null
+  addedAt_eq?: Int | null
+  addedAt_gt?: Int | null
+  addedAt_gte?: Int | null
+  addedAt_lt?: Int | null
+  addedAt_lte?: Int | null
+  addedAt_in?: Int[] | Int | null
+  typeId_eq?: Int | null
+  typeId_gt?: Int | null
+  typeId_gte?: Int | null
+  typeId_lt?: Int | null
+  typeId_lte?: Int | null
+  typeId_in?: Int[] | Int | null
+  size_eq?: BigInt | null
+  size_gt?: BigInt | null
+  size_gte?: BigInt | null
+  size_lt?: BigInt | null
+  size_lte?: BigInt | null
+  size_in?: BigInt[] | BigInt | null
+  liaisonId_eq?: BigInt | null
+  liaisonId_gt?: BigInt | null
+  liaisonId_gte?: BigInt | null
+  liaisonId_lt?: BigInt | null
+  liaisonId_lte?: BigInt | null
+  liaisonId_in?: BigInt[] | BigInt | null
+  liaisonJudgement_eq?: LiaisonJudgement | null
+  liaisonJudgement_in?: LiaisonJudgement[] | LiaisonJudgement | null
+  ipfsContentId_eq?: String | null
+  ipfsContentId_contains?: String | null
+  ipfsContentId_startsWith?: String | null
+  ipfsContentId_endsWith?: String | null
+  ipfsContentId_in?: String[] | String | null
+  joystreamContentId_eq?: String | null
+  joystreamContentId_contains?: String | null
+  joystreamContentId_startsWith?: String | null
+  joystreamContentId_endsWith?: String | null
+  joystreamContentId_in?: String[] | String | null
+}
+
+export interface DataObjectWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface FeaturedVideoCreateInput {
+  videoId: ID_Output
+}
+
+export interface FeaturedVideoUpdateInput {
+  videoId?: ID_Input | null
+}
+
+export interface FeaturedVideoWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  videoId_eq?: ID_Input | null
+  videoId_in?: ID_Output[] | ID_Output | null
+}
+
+export interface FeaturedVideoWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface LanguageCreateInput {
+  iso: String
+  happenedIn: Float
+}
+
+export interface LanguageUpdateInput {
+  iso?: String | null
+  happenedIn?: Float | null
+}
+
+export interface LanguageWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  iso_eq?: String | null
+  iso_contains?: String | null
+  iso_startsWith?: String | null
+  iso_endsWith?: String | null
+  iso_in?: String[] | String | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+}
+
+export interface LanguageWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface LicenseCreateInput {
+  code?: Float | null
+  attribution?: String | null
+  customText?: String | null
+}
+
+export interface LicenseUpdateInput {
+  code?: Float | null
+  attribution?: String | null
+  customText?: String | null
+}
+
+export interface LicenseWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  code_eq?: Int | null
+  code_gt?: Int | null
+  code_gte?: Int | null
+  code_lt?: Int | null
+  code_lte?: Int | null
+  code_in?: Int[] | Int | null
+  attribution_eq?: String | null
+  attribution_contains?: String | null
+  attribution_startsWith?: String | null
+  attribution_endsWith?: String | null
+  attribution_in?: String[] | String | null
+  customText_eq?: String | null
+  customText_contains?: String | null
+  customText_startsWith?: String | null
+  customText_endsWith?: String | null
+  customText_in?: String[] | String | null
+}
+
+export interface LicenseWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface MembershipCreateInput {
+  handle: String
+  avatarUri?: String | null
+  about?: String | null
+  controllerAccount: String
+  rootAccount: String
+  registeredAtBlock: Float
+  registeredAtTime: DateTime
+  entry: MembershipEntryMethod
+  subscription?: BigInt | null
+}
+
+export interface MembershipUpdateInput {
+  handle?: String | null
+  avatarUri?: String | null
+  about?: String | null
+  controllerAccount?: String | null
+  rootAccount?: String | null
+  registeredAtBlock?: Float | null
+  registeredAtTime?: DateTime | null
+  entry?: MembershipEntryMethod | null
+  subscription?: BigInt | null
+}
+
+export interface MembershipWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  handle_eq?: String | null
+  handle_contains?: String | null
+  handle_startsWith?: String | null
+  handle_endsWith?: String | null
+  handle_in?: String[] | String | null
+  avatarUri_eq?: String | null
+  avatarUri_contains?: String | null
+  avatarUri_startsWith?: String | null
+  avatarUri_endsWith?: String | null
+  avatarUri_in?: String[] | String | null
+  about_eq?: String | null
+  about_contains?: String | null
+  about_startsWith?: String | null
+  about_endsWith?: String | null
+  about_in?: String[] | String | null
+  controllerAccount_eq?: String | null
+  controllerAccount_contains?: String | null
+  controllerAccount_startsWith?: String | null
+  controllerAccount_endsWith?: String | null
+  controllerAccount_in?: String[] | String | null
+  rootAccount_eq?: String | null
+  rootAccount_contains?: String | null
+  rootAccount_startsWith?: String | null
+  rootAccount_endsWith?: String | null
+  rootAccount_in?: String[] | String | null
+  registeredAtBlock_eq?: Int | null
+  registeredAtBlock_gt?: Int | null
+  registeredAtBlock_gte?: Int | null
+  registeredAtBlock_lt?: Int | null
+  registeredAtBlock_lte?: Int | null
+  registeredAtBlock_in?: Int[] | Int | null
+  registeredAtTime_eq?: DateTime | null
+  registeredAtTime_lt?: DateTime | null
+  registeredAtTime_lte?: DateTime | null
+  registeredAtTime_gt?: DateTime | null
+  registeredAtTime_gte?: DateTime | null
+  entry_eq?: MembershipEntryMethod | null
+  entry_in?: MembershipEntryMethod[] | MembershipEntryMethod | null
+  subscription_eq?: BigInt | null
+  subscription_gt?: BigInt | null
+  subscription_gte?: BigInt | null
+  subscription_lt?: BigInt | null
+  subscription_lte?: BigInt | null
+  subscription_in?: BigInt[] | BigInt | null
+}
+
+export interface MembershipWhereUniqueInput {
+  id?: ID_Input | null
+  handle?: String | null
+}
+
+export interface VideoCategoryCreateInput {
+  name?: String | null
+  happenedIn: Float
+}
+
+export interface VideoCategoryUpdateInput {
+  name?: String | null
+  happenedIn?: Float | null
+}
+
+export interface VideoCategoryWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  name_eq?: String | null
+  name_contains?: String | null
+  name_startsWith?: String | null
+  name_endsWith?: String | null
+  name_in?: String[] | String | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+}
+
+export interface VideoCategoryWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface VideoCreateInput {
+  channelId: ID_Output
+  categoryId?: ID_Input | null
+  title?: String | null
+  description?: String | null
+  duration?: Float | null
+  thumbnailPhotoDataObjectId?: ID_Input | null
+  thumbnailPhotoUrls: Array<String>
+  thumbnailPhotoAvailability: AssetAvailability
+  languageId?: ID_Input | null
+  hasMarketing?: Boolean | null
+  publishedBeforeJoystream?: DateTime | null
+  isPublic?: Boolean | null
+  isCensored: Boolean
+  isExplicit?: Boolean | null
+  licenseId?: ID_Input | null
+  mediaDataObjectId?: ID_Input | null
+  mediaUrls: Array<String>
+  mediaAvailability: AssetAvailability
+  mediaMetadataId?: ID_Input | null
+  happenedIn: Float
+  isFeatured: Boolean
+}
+
+export interface VideoMediaEncodingCreateInput {
+  codecName?: String | null
+  container?: String | null
+  mimeMediaType?: String | null
+}
+
+export interface VideoMediaEncodingUpdateInput {
+  codecName?: String | null
+  container?: String | null
+  mimeMediaType?: String | null
+}
+
+export interface VideoMediaEncodingWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  codecName_eq?: String | null
+  codecName_contains?: String | null
+  codecName_startsWith?: String | null
+  codecName_endsWith?: String | null
+  codecName_in?: String[] | String | null
+  container_eq?: String | null
+  container_contains?: String | null
+  container_startsWith?: String | null
+  container_endsWith?: String | null
+  container_in?: String[] | String | null
+  mimeMediaType_eq?: String | null
+  mimeMediaType_contains?: String | null
+  mimeMediaType_startsWith?: String | null
+  mimeMediaType_endsWith?: String | null
+  mimeMediaType_in?: String[] | String | null
+}
+
+export interface VideoMediaEncodingWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface VideoMediaMetadataCreateInput {
+  encodingId?: ID_Input | null
+  pixelWidth?: Float | null
+  pixelHeight?: Float | null
+  size?: BigInt | null
+  happenedIn: Float
+}
+
+export interface VideoMediaMetadataUpdateInput {
+  encodingId?: ID_Input | null
+  pixelWidth?: Float | null
+  pixelHeight?: Float | null
+  size?: BigInt | null
+  happenedIn?: Float | null
+}
+
+export interface VideoMediaMetadataWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  encodingId_eq?: ID_Input | null
+  encodingId_in?: ID_Output[] | ID_Output | null
+  pixelWidth_eq?: Int | null
+  pixelWidth_gt?: Int | null
+  pixelWidth_gte?: Int | null
+  pixelWidth_lt?: Int | null
+  pixelWidth_lte?: Int | null
+  pixelWidth_in?: Int[] | Int | null
+  pixelHeight_eq?: Int | null
+  pixelHeight_gt?: Int | null
+  pixelHeight_gte?: Int | null
+  pixelHeight_lt?: Int | null
+  pixelHeight_lte?: Int | null
+  pixelHeight_in?: Int[] | Int | null
+  size_eq?: BigInt | null
+  size_gt?: BigInt | null
+  size_gte?: BigInt | null
+  size_lt?: BigInt | null
+  size_lte?: BigInt | null
+  size_in?: BigInt[] | BigInt | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+}
+
+export interface VideoMediaMetadataWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface VideoUpdateInput {
+  channelId?: ID_Input | null
+  categoryId?: ID_Input | null
+  title?: String | null
+  description?: String | null
+  duration?: Float | null
+  thumbnailPhotoDataObjectId?: ID_Input | null
+  thumbnailPhotoUrls?: String[] | String | null
+  thumbnailPhotoAvailability?: AssetAvailability | null
+  languageId?: ID_Input | null
+  hasMarketing?: Boolean | null
+  publishedBeforeJoystream?: DateTime | null
+  isPublic?: Boolean | null
+  isCensored?: Boolean | null
+  isExplicit?: Boolean | null
+  licenseId?: ID_Input | null
+  mediaDataObjectId?: ID_Input | null
+  mediaUrls?: String[] | String | null
+  mediaAvailability?: AssetAvailability | null
+  mediaMetadataId?: ID_Input | null
+  happenedIn?: Float | null
+  isFeatured?: Boolean | null
+}
+
+export interface VideoWhereInput {
+  id_eq?: ID_Input | null
+  id_in?: ID_Output[] | ID_Output | null
+  createdAt_eq?: DateTime | null
+  createdAt_lt?: DateTime | null
+  createdAt_lte?: DateTime | null
+  createdAt_gt?: DateTime | null
+  createdAt_gte?: DateTime | null
+  createdById_eq?: ID_Input | null
+  createdById_in?: ID_Output[] | ID_Output | null
+  updatedAt_eq?: DateTime | null
+  updatedAt_lt?: DateTime | null
+  updatedAt_lte?: DateTime | null
+  updatedAt_gt?: DateTime | null
+  updatedAt_gte?: DateTime | null
+  updatedById_eq?: ID_Input | null
+  updatedById_in?: ID_Output[] | ID_Output | null
+  deletedAt_all?: Boolean | null
+  deletedAt_eq?: DateTime | null
+  deletedAt_lt?: DateTime | null
+  deletedAt_lte?: DateTime | null
+  deletedAt_gt?: DateTime | null
+  deletedAt_gte?: DateTime | null
+  deletedById_eq?: ID_Input | null
+  deletedById_in?: ID_Output[] | ID_Output | null
+  channelId_eq?: ID_Input | null
+  channelId_in?: ID_Output[] | ID_Output | null
+  categoryId_eq?: ID_Input | null
+  categoryId_in?: ID_Output[] | ID_Output | null
+  title_eq?: String | null
+  title_contains?: String | null
+  title_startsWith?: String | null
+  title_endsWith?: String | null
+  title_in?: String[] | String | null
+  description_eq?: String | null
+  description_contains?: String | null
+  description_startsWith?: String | null
+  description_endsWith?: String | null
+  description_in?: String[] | String | null
+  duration_eq?: Int | null
+  duration_gt?: Int | null
+  duration_gte?: Int | null
+  duration_lt?: Int | null
+  duration_lte?: Int | null
+  duration_in?: Int[] | Int | null
+  thumbnailPhotoDataObjectId_eq?: ID_Input | null
+  thumbnailPhotoDataObjectId_in?: ID_Output[] | ID_Output | null
+  thumbnailPhotoAvailability_eq?: AssetAvailability | null
+  thumbnailPhotoAvailability_in?: AssetAvailability[] | AssetAvailability | null
+  languageId_eq?: ID_Input | null
+  languageId_in?: ID_Output[] | ID_Output | null
+  hasMarketing_eq?: Boolean | null
+  hasMarketing_in?: Boolean[] | Boolean | null
+  publishedBeforeJoystream_eq?: DateTime | null
+  publishedBeforeJoystream_lt?: DateTime | null
+  publishedBeforeJoystream_lte?: DateTime | null
+  publishedBeforeJoystream_gt?: DateTime | null
+  publishedBeforeJoystream_gte?: DateTime | null
+  isPublic_eq?: Boolean | null
+  isPublic_in?: Boolean[] | Boolean | null
+  isCensored_eq?: Boolean | null
+  isCensored_in?: Boolean[] | Boolean | null
+  isExplicit_eq?: Boolean | null
+  isExplicit_in?: Boolean[] | Boolean | null
+  licenseId_eq?: ID_Input | null
+  licenseId_in?: ID_Output[] | ID_Output | null
+  mediaDataObjectId_eq?: ID_Input | null
+  mediaDataObjectId_in?: ID_Output[] | ID_Output | null
+  mediaAvailability_eq?: AssetAvailability | null
+  mediaAvailability_in?: AssetAvailability[] | AssetAvailability | null
+  mediaMetadataId_eq?: ID_Input | null
+  mediaMetadataId_in?: ID_Output[] | ID_Output | null
+  happenedIn_eq?: Int | null
+  happenedIn_gt?: Int | null
+  happenedIn_gte?: Int | null
+  happenedIn_lt?: Int | null
+  happenedIn_lte?: Int | null
+  happenedIn_in?: Int[] | Int | null
+  isFeatured_eq?: Boolean | null
+  isFeatured_in?: Boolean[] | Boolean | null
+}
+
+export interface VideoWhereUniqueInput {
+  id: ID_Output
+}
+
+export interface BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+}
+
+export interface DeleteResponse {
+  id: ID_Output
+}
+
+export interface BaseModel extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+}
+
+export interface BaseModelUUID extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+}
+
+export interface Channel extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  ownerMember?: Membership | null
+  ownerMemberId?: String | null
+  ownerCuratorGroup?: CuratorGroup | null
+  ownerCuratorGroupId?: String | null
+  category?: ChannelCategory | null
+  categoryId?: String | null
+  rewardAccount?: String | null
+  title?: String | null
+  description?: String | null
+  coverPhotoDataObject?: DataObject | null
+  coverPhotoDataObjectId?: String | null
+  coverPhotoUrls: Array<String>
+  coverPhotoAvailability: AssetAvailability
+  avatarPhotoDataObject?: DataObject | null
+  avatarPhotoDataObjectId?: String | null
+  avatarPhotoUrls: Array<String>
+  avatarPhotoAvailability: AssetAvailability
+  isPublic?: Boolean | null
+  isCensored: Boolean
+  language?: Language | null
+  languageId?: String | null
+  videos: Array<Video>
+  happenedIn: Int
+}
+
+export interface ChannelCategoriesByNameFTSOutput {
+  item: ChannelCategoriesByNameSearchResult
+  rank: Float
+  isTypeOf: String
+  highlight: String
+}
+
+/*
+ * Category of media channel
+
+ */
+export interface ChannelCategory extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  name?: String | null
+  channels: Array<Channel>
+  happenedIn: Int
+}
+
+export interface ChannelCategoryConnection {
+  totalCount: Int
+  edges: Array<ChannelCategoryEdge>
+  pageInfo: PageInfo
+}
+
+export interface ChannelCategoryEdge {
+  node: ChannelCategory
+  cursor: String
+}
+
+export interface ChannelConnection {
+  totalCount: Int
+  edges: Array<ChannelEdge>
+  pageInfo: PageInfo
+}
+
+export interface ChannelEdge {
+  node: Channel
+  cursor: String
+}
+
+export interface CuratorGroup extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  curatorIds: Array<BigInt>
+  isActive: Boolean
+  channels: Array<Channel>
+}
+
+export interface CuratorGroupConnection {
+  totalCount: Int
+  edges: Array<CuratorGroupEdge>
+  pageInfo: PageInfo
+}
+
+export interface CuratorGroupEdge {
+  node: CuratorGroup
+  cursor: String
+}
+
+/*
+ * Manages content ids, type and storage provider decision about it
+
+ */
+export interface DataObject extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  owner: DataObjectOwner
+  addedAt: Int
+  typeId: Int
+  size: BigInt
+  liaisonId: BigInt
+  liaisonJudgement: LiaisonJudgement
+  ipfsContentId: String
+  joystreamContentId: String
+  channelcoverPhotoDataObject?: Array<Channel> | null
+  channelavatarPhotoDataObject?: Array<Channel> | null
+  videothumbnailPhotoDataObject?: Array<Video> | null
+  videomediaDataObject?: Array<Video> | null
+}
+
+export interface DataObjectConnection {
+  totalCount: Int
+  edges: Array<DataObjectEdge>
+  pageInfo: PageInfo
+}
+
+export interface DataObjectEdge {
+  node: DataObject
+  cursor: String
+}
+
+export interface DataObjectOwnerChannel {
+  channel: BigInt
+  dummy?: Int | null
+}
+
+export interface DataObjectOwnerCouncil {
+  dummy?: Int | null
+}
+
+export interface DataObjectOwnerDao {
+  dao: BigInt
+}
+
+export interface DataObjectOwnerMember {
+  member: BigInt
+  dummy?: Int | null
+}
+
+export interface DataObjectOwnerWorkingGroup {
+  dummy?: Int | null
+}
+
+export interface FeaturedVideo extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  video: Video
+  videoId: String
+}
+
+export interface FeaturedVideoConnection {
+  totalCount: Int
+  edges: Array<FeaturedVideoEdge>
+  pageInfo: PageInfo
+}
+
+export interface FeaturedVideoEdge {
+  node: FeaturedVideo
+  cursor: String
+}
+
+export interface Language extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  iso: String
+  happenedIn: Int
+  channellanguage?: Array<Channel> | null
+  videolanguage?: Array<Video> | null
+}
+
+export interface LanguageConnection {
+  totalCount: Int
+  edges: Array<LanguageEdge>
+  pageInfo: PageInfo
+}
+
+export interface LanguageEdge {
+  node: Language
+  cursor: String
+}
+
+export interface License extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  code?: Int | null
+  attribution?: String | null
+  customText?: String | null
+  videolicense?: Array<Video> | null
+}
+
+export interface LicenseConnection {
+  totalCount: Int
+  edges: Array<LicenseEdge>
+  pageInfo: PageInfo
+}
+
+export interface LicenseEdge {
+  node: License
+  cursor: String
+}
+
+export interface MembersByHandleFTSOutput {
+  item: MembersByHandleSearchResult
+  rank: Float
+  isTypeOf: String
+  highlight: String
+}
+
+/*
+ * Stored information about a registered user
+
+ */
+export interface Membership extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  handle: String
+  avatarUri?: String | null
+  about?: String | null
+  controllerAccount: String
+  rootAccount: String
+  registeredAtBlock: Int
+  registeredAtTime: DateTime
+  entry: MembershipEntryMethod
+  subscription?: BigInt | null
+  channels: Array<Channel>
+}
+
+export interface MembershipConnection {
+  totalCount: Int
+  edges: Array<MembershipEdge>
+  pageInfo: PageInfo
+}
+
+export interface MembershipEdge {
+  node: Membership
+  cursor: String
+}
+
+export interface PageInfo {
+  hasNextPage: Boolean
+  hasPreviousPage: Boolean
+  startCursor?: String | null
+  endCursor?: String | null
+}
+
+export interface ProcessorState {
+  lastCompleteBlock: Float
+  lastProcessedEvent: String
+  indexerHead: Float
+  chainHead: Float
+}
+
+export interface SearchFTSOutput {
+  item: SearchSearchResult
+  rank: Float
+  isTypeOf: String
+  highlight: String
+}
+
+export interface StandardDeleteResponse {
+  id: ID_Output
+}
+
+export interface Video extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  channel: Channel
+  channelId: String
+  category?: VideoCategory | null
+  categoryId?: String | null
+  title?: String | null
+  description?: String | null
+  duration?: Int | null
+  thumbnailPhotoDataObject?: DataObject | null
+  thumbnailPhotoDataObjectId?: String | null
+  thumbnailPhotoUrls: Array<String>
+  thumbnailPhotoAvailability: AssetAvailability
+  language?: Language | null
+  languageId?: String | null
+  hasMarketing?: Boolean | null
+  publishedBeforeJoystream?: DateTime | null
+  isPublic?: Boolean | null
+  isCensored: Boolean
+  isExplicit?: Boolean | null
+  license?: License | null
+  licenseId?: String | null
+  mediaDataObject?: DataObject | null
+  mediaDataObjectId?: String | null
+  mediaUrls: Array<String>
+  mediaAvailability: AssetAvailability
+  mediaMetadata?: VideoMediaMetadata | null
+  mediaMetadataId?: String | null
+  happenedIn: Int
+  isFeatured: Boolean
+  featured?: FeaturedVideo | null
+}
+
+export interface VideoCategoriesByNameFTSOutput {
+  item: VideoCategoriesByNameSearchResult
+  rank: Float
+  isTypeOf: String
+  highlight: String
+}
+
+export interface VideoCategory extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  name?: String | null
+  videos: Array<Video>
+  happenedIn: Int
+}
+
+export interface VideoCategoryConnection {
+  totalCount: Int
+  edges: Array<VideoCategoryEdge>
+  pageInfo: PageInfo
+}
+
+export interface VideoCategoryEdge {
+  node: VideoCategory
+  cursor: String
+}
+
+export interface VideoConnection {
+  totalCount: Int
+  edges: Array<VideoEdge>
+  pageInfo: PageInfo
+}
+
+export interface VideoEdge {
+  node: Video
+  cursor: String
+}
+
+export interface VideoMediaEncoding extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  codecName?: String | null
+  container?: String | null
+  mimeMediaType?: String | null
+  videomediametadataencoding?: Array<VideoMediaMetadata> | null
+}
+
+export interface VideoMediaEncodingConnection {
+  totalCount: Int
+  edges: Array<VideoMediaEncodingEdge>
+  pageInfo: PageInfo
+}
+
+export interface VideoMediaEncodingEdge {
+  node: VideoMediaEncoding
+  cursor: String
+}
+
+export interface VideoMediaMetadata extends BaseGraphQLObject {
+  id: ID_Output
+  createdAt: DateTime
+  createdById: String
+  updatedAt?: DateTime | null
+  updatedById?: String | null
+  deletedAt?: DateTime | null
+  deletedById?: String | null
+  version: Int
+  encoding?: VideoMediaEncoding | null
+  encodingId?: String | null
+  pixelWidth?: Int | null
+  pixelHeight?: Int | null
+  size?: BigInt | null
+  video?: Video | null
+  happenedIn: Int
+}
+
+export interface VideoMediaMetadataConnection {
+  totalCount: Int
+  edges: Array<VideoMediaMetadataEdge>
+  pageInfo: PageInfo
+}
+
+export interface VideoMediaMetadataEdge {
+  node: VideoMediaMetadata
+  cursor: String
+}
+
+/*
+GraphQL representation of BigInt
+*/
+export type BigInt = string
+
+/*
+The `Boolean` scalar type represents `true` or `false`.
+*/
+export type Boolean = boolean
+
+/*
+The javascript `Date` as string. Type represents date and time as the ISO Date string.
+*/
+export type DateTime = Date | string
+
+/*
+The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
+*/
+export type Float = number
+
+/*
+The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
+*/
+export type ID_Input = string | number
+export type ID_Output = string
+
+/*
+The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
+*/
+export type Int = number
+
+/*
+The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
+*/
+
+    export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
+
+    export type JsonPrimitive = string | number | boolean | null | {};
+    
+        // eslint-disable-next-line @typescript-eslint/no-empty-interface
+    export interface JsonArray extends Array<JsonValue> {}
+    
+    export type JsonObject = { [member: string]: JsonValue };
+
+    export type JSONObject = JsonObject;
+  
+
+/*
+The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
+*/
+export type String = string
+
+export type ChannelCategoriesByNameSearchResult = ChannelCategory
+
+export type DataObjectOwner = DataObjectOwnerMember | DataObjectOwnerChannel | DataObjectOwnerDao | DataObjectOwnerCouncil | DataObjectOwnerWorkingGroup
+
+export type MembersByHandleSearchResult = Membership
+
+export type SearchSearchResult = Channel | Video
+
+export type VideoCategoriesByNameSearchResult = VideoCategory

+ 3801 - 0
query-node/generated/graphql-server/generated/classes.ts

@@ -0,0 +1,3801 @@
+// This file has been auto-generated by Warthog.  Do not update directly as it
+// will be re-written.  If you need to change this file, update models or add
+// new TypeGraphQL objects
+// prettier-ignore
+// @ts-ignore
+import { DateResolver as Date } from 'graphql-scalars';
+// prettier-ignore
+// @ts-ignore
+import { GraphQLID as ID } from 'graphql';
+// prettier-ignore
+// @ts-ignore
+import { ArgsType, Field as TypeGraphQLField, Float, InputType as TypeGraphQLInputType, Int } from 'type-graphql';
+// prettier-ignore
+// @ts-ignore
+import { registerEnumType, GraphQLISODateTime as DateTime } from "type-graphql";
+
+import * as BN from "bn.js";
+
+// prettier-ignore
+// @ts-ignore eslint-disable-next-line @typescript-eslint/no-var-requires
+const { GraphQLJSONObject } = require('graphql-type-json');
+// prettier-ignore
+// @ts-ignore
+import { BaseWhereInput, JsonObject, PaginationArgs, DateOnlyString, DateTimeString, BigInt, Bytes } from 'warthog';
+
+import { MembershipEntryMethod } from "../src/modules/membership/membership.model";
+import { AssetAvailability } from "../src/modules/video/video.model";
+import { LiaisonJudgement } from "../src/modules/data-object/data-object.model";
+
+// @ts-ignore
+import { Membership } from "../src/modules/membership/membership.model";
+// @ts-ignore
+import { CuratorGroup } from "../src/modules/curator-group/curator-group.model";
+// @ts-ignore
+import { VideoCategory } from "../src/modules/video-category/video-category.model";
+// @ts-ignore
+import { Language } from "../src/modules/language/language.model";
+// @ts-ignore
+import { License } from "../src/modules/license/license.model";
+// @ts-ignore
+import { VideoMediaEncoding } from "../src/modules/video-media-encoding/video-media-encoding.model";
+// @ts-ignore
+import { VideoMediaMetadata } from "../src/modules/video-media-metadata/video-media-metadata.model";
+// @ts-ignore
+import { FeaturedVideo } from "../src/modules/featured-video/featured-video.model";
+// @ts-ignore
+import { Video } from "../src/modules/video/video.model";
+// @ts-ignore
+import { DataObject } from "../src/modules/data-object/data-object.model";
+// @ts-ignore
+import { Channel } from "../src/modules/channel/channel.model";
+// @ts-ignore
+import { ChannelCategory } from "../src/modules/channel-category/channel-category.model";
+
+export enum MembershipOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  handle_ASC = "handle_ASC",
+  handle_DESC = "handle_DESC",
+
+  avatarUri_ASC = "avatarUri_ASC",
+  avatarUri_DESC = "avatarUri_DESC",
+
+  about_ASC = "about_ASC",
+  about_DESC = "about_DESC",
+
+  controllerAccount_ASC = "controllerAccount_ASC",
+  controllerAccount_DESC = "controllerAccount_DESC",
+
+  rootAccount_ASC = "rootAccount_ASC",
+  rootAccount_DESC = "rootAccount_DESC",
+
+  registeredAtBlock_ASC = "registeredAtBlock_ASC",
+  registeredAtBlock_DESC = "registeredAtBlock_DESC",
+
+  registeredAtTime_ASC = "registeredAtTime_ASC",
+  registeredAtTime_DESC = "registeredAtTime_DESC",
+
+  entry_ASC = "entry_ASC",
+  entry_DESC = "entry_DESC",
+
+  subscription_ASC = "subscription_ASC",
+  subscription_DESC = "subscription_DESC"
+}
+
+registerEnumType(MembershipOrderByEnum, {
+  name: "MembershipOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class MembershipWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  handle_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  handle_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  handle_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  handle_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  handle_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  avatarUri_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  about_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  about_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  about_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  about_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  about_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  controllerAccount_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  controllerAccount_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  controllerAccount_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  controllerAccount_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  controllerAccount_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  rootAccount_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rootAccount_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rootAccount_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rootAccount_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  rootAccount_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  registeredAtBlock_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  registeredAtBlock_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  registeredAtBlock_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  registeredAtBlock_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  registeredAtBlock_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  registeredAtBlock_in?: number[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime_eq?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime_lt?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime_lte?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime_gt?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime_gte?: DateTimeString;
+
+  @TypeGraphQLField(() => MembershipEntryMethod, { nullable: true })
+  entry_eq?: MembershipEntryMethod;
+
+  @TypeGraphQLField(() => [MembershipEntryMethod], { nullable: true })
+  entry_in?: MembershipEntryMethod[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  subscription_in?: BN[];
+}
+
+@TypeGraphQLInputType()
+export class MembershipWhereUniqueInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id?: string;
+
+  @TypeGraphQLField(() => String, { nullable: true })
+  handle?: string;
+}
+
+@TypeGraphQLInputType()
+export class MembershipCreateInput {
+  @TypeGraphQLField()
+  handle!: string;
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  about?: string;
+
+  @TypeGraphQLField()
+  controllerAccount!: string;
+
+  @TypeGraphQLField()
+  rootAccount!: string;
+
+  @TypeGraphQLField()
+  registeredAtBlock!: number;
+
+  @TypeGraphQLField(() => DateTime)
+  registeredAtTime!: DateTimeString;
+
+  @TypeGraphQLField(() => MembershipEntryMethod)
+  entry!: MembershipEntryMethod;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription?: BN;
+}
+
+@TypeGraphQLInputType()
+export class MembershipUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  handle?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  avatarUri?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  about?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  controllerAccount?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rootAccount?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  registeredAtBlock?: number;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  registeredAtTime?: DateTimeString;
+
+  @TypeGraphQLField(() => MembershipEntryMethod, { nullable: true })
+  entry?: MembershipEntryMethod;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  subscription?: BN;
+}
+
+@ArgsType()
+export class MembershipWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => MembershipWhereInput, { nullable: true })
+  where?: MembershipWhereInput;
+
+  @TypeGraphQLField(() => MembershipOrderByEnum, { nullable: true })
+  orderBy?: MembershipOrderByEnum;
+}
+
+@ArgsType()
+export class MembershipCreateManyArgs {
+  @TypeGraphQLField(() => [MembershipCreateInput])
+  data!: MembershipCreateInput[];
+}
+
+@ArgsType()
+export class MembershipUpdateArgs {
+  @TypeGraphQLField() data!: MembershipUpdateInput;
+  @TypeGraphQLField() where!: MembershipWhereUniqueInput;
+}
+
+export enum CuratorGroupOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  isActive_ASC = "isActive_ASC",
+  isActive_DESC = "isActive_DESC"
+}
+
+registerEnumType(CuratorGroupOrderByEnum, {
+  name: "CuratorGroupOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class CuratorGroupWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isActive_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isActive_in?: Boolean[];
+}
+
+@TypeGraphQLInputType()
+export class CuratorGroupWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class CuratorGroupCreateInput {
+  @TypeGraphQLField(() => [BigInt])
+  curatorIds!: BN[];
+
+  @TypeGraphQLField()
+  isActive!: boolean;
+}
+
+@TypeGraphQLInputType()
+export class CuratorGroupUpdateInput {
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  curatorIds?: BN[];
+
+  @TypeGraphQLField({ nullable: true })
+  isActive?: boolean;
+}
+
+@ArgsType()
+export class CuratorGroupWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => CuratorGroupWhereInput, { nullable: true })
+  where?: CuratorGroupWhereInput;
+
+  @TypeGraphQLField(() => CuratorGroupOrderByEnum, { nullable: true })
+  orderBy?: CuratorGroupOrderByEnum;
+}
+
+@ArgsType()
+export class CuratorGroupCreateManyArgs {
+  @TypeGraphQLField(() => [CuratorGroupCreateInput])
+  data!: CuratorGroupCreateInput[];
+}
+
+@ArgsType()
+export class CuratorGroupUpdateArgs {
+  @TypeGraphQLField() data!: CuratorGroupUpdateInput;
+  @TypeGraphQLField() where!: CuratorGroupWhereUniqueInput;
+}
+
+export enum DataObjectOwnerChannelOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  channel_ASC = "channel_ASC",
+  channel_DESC = "channel_DESC",
+
+  dummy_ASC = "dummy_ASC",
+  dummy_DESC = "dummy_DESC"
+}
+
+registerEnumType(DataObjectOwnerChannelOrderByEnum, {
+  name: "DataObjectOwnerChannelOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerChannelWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  channel_in?: BN[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  dummy_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerChannelWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerChannelCreateInput {
+  @TypeGraphQLField(() => BigInt)
+  channel!: BN;
+
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerChannelUpdateInput {
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  channel?: BN;
+
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@ArgsType()
+export class DataObjectOwnerChannelWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectOwnerChannelWhereInput, { nullable: true })
+  where?: DataObjectOwnerChannelWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOwnerChannelOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOwnerChannelOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectOwnerChannelCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectOwnerChannelCreateInput])
+  data!: DataObjectOwnerChannelCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectOwnerChannelUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectOwnerChannelUpdateInput;
+  @TypeGraphQLField() where!: DataObjectOwnerChannelWhereUniqueInput;
+}
+
+export enum DataObjectOwnerCouncilOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  dummy_ASC = "dummy_ASC",
+  dummy_DESC = "dummy_DESC"
+}
+
+registerEnumType(DataObjectOwnerCouncilOrderByEnum, {
+  name: "DataObjectOwnerCouncilOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerCouncilWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  dummy_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerCouncilWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerCouncilCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerCouncilUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@ArgsType()
+export class DataObjectOwnerCouncilWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectOwnerCouncilWhereInput, { nullable: true })
+  where?: DataObjectOwnerCouncilWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOwnerCouncilOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOwnerCouncilOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectOwnerCouncilCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectOwnerCouncilCreateInput])
+  data!: DataObjectOwnerCouncilCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectOwnerCouncilUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectOwnerCouncilUpdateInput;
+  @TypeGraphQLField() where!: DataObjectOwnerCouncilWhereUniqueInput;
+}
+
+export enum DataObjectOwnerDaoOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  dao_ASC = "dao_ASC",
+  dao_DESC = "dao_DESC"
+}
+
+registerEnumType(DataObjectOwnerDaoOrderByEnum, {
+  name: "DataObjectOwnerDaoOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerDaoWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  dao_in?: BN[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerDaoWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerDaoCreateInput {
+  @TypeGraphQLField(() => BigInt)
+  dao!: BN;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerDaoUpdateInput {
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  dao?: BN;
+}
+
+@ArgsType()
+export class DataObjectOwnerDaoWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectOwnerDaoWhereInput, { nullable: true })
+  where?: DataObjectOwnerDaoWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOwnerDaoOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOwnerDaoOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectOwnerDaoCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectOwnerDaoCreateInput])
+  data!: DataObjectOwnerDaoCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectOwnerDaoUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectOwnerDaoUpdateInput;
+  @TypeGraphQLField() where!: DataObjectOwnerDaoWhereUniqueInput;
+}
+
+export enum DataObjectOwnerMemberOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  member_ASC = "member_ASC",
+  member_DESC = "member_DESC",
+
+  dummy_ASC = "dummy_ASC",
+  dummy_DESC = "dummy_DESC"
+}
+
+registerEnumType(DataObjectOwnerMemberOrderByEnum, {
+  name: "DataObjectOwnerMemberOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerMemberWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  member_in?: BN[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  dummy_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerMemberWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerMemberCreateInput {
+  @TypeGraphQLField(() => BigInt)
+  member!: BN;
+
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerMemberUpdateInput {
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  member?: BN;
+
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@ArgsType()
+export class DataObjectOwnerMemberWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectOwnerMemberWhereInput, { nullable: true })
+  where?: DataObjectOwnerMemberWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOwnerMemberOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOwnerMemberOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectOwnerMemberCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectOwnerMemberCreateInput])
+  data!: DataObjectOwnerMemberCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectOwnerMemberUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectOwnerMemberUpdateInput;
+  @TypeGraphQLField() where!: DataObjectOwnerMemberWhereUniqueInput;
+}
+
+export enum DataObjectOwnerWorkingGroupOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  dummy_ASC = "dummy_ASC",
+  dummy_DESC = "dummy_DESC"
+}
+
+registerEnumType(DataObjectOwnerWorkingGroupOrderByEnum, {
+  name: "DataObjectOwnerWorkingGroupOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerWorkingGroupWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  dummy_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  dummy_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerWorkingGroupWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerWorkingGroupCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectOwnerWorkingGroupUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  dummy?: number;
+}
+
+@ArgsType()
+export class DataObjectOwnerWorkingGroupWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectOwnerWorkingGroupWhereInput, {
+    nullable: true
+  })
+  where?: DataObjectOwnerWorkingGroupWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOwnerWorkingGroupOrderByEnum, {
+    nullable: true
+  })
+  orderBy?: DataObjectOwnerWorkingGroupOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectOwnerWorkingGroupCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectOwnerWorkingGroupCreateInput])
+  data!: DataObjectOwnerWorkingGroupCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectOwnerWorkingGroupUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectOwnerWorkingGroupUpdateInput;
+  @TypeGraphQLField() where!: DataObjectOwnerWorkingGroupWhereUniqueInput;
+}
+
+export enum VideoCategoryOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  name_ASC = "name_ASC",
+  name_DESC = "name_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC"
+}
+
+registerEnumType(VideoCategoryOrderByEnum, {
+  name: "VideoCategoryOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class VideoCategoryWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  name_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  name_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class VideoCategoryWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class VideoCategoryCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  name?: string;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+}
+
+@TypeGraphQLInputType()
+export class VideoCategoryUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  name?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+}
+
+@ArgsType()
+export class VideoCategoryWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => VideoCategoryWhereInput, { nullable: true })
+  where?: VideoCategoryWhereInput;
+
+  @TypeGraphQLField(() => VideoCategoryOrderByEnum, { nullable: true })
+  orderBy?: VideoCategoryOrderByEnum;
+}
+
+@ArgsType()
+export class VideoCategoryCreateManyArgs {
+  @TypeGraphQLField(() => [VideoCategoryCreateInput])
+  data!: VideoCategoryCreateInput[];
+}
+
+@ArgsType()
+export class VideoCategoryUpdateArgs {
+  @TypeGraphQLField() data!: VideoCategoryUpdateInput;
+  @TypeGraphQLField() where!: VideoCategoryWhereUniqueInput;
+}
+
+export enum LanguageOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  iso_ASC = "iso_ASC",
+  iso_DESC = "iso_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC"
+}
+
+registerEnumType(LanguageOrderByEnum, {
+  name: "LanguageOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class LanguageWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  iso_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  iso_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  iso_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  iso_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  iso_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class LanguageWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class LanguageCreateInput {
+  @TypeGraphQLField()
+  iso!: string;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+}
+
+@TypeGraphQLInputType()
+export class LanguageUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  iso?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+}
+
+@ArgsType()
+export class LanguageWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => LanguageWhereInput, { nullable: true })
+  where?: LanguageWhereInput;
+
+  @TypeGraphQLField(() => LanguageOrderByEnum, { nullable: true })
+  orderBy?: LanguageOrderByEnum;
+}
+
+@ArgsType()
+export class LanguageCreateManyArgs {
+  @TypeGraphQLField(() => [LanguageCreateInput])
+  data!: LanguageCreateInput[];
+}
+
+@ArgsType()
+export class LanguageUpdateArgs {
+  @TypeGraphQLField() data!: LanguageUpdateInput;
+  @TypeGraphQLField() where!: LanguageWhereUniqueInput;
+}
+
+export enum LicenseOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  code_ASC = "code_ASC",
+  code_DESC = "code_DESC",
+
+  attribution_ASC = "attribution_ASC",
+  attribution_DESC = "attribution_DESC",
+
+  customText_ASC = "customText_ASC",
+  customText_DESC = "customText_DESC"
+}
+
+registerEnumType(LicenseOrderByEnum, {
+  name: "LicenseOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class LicenseWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  code_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  code_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  code_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  code_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  code_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  code_in?: number[];
+
+  @TypeGraphQLField({ nullable: true })
+  attribution_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  attribution_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  attribution_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  attribution_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  attribution_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  customText_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  customText_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  customText_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  customText_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  customText_in?: string[];
+}
+
+@TypeGraphQLInputType()
+export class LicenseWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class LicenseCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  code?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  attribution?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  customText?: string;
+}
+
+@TypeGraphQLInputType()
+export class LicenseUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  code?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  attribution?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  customText?: string;
+}
+
+@ArgsType()
+export class LicenseWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => LicenseWhereInput, { nullable: true })
+  where?: LicenseWhereInput;
+
+  @TypeGraphQLField(() => LicenseOrderByEnum, { nullable: true })
+  orderBy?: LicenseOrderByEnum;
+}
+
+@ArgsType()
+export class LicenseCreateManyArgs {
+  @TypeGraphQLField(() => [LicenseCreateInput])
+  data!: LicenseCreateInput[];
+}
+
+@ArgsType()
+export class LicenseUpdateArgs {
+  @TypeGraphQLField() data!: LicenseUpdateInput;
+  @TypeGraphQLField() where!: LicenseWhereUniqueInput;
+}
+
+export enum VideoMediaEncodingOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  codecName_ASC = "codecName_ASC",
+  codecName_DESC = "codecName_DESC",
+
+  container_ASC = "container_ASC",
+  container_DESC = "container_DESC",
+
+  mimeMediaType_ASC = "mimeMediaType_ASC",
+  mimeMediaType_DESC = "mimeMediaType_DESC"
+}
+
+registerEnumType(VideoMediaEncodingOrderByEnum, {
+  name: "VideoMediaEncodingOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class VideoMediaEncodingWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  codecName_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  codecName_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  codecName_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  codecName_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  codecName_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  container_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  container_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  container_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  container_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  container_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  mimeMediaType_in?: string[];
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaEncodingWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaEncodingCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  codecName?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  container?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType?: string;
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaEncodingUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  codecName?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  container?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  mimeMediaType?: string;
+}
+
+@ArgsType()
+export class VideoMediaEncodingWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => VideoMediaEncodingWhereInput, { nullable: true })
+  where?: VideoMediaEncodingWhereInput;
+
+  @TypeGraphQLField(() => VideoMediaEncodingOrderByEnum, { nullable: true })
+  orderBy?: VideoMediaEncodingOrderByEnum;
+}
+
+@ArgsType()
+export class VideoMediaEncodingCreateManyArgs {
+  @TypeGraphQLField(() => [VideoMediaEncodingCreateInput])
+  data!: VideoMediaEncodingCreateInput[];
+}
+
+@ArgsType()
+export class VideoMediaEncodingUpdateArgs {
+  @TypeGraphQLField() data!: VideoMediaEncodingUpdateInput;
+  @TypeGraphQLField() where!: VideoMediaEncodingWhereUniqueInput;
+}
+
+export enum VideoMediaMetadataOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  encodingId_ASC = "encodingId_ASC",
+  encodingId_DESC = "encodingId_DESC",
+
+  pixelWidth_ASC = "pixelWidth_ASC",
+  pixelWidth_DESC = "pixelWidth_DESC",
+
+  pixelHeight_ASC = "pixelHeight_ASC",
+  pixelHeight_DESC = "pixelHeight_DESC",
+
+  size_ASC = "size_ASC",
+  size_DESC = "size_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC"
+}
+
+registerEnumType(VideoMediaMetadataOrderByEnum, {
+  name: "VideoMediaMetadataOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class VideoMediaMetadataWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  encodingId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  encodingId_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelWidth_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelWidth_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelWidth_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelWidth_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelWidth_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  pixelWidth_in?: number[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelHeight_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelHeight_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelHeight_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelHeight_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  pixelHeight_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  pixelHeight_in?: number[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  size_in?: BN[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaMetadataWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaMetadataCreateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  encodingId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  pixelWidth?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  pixelHeight?: number;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size?: BN;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+}
+
+@TypeGraphQLInputType()
+export class VideoMediaMetadataUpdateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  encodingId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  pixelWidth?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  pixelHeight?: number;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size?: BN;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+}
+
+@ArgsType()
+export class VideoMediaMetadataWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => VideoMediaMetadataWhereInput, { nullable: true })
+  where?: VideoMediaMetadataWhereInput;
+
+  @TypeGraphQLField(() => VideoMediaMetadataOrderByEnum, { nullable: true })
+  orderBy?: VideoMediaMetadataOrderByEnum;
+}
+
+@ArgsType()
+export class VideoMediaMetadataCreateManyArgs {
+  @TypeGraphQLField(() => [VideoMediaMetadataCreateInput])
+  data!: VideoMediaMetadataCreateInput[];
+}
+
+@ArgsType()
+export class VideoMediaMetadataUpdateArgs {
+  @TypeGraphQLField() data!: VideoMediaMetadataUpdateInput;
+  @TypeGraphQLField() where!: VideoMediaMetadataWhereUniqueInput;
+}
+
+export enum FeaturedVideoOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  videoId_ASC = "videoId_ASC",
+  videoId_DESC = "videoId_DESC"
+}
+
+registerEnumType(FeaturedVideoOrderByEnum, {
+  name: "FeaturedVideoOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class FeaturedVideoWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  videoId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  videoId_in?: string[];
+}
+
+@TypeGraphQLInputType()
+export class FeaturedVideoWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class FeaturedVideoCreateInput {
+  @TypeGraphQLField(() => ID)
+  videoId!: string;
+}
+
+@TypeGraphQLInputType()
+export class FeaturedVideoUpdateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  videoId?: string;
+}
+
+@ArgsType()
+export class FeaturedVideoWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => FeaturedVideoWhereInput, { nullable: true })
+  where?: FeaturedVideoWhereInput;
+
+  @TypeGraphQLField(() => FeaturedVideoOrderByEnum, { nullable: true })
+  orderBy?: FeaturedVideoOrderByEnum;
+}
+
+@ArgsType()
+export class FeaturedVideoCreateManyArgs {
+  @TypeGraphQLField(() => [FeaturedVideoCreateInput])
+  data!: FeaturedVideoCreateInput[];
+}
+
+@ArgsType()
+export class FeaturedVideoUpdateArgs {
+  @TypeGraphQLField() data!: FeaturedVideoUpdateInput;
+  @TypeGraphQLField() where!: FeaturedVideoWhereUniqueInput;
+}
+
+export enum VideoOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  channelId_ASC = "channelId_ASC",
+  channelId_DESC = "channelId_DESC",
+
+  categoryId_ASC = "categoryId_ASC",
+  categoryId_DESC = "categoryId_DESC",
+
+  title_ASC = "title_ASC",
+  title_DESC = "title_DESC",
+
+  description_ASC = "description_ASC",
+  description_DESC = "description_DESC",
+
+  duration_ASC = "duration_ASC",
+  duration_DESC = "duration_DESC",
+
+  thumbnailPhotoDataObjectId_ASC = "thumbnailPhotoDataObjectId_ASC",
+  thumbnailPhotoDataObjectId_DESC = "thumbnailPhotoDataObjectId_DESC",
+
+  thumbnailPhotoAvailability_ASC = "thumbnailPhotoAvailability_ASC",
+  thumbnailPhotoAvailability_DESC = "thumbnailPhotoAvailability_DESC",
+
+  languageId_ASC = "languageId_ASC",
+  languageId_DESC = "languageId_DESC",
+
+  hasMarketing_ASC = "hasMarketing_ASC",
+  hasMarketing_DESC = "hasMarketing_DESC",
+
+  publishedBeforeJoystream_ASC = "publishedBeforeJoystream_ASC",
+  publishedBeforeJoystream_DESC = "publishedBeforeJoystream_DESC",
+
+  isPublic_ASC = "isPublic_ASC",
+  isPublic_DESC = "isPublic_DESC",
+
+  isCensored_ASC = "isCensored_ASC",
+  isCensored_DESC = "isCensored_DESC",
+
+  isExplicit_ASC = "isExplicit_ASC",
+  isExplicit_DESC = "isExplicit_DESC",
+
+  licenseId_ASC = "licenseId_ASC",
+  licenseId_DESC = "licenseId_DESC",
+
+  mediaDataObjectId_ASC = "mediaDataObjectId_ASC",
+  mediaDataObjectId_DESC = "mediaDataObjectId_DESC",
+
+  mediaAvailability_ASC = "mediaAvailability_ASC",
+  mediaAvailability_DESC = "mediaAvailability_DESC",
+
+  mediaMetadataId_ASC = "mediaMetadataId_ASC",
+  mediaMetadataId_DESC = "mediaMetadataId_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC",
+
+  isFeatured_ASC = "isFeatured_ASC",
+  isFeatured_DESC = "isFeatured_DESC"
+}
+
+registerEnumType(VideoOrderByEnum, {
+  name: "VideoOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class VideoWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  channelId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  channelId_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  categoryId_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  title_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  title_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  description_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  description_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  duration_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  duration_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  duration_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  duration_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  duration_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  duration_in?: number[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  thumbnailPhotoDataObjectId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  thumbnailPhotoDataObjectId_in?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  thumbnailPhotoAvailability_eq?: AssetAvailability;
+
+  @TypeGraphQLField(() => [AssetAvailability], { nullable: true })
+  thumbnailPhotoAvailability_in?: AssetAvailability[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  languageId_in?: string[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  hasMarketing_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  hasMarketing_in?: Boolean[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream_eq?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream_lt?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream_lte?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream_gt?: DateTimeString;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream_gte?: DateTimeString;
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isPublic_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isPublic_in?: Boolean[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isCensored_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isCensored_in?: Boolean[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isExplicit_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isExplicit_in?: Boolean[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  licenseId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  licenseId_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaDataObjectId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  mediaDataObjectId_in?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  mediaAvailability_eq?: AssetAvailability;
+
+  @TypeGraphQLField(() => [AssetAvailability], { nullable: true })
+  mediaAvailability_in?: AssetAvailability[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaMetadataId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  mediaMetadataId_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isFeatured_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isFeatured_in?: Boolean[];
+}
+
+@TypeGraphQLInputType()
+export class VideoWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class VideoCreateInput {
+  @TypeGraphQLField(() => ID)
+  channelId!: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  duration?: number;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  thumbnailPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String])
+  thumbnailPhotoUrls!: string[];
+
+  @TypeGraphQLField(() => AssetAvailability)
+  thumbnailPhotoAvailability!: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  hasMarketing?: boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream?: DateTimeString;
+
+  @TypeGraphQLField({ nullable: true })
+  isPublic?: boolean;
+
+  @TypeGraphQLField()
+  isCensored!: boolean;
+
+  @TypeGraphQLField({ nullable: true })
+  isExplicit?: boolean;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  licenseId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String])
+  mediaUrls!: string[];
+
+  @TypeGraphQLField(() => AssetAvailability)
+  mediaAvailability!: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaMetadataId?: string;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+
+  @TypeGraphQLField()
+  isFeatured!: boolean;
+}
+
+@TypeGraphQLInputType()
+export class VideoUpdateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  channelId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  duration?: number;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  thumbnailPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  thumbnailPhotoUrls?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  thumbnailPhotoAvailability?: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  hasMarketing?: boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  publishedBeforeJoystream?: DateTimeString;
+
+  @TypeGraphQLField({ nullable: true })
+  isPublic?: boolean;
+
+  @TypeGraphQLField({ nullable: true })
+  isCensored?: boolean;
+
+  @TypeGraphQLField({ nullable: true })
+  isExplicit?: boolean;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  licenseId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  mediaUrls?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  mediaAvailability?: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  mediaMetadataId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  isFeatured?: boolean;
+}
+
+@ArgsType()
+export class VideoWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => VideoWhereInput, { nullable: true })
+  where?: VideoWhereInput;
+
+  @TypeGraphQLField(() => VideoOrderByEnum, { nullable: true })
+  orderBy?: VideoOrderByEnum;
+}
+
+@ArgsType()
+export class VideoCreateManyArgs {
+  @TypeGraphQLField(() => [VideoCreateInput])
+  data!: VideoCreateInput[];
+}
+
+@ArgsType()
+export class VideoUpdateArgs {
+  @TypeGraphQLField() data!: VideoUpdateInput;
+  @TypeGraphQLField() where!: VideoWhereUniqueInput;
+}
+
+export enum DataObjectOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  addedAt_ASC = "addedAt_ASC",
+  addedAt_DESC = "addedAt_DESC",
+
+  typeId_ASC = "typeId_ASC",
+  typeId_DESC = "typeId_DESC",
+
+  size_ASC = "size_ASC",
+  size_DESC = "size_DESC",
+
+  liaisonId_ASC = "liaisonId_ASC",
+  liaisonId_DESC = "liaisonId_DESC",
+
+  liaisonJudgement_ASC = "liaisonJudgement_ASC",
+  liaisonJudgement_DESC = "liaisonJudgement_DESC",
+
+  ipfsContentId_ASC = "ipfsContentId_ASC",
+  ipfsContentId_DESC = "ipfsContentId_DESC",
+
+  joystreamContentId_ASC = "joystreamContentId_ASC",
+  joystreamContentId_DESC = "joystreamContentId_DESC"
+}
+
+registerEnumType(DataObjectOrderByEnum, {
+  name: "DataObjectOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class DataObjectWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true })
+  owner_json?: JsonObject;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  addedAt_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  addedAt_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  addedAt_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  addedAt_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  addedAt_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  addedAt_in?: number[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  typeId_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  typeId_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  typeId_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  typeId_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  typeId_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  typeId_in?: number[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  size_in?: BN[];
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId_eq?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId_gt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId_gte?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId_lt?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId_lte?: BN;
+
+  @TypeGraphQLField(() => [BigInt], { nullable: true })
+  liaisonId_in?: BN[];
+
+  @TypeGraphQLField(() => LiaisonJudgement, { nullable: true })
+  liaisonJudgement_eq?: LiaisonJudgement;
+
+  @TypeGraphQLField(() => [LiaisonJudgement], { nullable: true })
+  liaisonJudgement_in?: LiaisonJudgement[];
+
+  @TypeGraphQLField({ nullable: true })
+  ipfsContentId_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  ipfsContentId_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  ipfsContentId_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  ipfsContentId_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  ipfsContentId_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  joystreamContentId_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  joystreamContentId_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  joystreamContentId_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  joystreamContentId_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  joystreamContentId_in?: string[];
+}
+
+@TypeGraphQLInputType()
+export class DataObjectWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectCreateInput {
+  @TypeGraphQLField(() => GraphQLJSONObject)
+  owner!: JsonObject;
+
+  @TypeGraphQLField()
+  addedAt!: number;
+
+  @TypeGraphQLField()
+  typeId!: number;
+
+  @TypeGraphQLField(() => BigInt)
+  size!: BN;
+
+  @TypeGraphQLField(() => BigInt)
+  liaisonId!: BN;
+
+  @TypeGraphQLField(() => LiaisonJudgement)
+  liaisonJudgement!: LiaisonJudgement;
+
+  @TypeGraphQLField()
+  ipfsContentId!: string;
+
+  @TypeGraphQLField()
+  joystreamContentId!: string;
+}
+
+@TypeGraphQLInputType()
+export class DataObjectUpdateInput {
+  @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true })
+  owner?: JsonObject;
+
+  @TypeGraphQLField({ nullable: true })
+  addedAt?: number;
+
+  @TypeGraphQLField({ nullable: true })
+  typeId?: number;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  size?: BN;
+
+  @TypeGraphQLField(() => BigInt, { nullable: true })
+  liaisonId?: BN;
+
+  @TypeGraphQLField(() => LiaisonJudgement, { nullable: true })
+  liaisonJudgement?: LiaisonJudgement;
+
+  @TypeGraphQLField({ nullable: true })
+  ipfsContentId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  joystreamContentId?: string;
+}
+
+@ArgsType()
+export class DataObjectWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => DataObjectWhereInput, { nullable: true })
+  where?: DataObjectWhereInput;
+
+  @TypeGraphQLField(() => DataObjectOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOrderByEnum;
+}
+
+@ArgsType()
+export class DataObjectCreateManyArgs {
+  @TypeGraphQLField(() => [DataObjectCreateInput])
+  data!: DataObjectCreateInput[];
+}
+
+@ArgsType()
+export class DataObjectUpdateArgs {
+  @TypeGraphQLField() data!: DataObjectUpdateInput;
+  @TypeGraphQLField() where!: DataObjectWhereUniqueInput;
+}
+
+export enum ChannelOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  ownerMemberId_ASC = "ownerMemberId_ASC",
+  ownerMemberId_DESC = "ownerMemberId_DESC",
+
+  ownerCuratorGroupId_ASC = "ownerCuratorGroupId_ASC",
+  ownerCuratorGroupId_DESC = "ownerCuratorGroupId_DESC",
+
+  categoryId_ASC = "categoryId_ASC",
+  categoryId_DESC = "categoryId_DESC",
+
+  rewardAccount_ASC = "rewardAccount_ASC",
+  rewardAccount_DESC = "rewardAccount_DESC",
+
+  title_ASC = "title_ASC",
+  title_DESC = "title_DESC",
+
+  description_ASC = "description_ASC",
+  description_DESC = "description_DESC",
+
+  coverPhotoDataObjectId_ASC = "coverPhotoDataObjectId_ASC",
+  coverPhotoDataObjectId_DESC = "coverPhotoDataObjectId_DESC",
+
+  coverPhotoAvailability_ASC = "coverPhotoAvailability_ASC",
+  coverPhotoAvailability_DESC = "coverPhotoAvailability_DESC",
+
+  avatarPhotoDataObjectId_ASC = "avatarPhotoDataObjectId_ASC",
+  avatarPhotoDataObjectId_DESC = "avatarPhotoDataObjectId_DESC",
+
+  avatarPhotoAvailability_ASC = "avatarPhotoAvailability_ASC",
+  avatarPhotoAvailability_DESC = "avatarPhotoAvailability_DESC",
+
+  isPublic_ASC = "isPublic_ASC",
+  isPublic_DESC = "isPublic_DESC",
+
+  isCensored_ASC = "isCensored_ASC",
+  isCensored_DESC = "isCensored_DESC",
+
+  languageId_ASC = "languageId_ASC",
+  languageId_DESC = "languageId_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC"
+}
+
+registerEnumType(ChannelOrderByEnum, {
+  name: "ChannelOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class ChannelWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerMemberId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  ownerMemberId_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerCuratorGroupId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  ownerCuratorGroupId_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  categoryId_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  rewardAccount_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  title_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  title_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  description_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  description_in?: string[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  coverPhotoDataObjectId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  coverPhotoDataObjectId_in?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  coverPhotoAvailability_eq?: AssetAvailability;
+
+  @TypeGraphQLField(() => [AssetAvailability], { nullable: true })
+  coverPhotoAvailability_in?: AssetAvailability[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  avatarPhotoDataObjectId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  avatarPhotoDataObjectId_in?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  avatarPhotoAvailability_eq?: AssetAvailability;
+
+  @TypeGraphQLField(() => [AssetAvailability], { nullable: true })
+  avatarPhotoAvailability_in?: AssetAvailability[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isPublic_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isPublic_in?: Boolean[];
+
+  @TypeGraphQLField(() => Boolean, { nullable: true })
+  isCensored_eq?: Boolean;
+
+  @TypeGraphQLField(() => [Boolean], { nullable: true })
+  isCensored_in?: Boolean[];
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  languageId_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class ChannelWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class ChannelCreateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerMemberId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerCuratorGroupId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  coverPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String])
+  coverPhotoUrls!: string[];
+
+  @TypeGraphQLField(() => AssetAvailability)
+  coverPhotoAvailability!: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  avatarPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String])
+  avatarPhotoUrls!: string[];
+
+  @TypeGraphQLField(() => AssetAvailability)
+  avatarPhotoAvailability!: AssetAvailability;
+
+  @TypeGraphQLField({ nullable: true })
+  isPublic?: boolean;
+
+  @TypeGraphQLField()
+  isCensored!: boolean;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId?: string;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+}
+
+@TypeGraphQLInputType()
+export class ChannelUpdateInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerMemberId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  ownerCuratorGroupId?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  categoryId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  rewardAccount?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  title?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  description?: string;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  coverPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  coverPhotoUrls?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  coverPhotoAvailability?: AssetAvailability;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  avatarPhotoDataObjectId?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  avatarPhotoUrls?: string[];
+
+  @TypeGraphQLField(() => AssetAvailability, { nullable: true })
+  avatarPhotoAvailability?: AssetAvailability;
+
+  @TypeGraphQLField({ nullable: true })
+  isPublic?: boolean;
+
+  @TypeGraphQLField({ nullable: true })
+  isCensored?: boolean;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  languageId?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+}
+
+@ArgsType()
+export class ChannelWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => ChannelWhereInput, { nullable: true })
+  where?: ChannelWhereInput;
+
+  @TypeGraphQLField(() => ChannelOrderByEnum, { nullable: true })
+  orderBy?: ChannelOrderByEnum;
+}
+
+@ArgsType()
+export class ChannelCreateManyArgs {
+  @TypeGraphQLField(() => [ChannelCreateInput])
+  data!: ChannelCreateInput[];
+}
+
+@ArgsType()
+export class ChannelUpdateArgs {
+  @TypeGraphQLField() data!: ChannelUpdateInput;
+  @TypeGraphQLField() where!: ChannelWhereUniqueInput;
+}
+
+export enum ChannelCategoryOrderByEnum {
+  createdAt_ASC = "createdAt_ASC",
+  createdAt_DESC = "createdAt_DESC",
+
+  updatedAt_ASC = "updatedAt_ASC",
+  updatedAt_DESC = "updatedAt_DESC",
+
+  deletedAt_ASC = "deletedAt_ASC",
+  deletedAt_DESC = "deletedAt_DESC",
+
+  name_ASC = "name_ASC",
+  name_DESC = "name_DESC",
+
+  happenedIn_ASC = "happenedIn_ASC",
+  happenedIn_DESC = "happenedIn_DESC"
+}
+
+registerEnumType(ChannelCategoryOrderByEnum, {
+  name: "ChannelCategoryOrderByInput"
+});
+
+@TypeGraphQLInputType()
+export class ChannelCategoryWhereInput {
+  @TypeGraphQLField(() => ID, { nullable: true })
+  id_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  id_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  createdAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  createdById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  createdById_in?: string[];
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  updatedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  updatedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  updatedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  deletedAt_all?: Boolean;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_eq?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_lte?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gt?: Date;
+
+  @TypeGraphQLField(() => DateTime, { nullable: true })
+  deletedAt_gte?: Date;
+
+  @TypeGraphQLField(() => ID, { nullable: true })
+  deletedById_eq?: string;
+
+  @TypeGraphQLField(() => [ID], { nullable: true })
+  deletedById_in?: string[];
+
+  @TypeGraphQLField({ nullable: true })
+  name_eq?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_contains?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_startsWith?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  name_endsWith?: string;
+
+  @TypeGraphQLField(() => [String], { nullable: true })
+  name_in?: string[];
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_eq?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_gte?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lt?: number;
+
+  @TypeGraphQLField(() => Int, { nullable: true })
+  happenedIn_lte?: number;
+
+  @TypeGraphQLField(() => [Int], { nullable: true })
+  happenedIn_in?: number[];
+}
+
+@TypeGraphQLInputType()
+export class ChannelCategoryWhereUniqueInput {
+  @TypeGraphQLField(() => ID)
+  id?: string;
+}
+
+@TypeGraphQLInputType()
+export class ChannelCategoryCreateInput {
+  @TypeGraphQLField({ nullable: true })
+  name?: string;
+
+  @TypeGraphQLField()
+  happenedIn!: number;
+}
+
+@TypeGraphQLInputType()
+export class ChannelCategoryUpdateInput {
+  @TypeGraphQLField({ nullable: true })
+  name?: string;
+
+  @TypeGraphQLField({ nullable: true })
+  happenedIn?: number;
+}
+
+@ArgsType()
+export class ChannelCategoryWhereArgs extends PaginationArgs {
+  @TypeGraphQLField(() => ChannelCategoryWhereInput, { nullable: true })
+  where?: ChannelCategoryWhereInput;
+
+  @TypeGraphQLField(() => ChannelCategoryOrderByEnum, { nullable: true })
+  orderBy?: ChannelCategoryOrderByEnum;
+}
+
+@ArgsType()
+export class ChannelCategoryCreateManyArgs {
+  @TypeGraphQLField(() => [ChannelCategoryCreateInput])
+  data!: ChannelCategoryCreateInput[];
+}
+
+@ArgsType()
+export class ChannelCategoryUpdateArgs {
+  @TypeGraphQLField() data!: ChannelCategoryUpdateInput;
+  @TypeGraphQLField() where!: ChannelCategoryWhereUniqueInput;
+}

+ 1 - 0
query-node/generated/graphql-server/generated/index.ts

@@ -0,0 +1 @@
+export * from './classes';

+ 3 - 0
query-node/generated/graphql-server/generated/ormconfig.ts

@@ -0,0 +1,3 @@
+import { getBaseConfig } from 'warthog';
+
+module.exports = getBaseConfig();

+ 2053 - 0
query-node/generated/graphql-server/generated/schema.graphql

@@ -0,0 +1,2053 @@
+enum AssetAvailability {
+  ACCEPTED
+  PENDING
+  INVALID
+}
+
+interface BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+}
+
+type BaseModel implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+}
+
+type BaseModelUUID implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+}
+
+input BaseWhereInput {
+  id_eq: String
+  id_in: [String!]
+  createdAt_eq: String
+  createdAt_lt: String
+  createdAt_lte: String
+  createdAt_gt: String
+  createdAt_gte: String
+  createdById_eq: String
+  updatedAt_eq: String
+  updatedAt_lt: String
+  updatedAt_lte: String
+  updatedAt_gt: String
+  updatedAt_gte: String
+  updatedById_eq: String
+  deletedAt_all: Boolean
+  deletedAt_eq: String
+  deletedAt_lt: String
+  deletedAt_lte: String
+  deletedAt_gt: String
+  deletedAt_gte: String
+  deletedById_eq: String
+}
+
+"""GraphQL representation of BigInt"""
+scalar BigInt
+
+type Channel implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+  ownerMember: Membership
+  ownerMemberId: String
+  ownerCuratorGroup: CuratorGroup
+  ownerCuratorGroupId: String
+  category: ChannelCategory
+  categoryId: String
+
+  """Reward account where revenue is sent if set."""
+  rewardAccount: String
+
+  """The title of the Channel"""
+  title: String
+
+  """The description of a Channel"""
+  description: String
+  coverPhotoDataObject: DataObject
+  coverPhotoDataObjectId: String
+
+  """URLs where the asset content can be accessed (if any)"""
+  coverPhotoUrls: [String!]!
+
+  """Availability meta information"""
+  coverPhotoAvailability: AssetAvailability!
+  avatarPhotoDataObject: DataObject
+  avatarPhotoDataObjectId: String
+
+  """URLs where the asset content can be accessed (if any)"""
+  avatarPhotoUrls: [String!]!
+
+  """Availability meta information"""
+  avatarPhotoAvailability: AssetAvailability!
+
+  """Flag signaling whether a channel is public."""
+  isPublic: Boolean
+
+  """Flag signaling whether a channel is censored."""
+  isCensored: Boolean!
+  language: Language
+  languageId: String
+  videos: [Video!]!
+  happenedIn: Int!
+}
+
+type ChannelCategoriesByNameFTSOutput {
+  item: ChannelCategoriesByNameSearchResult!
+  rank: Float!
+  isTypeOf: String!
+  highlight: String!
+}
+
+union ChannelCategoriesByNameSearchResult = ChannelCategory
+
+"""Category of media channel"""
+type ChannelCategory implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """The name of the category"""
+  name: String
+  channels: [Channel!]!
+  happenedIn: Int!
+}
+
+type ChannelCategoryConnection {
+  totalCount: Int!
+  edges: [ChannelCategoryEdge!]!
+  pageInfo: PageInfo!
+}
+
+input ChannelCategoryCreateInput {
+  name: String
+  happenedIn: Float!
+}
+
+type ChannelCategoryEdge {
+  node: ChannelCategory!
+  cursor: String!
+}
+
+enum ChannelCategoryOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  name_ASC
+  name_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+}
+
+input ChannelCategoryUpdateInput {
+  name: String
+  happenedIn: Float
+}
+
+input ChannelCategoryWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  name_eq: String
+  name_contains: String
+  name_startsWith: String
+  name_endsWith: String
+  name_in: [String!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+}
+
+input ChannelCategoryWhereUniqueInput {
+  id: ID!
+}
+
+type ChannelConnection {
+  totalCount: Int!
+  edges: [ChannelEdge!]!
+  pageInfo: PageInfo!
+}
+
+input ChannelCreateInput {
+  ownerMemberId: ID
+  ownerCuratorGroupId: ID
+  categoryId: ID
+  rewardAccount: String
+  title: String
+  description: String
+  coverPhotoDataObjectId: ID
+  coverPhotoUrls: [String!]!
+  coverPhotoAvailability: AssetAvailability!
+  avatarPhotoDataObjectId: ID
+  avatarPhotoUrls: [String!]!
+  avatarPhotoAvailability: AssetAvailability!
+  isPublic: Boolean
+  isCensored: Boolean!
+  languageId: ID
+  happenedIn: Float!
+}
+
+type ChannelEdge {
+  node: Channel!
+  cursor: String!
+}
+
+enum ChannelOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  ownerMemberId_ASC
+  ownerMemberId_DESC
+  ownerCuratorGroupId_ASC
+  ownerCuratorGroupId_DESC
+  categoryId_ASC
+  categoryId_DESC
+  rewardAccount_ASC
+  rewardAccount_DESC
+  title_ASC
+  title_DESC
+  description_ASC
+  description_DESC
+  coverPhotoDataObjectId_ASC
+  coverPhotoDataObjectId_DESC
+  coverPhotoAvailability_ASC
+  coverPhotoAvailability_DESC
+  avatarPhotoDataObjectId_ASC
+  avatarPhotoDataObjectId_DESC
+  avatarPhotoAvailability_ASC
+  avatarPhotoAvailability_DESC
+  isPublic_ASC
+  isPublic_DESC
+  isCensored_ASC
+  isCensored_DESC
+  languageId_ASC
+  languageId_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+}
+
+input ChannelUpdateInput {
+  ownerMemberId: ID
+  ownerCuratorGroupId: ID
+  categoryId: ID
+  rewardAccount: String
+  title: String
+  description: String
+  coverPhotoDataObjectId: ID
+  coverPhotoUrls: [String!]
+  coverPhotoAvailability: AssetAvailability
+  avatarPhotoDataObjectId: ID
+  avatarPhotoUrls: [String!]
+  avatarPhotoAvailability: AssetAvailability
+  isPublic: Boolean
+  isCensored: Boolean
+  languageId: ID
+  happenedIn: Float
+}
+
+input ChannelWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  ownerMemberId_eq: ID
+  ownerMemberId_in: [ID!]
+  ownerCuratorGroupId_eq: ID
+  ownerCuratorGroupId_in: [ID!]
+  categoryId_eq: ID
+  categoryId_in: [ID!]
+  rewardAccount_eq: String
+  rewardAccount_contains: String
+  rewardAccount_startsWith: String
+  rewardAccount_endsWith: String
+  rewardAccount_in: [String!]
+  title_eq: String
+  title_contains: String
+  title_startsWith: String
+  title_endsWith: String
+  title_in: [String!]
+  description_eq: String
+  description_contains: String
+  description_startsWith: String
+  description_endsWith: String
+  description_in: [String!]
+  coverPhotoDataObjectId_eq: ID
+  coverPhotoDataObjectId_in: [ID!]
+  coverPhotoAvailability_eq: AssetAvailability
+  coverPhotoAvailability_in: [AssetAvailability!]
+  avatarPhotoDataObjectId_eq: ID
+  avatarPhotoDataObjectId_in: [ID!]
+  avatarPhotoAvailability_eq: AssetAvailability
+  avatarPhotoAvailability_in: [AssetAvailability!]
+  isPublic_eq: Boolean
+  isPublic_in: [Boolean!]
+  isCensored_eq: Boolean
+  isCensored_in: [Boolean!]
+  languageId_eq: ID
+  languageId_in: [ID!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+}
+
+input ChannelWhereUniqueInput {
+  id: ID!
+}
+
+type CuratorGroup implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """Curators belonging to this group"""
+  curatorIds: [BigInt!]!
+
+  """Is group active or not"""
+  isActive: Boolean!
+  channels: [Channel!]!
+}
+
+type CuratorGroupConnection {
+  totalCount: Int!
+  edges: [CuratorGroupEdge!]!
+  pageInfo: PageInfo!
+}
+
+input CuratorGroupCreateInput {
+  curatorIds: [BigInt!]!
+  isActive: Boolean!
+}
+
+type CuratorGroupEdge {
+  node: CuratorGroup!
+  cursor: String!
+}
+
+enum CuratorGroupOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  isActive_ASC
+  isActive_DESC
+}
+
+input CuratorGroupUpdateInput {
+  curatorIds: [BigInt!]
+  isActive: Boolean
+}
+
+input CuratorGroupWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  isActive_eq: Boolean
+  isActive_in: [Boolean!]
+}
+
+input CuratorGroupWhereUniqueInput {
+  id: ID!
+}
+
+"""Manages content ids, type and storage provider decision about it"""
+type DataObject implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """Content owner"""
+  owner: DataObjectOwner!
+
+  """Content added at"""
+  addedAt: Int!
+
+  """Content type id"""
+  typeId: Int!
+
+  """Content size in bytes"""
+  size: BigInt!
+
+  """Storage provider id of the liaison"""
+  liaisonId: BigInt!
+
+  """Storage provider as liaison judgment"""
+  liaisonJudgement: LiaisonJudgement!
+
+  """IPFS content id"""
+  ipfsContentId: String!
+
+  """Joystream runtime content"""
+  joystreamContentId: String!
+  channelcoverPhotoDataObject: [Channel!]
+  channelavatarPhotoDataObject: [Channel!]
+  videothumbnailPhotoDataObject: [Video!]
+  videomediaDataObject: [Video!]
+}
+
+type DataObjectConnection {
+  totalCount: Int!
+  edges: [DataObjectEdge!]!
+  pageInfo: PageInfo!
+}
+
+input DataObjectCreateInput {
+  owner: JSONObject!
+  addedAt: Float!
+  typeId: Float!
+  size: BigInt!
+  liaisonId: BigInt!
+  liaisonJudgement: LiaisonJudgement!
+  ipfsContentId: String!
+  joystreamContentId: String!
+}
+
+type DataObjectEdge {
+  node: DataObject!
+  cursor: String!
+}
+
+enum DataObjectOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  addedAt_ASC
+  addedAt_DESC
+  typeId_ASC
+  typeId_DESC
+  size_ASC
+  size_DESC
+  liaisonId_ASC
+  liaisonId_DESC
+  liaisonJudgement_ASC
+  liaisonJudgement_DESC
+  ipfsContentId_ASC
+  ipfsContentId_DESC
+  joystreamContentId_ASC
+  joystreamContentId_DESC
+}
+
+union DataObjectOwner = DataObjectOwnerMember | DataObjectOwnerChannel | DataObjectOwnerDao | DataObjectOwnerCouncil | DataObjectOwnerWorkingGroup
+
+type DataObjectOwnerChannel {
+  """Channel identifier"""
+  channel: BigInt!
+
+  """Variant needs to have at least one property. This value is not used."""
+  dummy: Int
+}
+
+input DataObjectOwnerChannelCreateInput {
+  channel: BigInt!
+  dummy: Float
+}
+
+input DataObjectOwnerChannelUpdateInput {
+  channel: BigInt
+  dummy: Float
+}
+
+input DataObjectOwnerChannelWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  channel_eq: BigInt
+  channel_gt: BigInt
+  channel_gte: BigInt
+  channel_lt: BigInt
+  channel_lte: BigInt
+  channel_in: [BigInt!]
+  dummy_eq: Int
+  dummy_gt: Int
+  dummy_gte: Int
+  dummy_lt: Int
+  dummy_lte: Int
+  dummy_in: [Int!]
+}
+
+input DataObjectOwnerChannelWhereUniqueInput {
+  id: ID!
+}
+
+type DataObjectOwnerCouncil {
+  """Variant needs to have at least one property. This value is not used."""
+  dummy: Int
+}
+
+input DataObjectOwnerCouncilCreateInput {
+  dummy: Float
+}
+
+input DataObjectOwnerCouncilUpdateInput {
+  dummy: Float
+}
+
+input DataObjectOwnerCouncilWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  dummy_eq: Int
+  dummy_gt: Int
+  dummy_gte: Int
+  dummy_lt: Int
+  dummy_lte: Int
+  dummy_in: [Int!]
+}
+
+input DataObjectOwnerCouncilWhereUniqueInput {
+  id: ID!
+}
+
+type DataObjectOwnerDao {
+  """DAO identifier"""
+  dao: BigInt!
+}
+
+input DataObjectOwnerDaoCreateInput {
+  dao: BigInt!
+}
+
+input DataObjectOwnerDaoUpdateInput {
+  dao: BigInt
+}
+
+input DataObjectOwnerDaoWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  dao_eq: BigInt
+  dao_gt: BigInt
+  dao_gte: BigInt
+  dao_lt: BigInt
+  dao_lte: BigInt
+  dao_in: [BigInt!]
+}
+
+input DataObjectOwnerDaoWhereUniqueInput {
+  id: ID!
+}
+
+type DataObjectOwnerMember {
+  """Member identifier"""
+  member: BigInt!
+
+  """Variant needs to have at least one property. This value is not used."""
+  dummy: Int
+}
+
+input DataObjectOwnerMemberCreateInput {
+  member: BigInt!
+  dummy: Float
+}
+
+input DataObjectOwnerMemberUpdateInput {
+  member: BigInt
+  dummy: Float
+}
+
+input DataObjectOwnerMemberWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  member_eq: BigInt
+  member_gt: BigInt
+  member_gte: BigInt
+  member_lt: BigInt
+  member_lte: BigInt
+  member_in: [BigInt!]
+  dummy_eq: Int
+  dummy_gt: Int
+  dummy_gte: Int
+  dummy_lt: Int
+  dummy_lte: Int
+  dummy_in: [Int!]
+}
+
+input DataObjectOwnerMemberWhereUniqueInput {
+  id: ID!
+}
+
+type DataObjectOwnerWorkingGroup {
+  """Variant needs to have at least one property. This value is not used."""
+  dummy: Int
+}
+
+input DataObjectOwnerWorkingGroupCreateInput {
+  dummy: Float
+}
+
+input DataObjectOwnerWorkingGroupUpdateInput {
+  dummy: Float
+}
+
+input DataObjectOwnerWorkingGroupWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  dummy_eq: Int
+  dummy_gt: Int
+  dummy_gte: Int
+  dummy_lt: Int
+  dummy_lte: Int
+  dummy_in: [Int!]
+}
+
+input DataObjectOwnerWorkingGroupWhereUniqueInput {
+  id: ID!
+}
+
+input DataObjectUpdateInput {
+  owner: JSONObject
+  addedAt: Float
+  typeId: Float
+  size: BigInt
+  liaisonId: BigInt
+  liaisonJudgement: LiaisonJudgement
+  ipfsContentId: String
+  joystreamContentId: String
+}
+
+input DataObjectWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  owner_json: JSONObject
+  addedAt_eq: Int
+  addedAt_gt: Int
+  addedAt_gte: Int
+  addedAt_lt: Int
+  addedAt_lte: Int
+  addedAt_in: [Int!]
+  typeId_eq: Int
+  typeId_gt: Int
+  typeId_gte: Int
+  typeId_lt: Int
+  typeId_lte: Int
+  typeId_in: [Int!]
+  size_eq: BigInt
+  size_gt: BigInt
+  size_gte: BigInt
+  size_lt: BigInt
+  size_lte: BigInt
+  size_in: [BigInt!]
+  liaisonId_eq: BigInt
+  liaisonId_gt: BigInt
+  liaisonId_gte: BigInt
+  liaisonId_lt: BigInt
+  liaisonId_lte: BigInt
+  liaisonId_in: [BigInt!]
+  liaisonJudgement_eq: LiaisonJudgement
+  liaisonJudgement_in: [LiaisonJudgement!]
+  ipfsContentId_eq: String
+  ipfsContentId_contains: String
+  ipfsContentId_startsWith: String
+  ipfsContentId_endsWith: String
+  ipfsContentId_in: [String!]
+  joystreamContentId_eq: String
+  joystreamContentId_contains: String
+  joystreamContentId_startsWith: String
+  joystreamContentId_endsWith: String
+  joystreamContentId_in: [String!]
+}
+
+input DataObjectWhereUniqueInput {
+  id: ID!
+}
+
+"""
+The javascript `Date` as string. Type represents date and time as the ISO Date string.
+"""
+scalar DateTime
+
+interface DeleteResponse {
+  id: ID!
+}
+
+type FeaturedVideo implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+  video: Video!
+  videoId: String!
+}
+
+type FeaturedVideoConnection {
+  totalCount: Int!
+  edges: [FeaturedVideoEdge!]!
+  pageInfo: PageInfo!
+}
+
+input FeaturedVideoCreateInput {
+  videoId: ID!
+}
+
+type FeaturedVideoEdge {
+  node: FeaturedVideo!
+  cursor: String!
+}
+
+enum FeaturedVideoOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  videoId_ASC
+  videoId_DESC
+}
+
+input FeaturedVideoUpdateInput {
+  videoId: ID
+}
+
+input FeaturedVideoWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  videoId_eq: ID
+  videoId_in: [ID!]
+}
+
+input FeaturedVideoWhereUniqueInput {
+  id: ID!
+}
+
+"""
+The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
+"""
+scalar JSONObject
+
+type Language implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """Language identifier ISO 639-1"""
+  iso: String!
+  happenedIn: Int!
+  channellanguage: [Channel!]
+  videolanguage: [Video!]
+}
+
+type LanguageConnection {
+  totalCount: Int!
+  edges: [LanguageEdge!]!
+  pageInfo: PageInfo!
+}
+
+input LanguageCreateInput {
+  iso: String!
+  happenedIn: Float!
+}
+
+type LanguageEdge {
+  node: Language!
+  cursor: String!
+}
+
+enum LanguageOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  iso_ASC
+  iso_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+}
+
+input LanguageUpdateInput {
+  iso: String
+  happenedIn: Float
+}
+
+input LanguageWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  iso_eq: String
+  iso_contains: String
+  iso_startsWith: String
+  iso_endsWith: String
+  iso_in: [String!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+}
+
+input LanguageWhereUniqueInput {
+  id: ID!
+}
+
+enum LiaisonJudgement {
+  PENDING
+  ACCEPTED
+  REJECTED
+}
+
+type License implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """License code defined by Joystream"""
+  code: Int
+
+  """Attribution (if required by the license)"""
+  attribution: String
+
+  """Custom license content"""
+  customText: String
+  videolicense: [Video!]
+}
+
+type LicenseConnection {
+  totalCount: Int!
+  edges: [LicenseEdge!]!
+  pageInfo: PageInfo!
+}
+
+input LicenseCreateInput {
+  code: Float
+  attribution: String
+  customText: String
+}
+
+type LicenseEdge {
+  node: License!
+  cursor: String!
+}
+
+enum LicenseOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  code_ASC
+  code_DESC
+  attribution_ASC
+  attribution_DESC
+  customText_ASC
+  customText_DESC
+}
+
+input LicenseUpdateInput {
+  code: Float
+  attribution: String
+  customText: String
+}
+
+input LicenseWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  code_eq: Int
+  code_gt: Int
+  code_gte: Int
+  code_lt: Int
+  code_lte: Int
+  code_in: [Int!]
+  attribution_eq: String
+  attribution_contains: String
+  attribution_startsWith: String
+  attribution_endsWith: String
+  attribution_in: [String!]
+  customText_eq: String
+  customText_contains: String
+  customText_startsWith: String
+  customText_endsWith: String
+  customText_in: [String!]
+}
+
+input LicenseWhereUniqueInput {
+  id: ID!
+}
+
+type MembersByHandleFTSOutput {
+  item: MembersByHandleSearchResult!
+  rank: Float!
+  isTypeOf: String!
+  highlight: String!
+}
+
+union MembersByHandleSearchResult = Membership
+
+"""Stored information about a registered user"""
+type Membership implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """The unique handle chosen by member"""
+  handle: String!
+
+  """A Url to member's Avatar image"""
+  avatarUri: String
+
+  """Short text chosen by member to share information about themselves"""
+  about: String
+
+  """Member's controller account id"""
+  controllerAccount: String!
+
+  """Member's root account id"""
+  rootAccount: String!
+
+  """Blocknumber when member was registered"""
+  registeredAtBlock: Int!
+
+  """Timestamp when member was registered"""
+  registeredAtTime: DateTime!
+
+  """How the member was registered"""
+  entry: MembershipEntryMethod!
+
+  """The type of subscription the member has purchased if any."""
+  subscription: BigInt
+  channels: [Channel!]!
+}
+
+type MembershipConnection {
+  totalCount: Int!
+  edges: [MembershipEdge!]!
+  pageInfo: PageInfo!
+}
+
+input MembershipCreateInput {
+  handle: String!
+  avatarUri: String
+  about: String
+  controllerAccount: String!
+  rootAccount: String!
+  registeredAtBlock: Float!
+  registeredAtTime: DateTime!
+  entry: MembershipEntryMethod!
+  subscription: BigInt
+}
+
+type MembershipEdge {
+  node: Membership!
+  cursor: String!
+}
+
+enum MembershipEntryMethod {
+  PAID
+  SCREENING
+  GENESIS
+}
+
+enum MembershipOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  handle_ASC
+  handle_DESC
+  avatarUri_ASC
+  avatarUri_DESC
+  about_ASC
+  about_DESC
+  controllerAccount_ASC
+  controllerAccount_DESC
+  rootAccount_ASC
+  rootAccount_DESC
+  registeredAtBlock_ASC
+  registeredAtBlock_DESC
+  registeredAtTime_ASC
+  registeredAtTime_DESC
+  entry_ASC
+  entry_DESC
+  subscription_ASC
+  subscription_DESC
+}
+
+input MembershipUpdateInput {
+  handle: String
+  avatarUri: String
+  about: String
+  controllerAccount: String
+  rootAccount: String
+  registeredAtBlock: Float
+  registeredAtTime: DateTime
+  entry: MembershipEntryMethod
+  subscription: BigInt
+}
+
+input MembershipWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  handle_eq: String
+  handle_contains: String
+  handle_startsWith: String
+  handle_endsWith: String
+  handle_in: [String!]
+  avatarUri_eq: String
+  avatarUri_contains: String
+  avatarUri_startsWith: String
+  avatarUri_endsWith: String
+  avatarUri_in: [String!]
+  about_eq: String
+  about_contains: String
+  about_startsWith: String
+  about_endsWith: String
+  about_in: [String!]
+  controllerAccount_eq: String
+  controllerAccount_contains: String
+  controllerAccount_startsWith: String
+  controllerAccount_endsWith: String
+  controllerAccount_in: [String!]
+  rootAccount_eq: String
+  rootAccount_contains: String
+  rootAccount_startsWith: String
+  rootAccount_endsWith: String
+  rootAccount_in: [String!]
+  registeredAtBlock_eq: Int
+  registeredAtBlock_gt: Int
+  registeredAtBlock_gte: Int
+  registeredAtBlock_lt: Int
+  registeredAtBlock_lte: Int
+  registeredAtBlock_in: [Int!]
+  registeredAtTime_eq: DateTime
+  registeredAtTime_lt: DateTime
+  registeredAtTime_lte: DateTime
+  registeredAtTime_gt: DateTime
+  registeredAtTime_gte: DateTime
+  entry_eq: MembershipEntryMethod
+  entry_in: [MembershipEntryMethod!]
+  subscription_eq: BigInt
+  subscription_gt: BigInt
+  subscription_gte: BigInt
+  subscription_lt: BigInt
+  subscription_lte: BigInt
+  subscription_in: [BigInt!]
+}
+
+input MembershipWhereUniqueInput {
+  id: ID
+  handle: String
+}
+
+type PageInfo {
+  hasNextPage: Boolean!
+  hasPreviousPage: Boolean!
+  startCursor: String
+  endCursor: String
+}
+
+type ProcessorState {
+  lastCompleteBlock: Float!
+  lastProcessedEvent: String!
+  indexerHead: Float!
+  chainHead: Float!
+}
+
+type Query {
+  channelCategories(offset: Int, limit: Int = 50, where: ChannelCategoryWhereInput, orderBy: ChannelCategoryOrderByInput): [ChannelCategory!]!
+  channelCategoryByUniqueInput(where: ChannelCategoryWhereUniqueInput!): ChannelCategory
+  channelCategoriesConnection(first: Int, after: String, last: Int, before: String, where: ChannelCategoryWhereInput, orderBy: ChannelCategoryOrderByInput): ChannelCategoryConnection!
+  channels(offset: Int, limit: Int = 50, where: ChannelWhereInput, orderBy: ChannelOrderByInput): [Channel!]!
+  channelByUniqueInput(where: ChannelWhereUniqueInput!): Channel
+  channelsConnection(first: Int, after: String, last: Int, before: String, where: ChannelWhereInput, orderBy: ChannelOrderByInput): ChannelConnection!
+  curatorGroups(offset: Int, limit: Int = 50, where: CuratorGroupWhereInput, orderBy: CuratorGroupOrderByInput): [CuratorGroup!]!
+  curatorGroupByUniqueInput(where: CuratorGroupWhereUniqueInput!): CuratorGroup
+  curatorGroupsConnection(first: Int, after: String, last: Int, before: String, where: CuratorGroupWhereInput, orderBy: CuratorGroupOrderByInput): CuratorGroupConnection!
+  dataObjects(offset: Int, limit: Int = 50, where: DataObjectWhereInput, orderBy: DataObjectOrderByInput): [DataObject!]!
+  dataObjectByUniqueInput(where: DataObjectWhereUniqueInput!): DataObject
+  dataObjectsConnection(first: Int, after: String, last: Int, before: String, where: DataObjectWhereInput, orderBy: DataObjectOrderByInput): DataObjectConnection!
+  featuredVideos(offset: Int, limit: Int = 50, where: FeaturedVideoWhereInput, orderBy: FeaturedVideoOrderByInput): [FeaturedVideo!]!
+  featuredVideoByUniqueInput(where: FeaturedVideoWhereUniqueInput!): FeaturedVideo
+  featuredVideosConnection(first: Int, after: String, last: Int, before: String, where: FeaturedVideoWhereInput, orderBy: FeaturedVideoOrderByInput): FeaturedVideoConnection!
+  languages(offset: Int, limit: Int = 50, where: LanguageWhereInput, orderBy: LanguageOrderByInput): [Language!]!
+  languageByUniqueInput(where: LanguageWhereUniqueInput!): Language
+  languagesConnection(first: Int, after: String, last: Int, before: String, where: LanguageWhereInput, orderBy: LanguageOrderByInput): LanguageConnection!
+  licenses(offset: Int, limit: Int = 50, where: LicenseWhereInput, orderBy: LicenseOrderByInput): [License!]!
+  licenseByUniqueInput(where: LicenseWhereUniqueInput!): License
+  licensesConnection(first: Int, after: String, last: Int, before: String, where: LicenseWhereInput, orderBy: LicenseOrderByInput): LicenseConnection!
+  memberships(offset: Int, limit: Int = 50, where: MembershipWhereInput, orderBy: MembershipOrderByInput): [Membership!]!
+  membershipByUniqueInput(where: MembershipWhereUniqueInput!): Membership
+  membershipsConnection(first: Int, after: String, last: Int, before: String, where: MembershipWhereInput, orderBy: MembershipOrderByInput): MembershipConnection!
+  channelCategoriesByName(whereChannelCategory: ChannelCategoryWhereInput, skip: Int = 0, limit: Int = 5, text: String!): [ChannelCategoriesByNameFTSOutput!]!
+  membersByHandle(whereMembership: MembershipWhereInput, skip: Int = 0, limit: Int = 5, text: String!): [MembersByHandleFTSOutput!]!
+  search(whereVideo: VideoWhereInput, whereChannel: ChannelWhereInput, skip: Int = 0, limit: Int = 5, text: String!): [SearchFTSOutput!]!
+  videoCategoriesByName(whereVideoCategory: VideoCategoryWhereInput, skip: Int = 0, limit: Int = 5, text: String!): [VideoCategoriesByNameFTSOutput!]!
+  videoCategories(offset: Int, limit: Int = 50, where: VideoCategoryWhereInput, orderBy: VideoCategoryOrderByInput): [VideoCategory!]!
+  videoCategoryByUniqueInput(where: VideoCategoryWhereUniqueInput!): VideoCategory
+  videoCategoriesConnection(first: Int, after: String, last: Int, before: String, where: VideoCategoryWhereInput, orderBy: VideoCategoryOrderByInput): VideoCategoryConnection!
+  videoMediaEncodings(offset: Int, limit: Int = 50, where: VideoMediaEncodingWhereInput, orderBy: VideoMediaEncodingOrderByInput): [VideoMediaEncoding!]!
+  videoMediaEncodingByUniqueInput(where: VideoMediaEncodingWhereUniqueInput!): VideoMediaEncoding
+  videoMediaEncodingsConnection(first: Int, after: String, last: Int, before: String, where: VideoMediaEncodingWhereInput, orderBy: VideoMediaEncodingOrderByInput): VideoMediaEncodingConnection!
+  videoMediaMetadata(offset: Int, limit: Int = 50, where: VideoMediaMetadataWhereInput, orderBy: VideoMediaMetadataOrderByInput): [VideoMediaMetadata!]!
+  videoMediaMetadataByUniqueInput(where: VideoMediaMetadataWhereUniqueInput!): VideoMediaMetadata
+  videoMediaMetadataConnection(first: Int, after: String, last: Int, before: String, where: VideoMediaMetadataWhereInput, orderBy: VideoMediaMetadataOrderByInput): VideoMediaMetadataConnection!
+  videos(offset: Int, limit: Int = 50, where: VideoWhereInput, orderBy: VideoOrderByInput): [Video!]!
+  videoByUniqueInput(where: VideoWhereUniqueInput!): Video
+  videosConnection(first: Int, after: String, last: Int, before: String, where: VideoWhereInput, orderBy: VideoOrderByInput): VideoConnection!
+}
+
+type SearchFTSOutput {
+  item: SearchSearchResult!
+  rank: Float!
+  isTypeOf: String!
+  highlight: String!
+}
+
+union SearchSearchResult = Channel | Video
+
+type StandardDeleteResponse {
+  id: ID!
+}
+
+type Subscription {
+  stateSubscription: ProcessorState!
+}
+
+type Video implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+  channel: Channel!
+  channelId: String!
+  category: VideoCategory
+  categoryId: String
+
+  """The title of the video"""
+  title: String
+
+  """The description of the Video"""
+  description: String
+
+  """Video duration in seconds"""
+  duration: Int
+  thumbnailPhotoDataObject: DataObject
+  thumbnailPhotoDataObjectId: String
+
+  """URLs where the asset content can be accessed (if any)"""
+  thumbnailPhotoUrls: [String!]!
+
+  """Availability meta information"""
+  thumbnailPhotoAvailability: AssetAvailability!
+  language: Language
+  languageId: String
+
+  """Whether or not Video contains marketing"""
+  hasMarketing: Boolean
+
+  """
+  If the Video was published on other platform before beeing published on Joystream - the original publication date
+  """
+  publishedBeforeJoystream: DateTime
+
+  """Whether the Video is supposed to be publically displayed"""
+  isPublic: Boolean
+
+  """Flag signaling whether a video is censored."""
+  isCensored: Boolean!
+
+  """Whether the Video contains explicit material."""
+  isExplicit: Boolean
+  license: License
+  licenseId: String
+  mediaDataObject: DataObject
+  mediaDataObjectId: String
+
+  """URLs where the asset content can be accessed (if any)"""
+  mediaUrls: [String!]!
+
+  """Availability meta information"""
+  mediaAvailability: AssetAvailability!
+  mediaMetadata: VideoMediaMetadata
+  mediaMetadataId: String
+  happenedIn: Int!
+
+  """Is video featured or not"""
+  isFeatured: Boolean!
+  featured: FeaturedVideo
+}
+
+type VideoCategoriesByNameFTSOutput {
+  item: VideoCategoriesByNameSearchResult!
+  rank: Float!
+  isTypeOf: String!
+  highlight: String!
+}
+
+union VideoCategoriesByNameSearchResult = VideoCategory
+
+type VideoCategory implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """The name of the category"""
+  name: String
+  videos: [Video!]!
+  happenedIn: Int!
+}
+
+type VideoCategoryConnection {
+  totalCount: Int!
+  edges: [VideoCategoryEdge!]!
+  pageInfo: PageInfo!
+}
+
+input VideoCategoryCreateInput {
+  name: String
+  happenedIn: Float!
+}
+
+type VideoCategoryEdge {
+  node: VideoCategory!
+  cursor: String!
+}
+
+enum VideoCategoryOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  name_ASC
+  name_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+}
+
+input VideoCategoryUpdateInput {
+  name: String
+  happenedIn: Float
+}
+
+input VideoCategoryWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  name_eq: String
+  name_contains: String
+  name_startsWith: String
+  name_endsWith: String
+  name_in: [String!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+}
+
+input VideoCategoryWhereUniqueInput {
+  id: ID!
+}
+
+type VideoConnection {
+  totalCount: Int!
+  edges: [VideoEdge!]!
+  pageInfo: PageInfo!
+}
+
+input VideoCreateInput {
+  channelId: ID!
+  categoryId: ID
+  title: String
+  description: String
+  duration: Float
+  thumbnailPhotoDataObjectId: ID
+  thumbnailPhotoUrls: [String!]!
+  thumbnailPhotoAvailability: AssetAvailability!
+  languageId: ID
+  hasMarketing: Boolean
+  publishedBeforeJoystream: DateTime
+  isPublic: Boolean
+  isCensored: Boolean!
+  isExplicit: Boolean
+  licenseId: ID
+  mediaDataObjectId: ID
+  mediaUrls: [String!]!
+  mediaAvailability: AssetAvailability!
+  mediaMetadataId: ID
+  happenedIn: Float!
+  isFeatured: Boolean!
+}
+
+type VideoEdge {
+  node: Video!
+  cursor: String!
+}
+
+type VideoMediaEncoding implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+
+  """Encoding of the video media object"""
+  codecName: String
+
+  """Media container format"""
+  container: String
+
+  """Content MIME type"""
+  mimeMediaType: String
+  videomediametadataencoding: [VideoMediaMetadata!]
+}
+
+type VideoMediaEncodingConnection {
+  totalCount: Int!
+  edges: [VideoMediaEncodingEdge!]!
+  pageInfo: PageInfo!
+}
+
+input VideoMediaEncodingCreateInput {
+  codecName: String
+  container: String
+  mimeMediaType: String
+}
+
+type VideoMediaEncodingEdge {
+  node: VideoMediaEncoding!
+  cursor: String!
+}
+
+enum VideoMediaEncodingOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  codecName_ASC
+  codecName_DESC
+  container_ASC
+  container_DESC
+  mimeMediaType_ASC
+  mimeMediaType_DESC
+}
+
+input VideoMediaEncodingUpdateInput {
+  codecName: String
+  container: String
+  mimeMediaType: String
+}
+
+input VideoMediaEncodingWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  codecName_eq: String
+  codecName_contains: String
+  codecName_startsWith: String
+  codecName_endsWith: String
+  codecName_in: [String!]
+  container_eq: String
+  container_contains: String
+  container_startsWith: String
+  container_endsWith: String
+  container_in: [String!]
+  mimeMediaType_eq: String
+  mimeMediaType_contains: String
+  mimeMediaType_startsWith: String
+  mimeMediaType_endsWith: String
+  mimeMediaType_in: [String!]
+}
+
+input VideoMediaEncodingWhereUniqueInput {
+  id: ID!
+}
+
+type VideoMediaMetadata implements BaseGraphQLObject {
+  id: ID!
+  createdAt: DateTime!
+  createdById: String!
+  updatedAt: DateTime
+  updatedById: String
+  deletedAt: DateTime
+  deletedById: String
+  version: Int!
+  encoding: VideoMediaEncoding
+  encodingId: String
+
+  """Video media width in pixels"""
+  pixelWidth: Int
+
+  """Video media height in pixels"""
+  pixelHeight: Int
+
+  """Video media size in bytes"""
+  size: BigInt
+  video: Video
+  happenedIn: Int!
+}
+
+type VideoMediaMetadataConnection {
+  totalCount: Int!
+  edges: [VideoMediaMetadataEdge!]!
+  pageInfo: PageInfo!
+}
+
+input VideoMediaMetadataCreateInput {
+  encodingId: ID
+  pixelWidth: Float
+  pixelHeight: Float
+  size: BigInt
+  happenedIn: Float!
+}
+
+type VideoMediaMetadataEdge {
+  node: VideoMediaMetadata!
+  cursor: String!
+}
+
+enum VideoMediaMetadataOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  encodingId_ASC
+  encodingId_DESC
+  pixelWidth_ASC
+  pixelWidth_DESC
+  pixelHeight_ASC
+  pixelHeight_DESC
+  size_ASC
+  size_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+}
+
+input VideoMediaMetadataUpdateInput {
+  encodingId: ID
+  pixelWidth: Float
+  pixelHeight: Float
+  size: BigInt
+  happenedIn: Float
+}
+
+input VideoMediaMetadataWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  encodingId_eq: ID
+  encodingId_in: [ID!]
+  pixelWidth_eq: Int
+  pixelWidth_gt: Int
+  pixelWidth_gte: Int
+  pixelWidth_lt: Int
+  pixelWidth_lte: Int
+  pixelWidth_in: [Int!]
+  pixelHeight_eq: Int
+  pixelHeight_gt: Int
+  pixelHeight_gte: Int
+  pixelHeight_lt: Int
+  pixelHeight_lte: Int
+  pixelHeight_in: [Int!]
+  size_eq: BigInt
+  size_gt: BigInt
+  size_gte: BigInt
+  size_lt: BigInt
+  size_lte: BigInt
+  size_in: [BigInt!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+}
+
+input VideoMediaMetadataWhereUniqueInput {
+  id: ID!
+}
+
+enum VideoOrderByInput {
+  createdAt_ASC
+  createdAt_DESC
+  updatedAt_ASC
+  updatedAt_DESC
+  deletedAt_ASC
+  deletedAt_DESC
+  channelId_ASC
+  channelId_DESC
+  categoryId_ASC
+  categoryId_DESC
+  title_ASC
+  title_DESC
+  description_ASC
+  description_DESC
+  duration_ASC
+  duration_DESC
+  thumbnailPhotoDataObjectId_ASC
+  thumbnailPhotoDataObjectId_DESC
+  thumbnailPhotoAvailability_ASC
+  thumbnailPhotoAvailability_DESC
+  languageId_ASC
+  languageId_DESC
+  hasMarketing_ASC
+  hasMarketing_DESC
+  publishedBeforeJoystream_ASC
+  publishedBeforeJoystream_DESC
+  isPublic_ASC
+  isPublic_DESC
+  isCensored_ASC
+  isCensored_DESC
+  isExplicit_ASC
+  isExplicit_DESC
+  licenseId_ASC
+  licenseId_DESC
+  mediaDataObjectId_ASC
+  mediaDataObjectId_DESC
+  mediaAvailability_ASC
+  mediaAvailability_DESC
+  mediaMetadataId_ASC
+  mediaMetadataId_DESC
+  happenedIn_ASC
+  happenedIn_DESC
+  isFeatured_ASC
+  isFeatured_DESC
+}
+
+input VideoUpdateInput {
+  channelId: ID
+  categoryId: ID
+  title: String
+  description: String
+  duration: Float
+  thumbnailPhotoDataObjectId: ID
+  thumbnailPhotoUrls: [String!]
+  thumbnailPhotoAvailability: AssetAvailability
+  languageId: ID
+  hasMarketing: Boolean
+  publishedBeforeJoystream: DateTime
+  isPublic: Boolean
+  isCensored: Boolean
+  isExplicit: Boolean
+  licenseId: ID
+  mediaDataObjectId: ID
+  mediaUrls: [String!]
+  mediaAvailability: AssetAvailability
+  mediaMetadataId: ID
+  happenedIn: Float
+  isFeatured: Boolean
+}
+
+input VideoWhereInput {
+  id_eq: ID
+  id_in: [ID!]
+  createdAt_eq: DateTime
+  createdAt_lt: DateTime
+  createdAt_lte: DateTime
+  createdAt_gt: DateTime
+  createdAt_gte: DateTime
+  createdById_eq: ID
+  createdById_in: [ID!]
+  updatedAt_eq: DateTime
+  updatedAt_lt: DateTime
+  updatedAt_lte: DateTime
+  updatedAt_gt: DateTime
+  updatedAt_gte: DateTime
+  updatedById_eq: ID
+  updatedById_in: [ID!]
+  deletedAt_all: Boolean
+  deletedAt_eq: DateTime
+  deletedAt_lt: DateTime
+  deletedAt_lte: DateTime
+  deletedAt_gt: DateTime
+  deletedAt_gte: DateTime
+  deletedById_eq: ID
+  deletedById_in: [ID!]
+  channelId_eq: ID
+  channelId_in: [ID!]
+  categoryId_eq: ID
+  categoryId_in: [ID!]
+  title_eq: String
+  title_contains: String
+  title_startsWith: String
+  title_endsWith: String
+  title_in: [String!]
+  description_eq: String
+  description_contains: String
+  description_startsWith: String
+  description_endsWith: String
+  description_in: [String!]
+  duration_eq: Int
+  duration_gt: Int
+  duration_gte: Int
+  duration_lt: Int
+  duration_lte: Int
+  duration_in: [Int!]
+  thumbnailPhotoDataObjectId_eq: ID
+  thumbnailPhotoDataObjectId_in: [ID!]
+  thumbnailPhotoAvailability_eq: AssetAvailability
+  thumbnailPhotoAvailability_in: [AssetAvailability!]
+  languageId_eq: ID
+  languageId_in: [ID!]
+  hasMarketing_eq: Boolean
+  hasMarketing_in: [Boolean!]
+  publishedBeforeJoystream_eq: DateTime
+  publishedBeforeJoystream_lt: DateTime
+  publishedBeforeJoystream_lte: DateTime
+  publishedBeforeJoystream_gt: DateTime
+  publishedBeforeJoystream_gte: DateTime
+  isPublic_eq: Boolean
+  isPublic_in: [Boolean!]
+  isCensored_eq: Boolean
+  isCensored_in: [Boolean!]
+  isExplicit_eq: Boolean
+  isExplicit_in: [Boolean!]
+  licenseId_eq: ID
+  licenseId_in: [ID!]
+  mediaDataObjectId_eq: ID
+  mediaDataObjectId_in: [ID!]
+  mediaAvailability_eq: AssetAvailability
+  mediaAvailability_in: [AssetAvailability!]
+  mediaMetadataId_eq: ID
+  mediaMetadataId_in: [ID!]
+  happenedIn_eq: Int
+  happenedIn_gt: Int
+  happenedIn_gte: Int
+  happenedIn_lt: Int
+  happenedIn_lte: Int
+  happenedIn_in: [Int!]
+  isFeatured_eq: Boolean
+  isFeatured_in: [Boolean!]
+}
+
+input VideoWhereUniqueInput {
+  id: ID!
+}

+ 47 - 0
query-node/generated/graphql-server/model/index.ts

@@ -0,0 +1,47 @@
+import { Channel } from '../src/modules/channel/channel.model';
+export { Channel };
+import { ChannelCategory } from '../src/modules/channel-category/channel-category.model';
+export { ChannelCategory };
+import { CuratorGroup } from '../src/modules/curator-group/curator-group.model';
+export { CuratorGroup };
+import { DataObject } from '../src/modules/data-object/data-object.model';
+export { DataObject };
+import { FeaturedVideo } from '../src/modules/featured-video/featured-video.model';
+export { FeaturedVideo };
+import { Language } from '../src/modules/language/language.model';
+export { Language };
+import { License } from '../src/modules/license/license.model';
+export { License };
+import { Membership } from '../src/modules/membership/membership.model';
+export { Membership };
+import { Video } from '../src/modules/video/video.model';
+export { Video };
+import { VideoCategory } from '../src/modules/video-category/video-category.model';
+export { VideoCategory };
+import { VideoMediaEncoding } from '../src/modules/video-media-encoding/video-media-encoding.model';
+export { VideoMediaEncoding };
+import { VideoMediaMetadata } from '../src/modules/video-media-metadata/video-media-metadata.model';
+export { VideoMediaMetadata };
+
+import { Network } from '../src/modules/enums/enums';
+export { Network };
+import { MembershipEntryMethod } from '../src/modules/enums/enums';
+export { MembershipEntryMethod };
+import { AssetAvailability } from '../src/modules/enums/enums';
+export { AssetAvailability };
+import { LiaisonJudgement } from '../src/modules/enums/enums';
+export { LiaisonJudgement };
+
+import { DataObjectOwnerChannel } from '../src/modules/variants/variants.model';
+export { DataObjectOwnerChannel };
+import { DataObjectOwnerCouncil } from '../src/modules/variants/variants.model';
+export { DataObjectOwnerCouncil };
+import { DataObjectOwnerDao } from '../src/modules/variants/variants.model';
+export { DataObjectOwnerDao };
+import { DataObjectOwnerMember } from '../src/modules/variants/variants.model';
+export { DataObjectOwnerMember };
+import { DataObjectOwnerWorkingGroup } from '../src/modules/variants/variants.model';
+export { DataObjectOwnerWorkingGroup };
+
+import { DataObjectOwner } from '../src/modules/variants/variants.model';
+export { DataObjectOwner };

+ 105 - 0
query-node/generated/graphql-server/package.json

@@ -0,0 +1,105 @@
+{
+  "name": "query-node",
+  "version": "0.1.0",
+  "description": "Generated Warthog Project",
+  "license": "MIT",
+  "main": "dist/model/index.js",
+  "types": "dist/model/index.d.ts",
+  "scripts": {
+    "bootstrap": "yarn bootstrap:dev",
+    "bootstrap:dev": "yarn && yarn build:dev && yarn db:drop && yarn db:create && yarn db:migrate && yarn db:seed",
+    "bootstrap:prod": "yarn && yarn build:prod && yarn start:prod",
+    "//": "This is the default command run in CI, so it should point to Prod and also create Prod config",
+    "build": "yarn build:prod",
+    "build:prod": "WARTHOG_ENV=production yarn run config && yarn compile",
+    "build:dev": "yarn run config:dev && yarn codegen && yarn compile",
+    "check:code": "tsc --noEmit && yarn lint && prettier ./{src,test,tools}/**/*.ts --write",
+    "clean": "yarn db:drop && rm -rf ./node_modules ./generated ./dist",
+    "codegen": "warthog codegen",
+    "config": "WARTHOG_ENV=$NODE_ENV yarn dotenv:generate",
+    "config:dev": "WARTHOG_ENV=development yarn dotenv:generate",
+    "compile": "rm -rf ./dist && yarn tsc",
+    "deploy": "heroku git:remote -a warthog-starter && git push heroku main && WARTHOG_ENV=production yarn dotenv:generate && warthog db:migrate",
+    "dotenv:generate": "dotenvi -s ${WARTHOG_ENV:-development}",
+    "db:create": "warthog db:create",
+    "db:drop": "warthog db:drop",
+    "db:migrate:generate": "warthog db:migrate:generate --name",
+    "db:migrate": "warthog db:migrate",
+    "db:seed": "ts-node tools/seed.ts",
+    "lint": "eslint './+(src|test|tools)/**/*.{js,ts}' --fix",
+    "list:users": "ts-node ./tools/list-users.ts",
+    "playground": "warthog playground",
+    "prettier": "prettier ./{src,test,tools}/**/*.ts --write",
+    "start": "yarn start:prod",
+    "start:dev": "ts-node --type-check src/index.ts",
+    "start:dev:watch": "nodemon -e ts,graphql -x ts-node --type-check src/index.ts",
+    "start:prod": "WARTHOG_ENV=production yarn dotenv:generate && node dist/src/index.js",
+    "test": "DEBUG= jest --verbose --coverage",
+    "test:watch": "DEBUG= jest --watch",
+    "db:sync": "SYNC=true WARTHOG_DB_SYNCHRONIZE=true ts-node --type-check src/index.ts"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "yarn run config:dev && lint-staged && tsc -p ./tsconfig.json && yarn test"
+    }
+  },
+  "lint-staged": {
+    "linters": {
+      "*.ts": [
+        "eslint --fix",
+        "prettier --write",
+        "git add"
+      ],
+      "*.{js,json}": [
+        "prettier --write",
+        "git add"
+      ]
+    },
+    "ignore": [
+      "**/generated/*"
+    ]
+  },
+  "hydra": "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz",
+  "dependencies": {
+    "dotenv": "^8.2.0",
+    "reflect-metadata": "^0.1.13",
+    "warthog": "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz",
+    "@types/bn.js": "^4.11.6",
+    "bn.js": "^5.1.3",
+    "lodash": "^4.17.15",
+    "pg-listen": "^1.7.0",
+    "typeorm": "^0.2.31"
+  },
+  "devDependencies": {
+    "@types/jest": "^24.0.23",
+    "dotenvi": "^0.9.0",
+    "jest": "^24.9.0",
+    "ts-jest": "^24.1.0",
+    "ts-node": "^8.10",
+    "ts-node-dev": "^1.0.0-pre.60",
+    "typescript": "^3.9.7"
+  },
+  "jest": {
+    "globals": {
+      "ts-jest": {
+        "tsConfig": "tsconfig.test.json"
+      }
+    },
+    "transform": {
+      ".ts": "ts-jest"
+    },
+    "testRegex": "\\.test\\.ts$",
+    "moduleFileExtensions": [
+      "js",
+      "ts"
+    ],
+    "coveragePathIgnorePatterns": [
+      "/node_modules/",
+      "\\.test\\.ts$"
+    ]
+  },
+  "prettier": {
+    "printWidth": 100,
+    "singleQuote": true
+  }
+}

+ 7 - 0
query-node/generated/graphql-server/src/config.ts

@@ -0,0 +1,7 @@
+import * as dotenv from 'dotenv';
+import * as path from 'path';
+
+export function loadConfig() {
+  delete process.env.NODE_ENV;
+  dotenv.config({ path: path.join(__dirname, '../.env') });
+}

+ 45 - 0
query-node/generated/graphql-server/src/index.ts

@@ -0,0 +1,45 @@
+import 'reflect-metadata';
+
+import { SnakeNamingStrategy } from 'warthog';
+import { snakeCase } from 'typeorm/util/StringUtils';
+
+import { loadConfig } from '../src/config';
+import { Logger } from '../src/logger';
+
+import { buildServerSchema, getServer } from './server';
+import { startPgSubsribers } from './pubsub';
+
+
+class CustomNamingStrategy extends SnakeNamingStrategy {
+  constructor() {
+    super();
+  }
+  tableName(className: string, customName?: string): string {
+    return customName ? customName : `${snakeCase(className)}`;
+  }
+}
+
+async function bootstrap() {
+  await loadConfig();
+
+  const server = getServer({}, { namingStrategy: new CustomNamingStrategy() });
+
+  // Create database tables. Warthog migrate command does not support CustomNamingStrategy thats why
+  // we have this code
+  const syncDatabase: string | undefined = process.env.SYNC;
+  if (syncDatabase === 'true') {
+    await server.establishDBConnection();
+    process.exit(0);
+  }
+  await buildServerSchema(server);
+  await startPgSubsribers();
+  await server.start();
+}
+
+bootstrap().catch((error: Error) => {
+  Logger.error(error);
+  if (error.stack) {
+    Logger.error(error.stack.split('\n'));
+  }
+  process.exit(1);
+});

+ 35 - 0
query-node/generated/graphql-server/src/logger.ts

@@ -0,0 +1,35 @@
+/* eslint-disable no-console */
+
+import * as util from 'util';
+
+import { getBindingError } from 'warthog';
+
+export class Logger {
+  static info(...args: any[]) {
+    args = args.length === 1 ? args[0] : args;
+    console.log(util.inspect(args, { showHidden: false, depth: null }));
+  }
+
+  static error(...args: any[]) {
+    args = args.length === 1 ? args[0] : args;
+    console.error(util.inspect(args, { showHidden: false, depth: null }));
+  }
+
+  // static debug(...args: any[]) {
+  //   console.debug(args);
+  // }
+
+  static log(...args: any[]) {
+    console.log(args);
+  }
+
+  static warn(...args: any[]) {
+    console.warn(args);
+  }
+
+  // This takes a raw GraphQL error and pulls out the relevant info
+  static logGraphQLError(error: Error) {
+    console.error(util.inspect(getBindingError(error), { showHidden: false, depth: null }));
+  }
+}
+/* eslint-enable no-console */

+ 23 - 0
query-node/generated/graphql-server/src/modules/channel-category/channel-category.model.ts

@@ -0,0 +1,23 @@
+import { BaseModel, IntField, Model, OneToMany, StringField } from 'warthog';
+
+import { Channel } from '../channel/channel.model';
+
+@Model({ api: { description: `Category of media channel` } })
+export class ChannelCategory extends BaseModel {
+  @StringField({
+    nullable: true,
+    description: `The name of the category`,
+  })
+  name?: string;
+
+  @OneToMany(() => Channel, (param: Channel) => param.category)
+  channels?: Channel[];
+
+  @IntField({})
+  createdInBlock!: number;
+
+  constructor(init?: Partial<ChannelCategory>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/channel-category/channel-category.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  ChannelCategoryCreateInput,
+  ChannelCategoryCreateManyArgs,
+  ChannelCategoryUpdateArgs,
+  ChannelCategoryWhereArgs,
+  ChannelCategoryWhereInput,
+  ChannelCategoryWhereUniqueInput,
+  ChannelCategoryOrderByEnum,
+} from '../../../generated';
+
+import { ChannelCategory } from './channel-category.model';
+import { ChannelCategoryService } from './channel-category.service';
+
+import { Channel } from '../channel/channel.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class ChannelCategoryEdge {
+  @Field(() => ChannelCategory, { nullable: false })
+  node!: ChannelCategory;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class ChannelCategoryConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [ChannelCategoryEdge], { nullable: false })
+  edges!: ChannelCategoryEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class ChannelCategoryConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => ChannelCategoryWhereInput, { nullable: true })
+  where?: ChannelCategoryWhereInput;
+
+  @Field(() => ChannelCategoryOrderByEnum, { nullable: true })
+  orderBy?: ChannelCategoryOrderByEnum;
+}
+
+@Resolver(ChannelCategory)
+export class ChannelCategoryResolver {
+  constructor(@Inject('ChannelCategoryService') public readonly service: ChannelCategoryService) {}
+
+  @Query(() => [ChannelCategory])
+  async channelCategories(
+    @Args() { where, orderBy, limit, offset }: ChannelCategoryWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<ChannelCategory[]> {
+    return this.service.find<ChannelCategoryWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => ChannelCategory, { nullable: true })
+  async channelCategoryByUniqueInput(
+    @Arg('where') where: ChannelCategoryWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<ChannelCategory | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => ChannelCategoryConnection)
+  async channelCategoriesConnection(
+    @Args() { where, orderBy, ...pageOptions }: ChannelCategoryConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<ChannelCategoryConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<ChannelCategoryWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<ChannelCategoryConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channels(@Root() r: ChannelCategory): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(ChannelCategory)
+      .findOne(r.id, { relations: ['channels'] });
+    if (result && result.channels !== undefined) {
+      return result.channels;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/channel-category/channel-category.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { ChannelCategory } from './channel-category.model';
+
+@Service('ChannelCategoryService')
+export class ChannelCategoryService extends BaseService<ChannelCategory> {
+  constructor(@InjectRepository(ChannelCategory) protected readonly repository: Repository<ChannelCategory>) {
+    super(ChannelCategory, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<ChannelCategory[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 116 - 0
query-node/generated/graphql-server/src/modules/channel/channel.model.ts

@@ -0,0 +1,116 @@
+import {
+  BaseModel,
+  BooleanField,
+  IntField,
+  Model,
+  ManyToOne,
+  OneToMany,
+  CustomField,
+  EnumField,
+  StringField,
+} from 'warthog';
+
+import { Membership } from '../membership/membership.model';
+import { CuratorGroup } from '../curator-group/curator-group.model';
+import { ChannelCategory } from '../channel-category/channel-category.model';
+import { DataObject } from '../data-object/data-object.model';
+import { Language } from '../language/language.model';
+import { Video } from '../video/video.model';
+
+import { AssetAvailability } from '../enums/enums';
+export { AssetAvailability };
+
+@Model({ api: {} })
+export class Channel extends BaseModel {
+  @ManyToOne(() => Membership, (param: Membership) => param.channels, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"] })
+  ownerMember?: Membership;
+
+  @ManyToOne(() => CuratorGroup, (param: CuratorGroup) => param.channels, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"]})
+  ownerCuratorGroup?: CuratorGroup;
+
+  @ManyToOne(() => ChannelCategory, (param: ChannelCategory) => param.channels, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  category?: ChannelCategory;
+
+  @StringField({
+    nullable: true,
+    description: `Reward account where revenue is sent if set.`,
+  })
+  rewardAccount?: string;
+
+  @StringField({
+    nullable: true,
+    description: `The title of the Channel`,
+  })
+  title?: string;
+
+  @StringField({
+    nullable: true,
+    description: `The description of a Channel`,
+  })
+  description?: string;
+
+  @ManyToOne(() => DataObject, (param: DataObject) => param.channelcoverPhotoDataObject, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  coverPhotoDataObject?: DataObject;
+
+  @CustomField({
+    db: { type: 'text', array: true },
+    api: { type: 'string', description: `URLs where the asset content can be accessed (if any)` },
+  })
+  coverPhotoUrls!: string[];
+
+  @EnumField('AssetAvailability', AssetAvailability, {
+    description: `Availability meta information`,
+  })
+  coverPhotoAvailability!: AssetAvailability;
+
+  @ManyToOne(() => DataObject, (param: DataObject) => param.channelavatarPhotoDataObject, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  avatarPhotoDataObject?: DataObject;
+
+  @CustomField({
+    db: { type: 'text', array: true },
+    api: { type: 'string', description: `URLs where the asset content can be accessed (if any)` },
+  })
+  avatarPhotoUrls!: string[];
+
+  @EnumField('AssetAvailability', AssetAvailability, {
+    description: `Availability meta information`,
+  })
+  avatarPhotoAvailability!: AssetAvailability;
+
+  @BooleanField({
+    nullable: true,
+    description: `Flag signaling whether a channel is public.`,
+  })
+  isPublic?: boolean;
+
+  @BooleanField({
+    description: `Flag signaling whether a channel is censored.`,
+  })
+  isCensored!: boolean;
+
+  @ManyToOne(() => Language, (param: Language) => param.channellanguage, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"] })
+  language?: Language;
+
+  @OneToMany(() => Video, (param: Video) => param.channel, { cascade: ["insert", "update"] })
+  videos?: Video[];
+
+  @IntField({})
+  createdInBlock!: number;
+
+  constructor(init?: Partial<Channel>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 213 - 0
query-node/generated/graphql-server/src/modules/channel/channel.resolver.ts

@@ -0,0 +1,213 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  ChannelCreateInput,
+  ChannelCreateManyArgs,
+  ChannelUpdateArgs,
+  ChannelWhereArgs,
+  ChannelWhereInput,
+  ChannelWhereUniqueInput,
+  ChannelOrderByEnum,
+} from '../../../generated';
+
+import { Channel } from './channel.model';
+import { ChannelService } from './channel.service';
+
+import { Membership } from '../membership/membership.model';
+import { CuratorGroup } from '../curator-group/curator-group.model';
+import { ChannelCategory } from '../channel-category/channel-category.model';
+import { DataObject } from '../data-object/data-object.model';
+import { Language } from '../language/language.model';
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class ChannelEdge {
+  @Field(() => Channel, { nullable: false })
+  node!: Channel;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class ChannelConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [ChannelEdge], { nullable: false })
+  edges!: ChannelEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class ChannelConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => ChannelWhereInput, { nullable: true })
+  where?: ChannelWhereInput;
+
+  @Field(() => ChannelOrderByEnum, { nullable: true })
+  orderBy?: ChannelOrderByEnum;
+}
+
+@Resolver(Channel)
+export class ChannelResolver {
+  constructor(@Inject('ChannelService') public readonly service: ChannelService) {}
+
+  @Query(() => [Channel])
+  async channels(
+    @Args() { where, orderBy, limit, offset }: ChannelWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<Channel[]> {
+    return this.service.find<ChannelWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => Channel, { nullable: true })
+  async channelByUniqueInput(
+    @Arg('where') where: ChannelWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<Channel | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => ChannelConnection)
+  async channelsConnection(
+    @Args() { where, orderBy, ...pageOptions }: ChannelConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<ChannelConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<ChannelWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<ChannelConnection>;
+  }
+
+  @FieldResolver(() => Membership)
+  async ownerMember(@Root() r: Channel): Promise<Membership | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['ownerMember'] });
+    if (result && result.ownerMember !== undefined) {
+      return result.ownerMember;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => CuratorGroup)
+  async ownerCuratorGroup(@Root() r: Channel): Promise<CuratorGroup | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['ownerCuratorGroup'] });
+    if (result && result.ownerCuratorGroup !== undefined) {
+      return result.ownerCuratorGroup;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => ChannelCategory)
+  async category(@Root() r: Channel): Promise<ChannelCategory | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['category'] });
+    if (result && result.category !== undefined) {
+      return result.category;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => DataObject)
+  async coverPhotoDataObject(@Root() r: Channel): Promise<DataObject | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['coverPhotoDataObject'] });
+    if (result && result.coverPhotoDataObject !== undefined) {
+      return result.coverPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => DataObject)
+  async avatarPhotoDataObject(@Root() r: Channel): Promise<DataObject | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['avatarPhotoDataObject'] });
+    if (result && result.avatarPhotoDataObject !== undefined) {
+      return result.avatarPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Language)
+  async language(@Root() r: Channel): Promise<Language | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['language'] });
+    if (result && result.language !== undefined) {
+      return result.language;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Video)
+  async videos(@Root() r: Channel): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(Channel)
+      .findOne(r.id, { relations: ['videos'] });
+    if (result && result.videos !== undefined) {
+      return result.videos;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/channel/channel.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { Channel } from './channel.model';
+
+@Service('ChannelService')
+export class ChannelService extends BaseService<Channel> {
+  constructor(@InjectRepository(Channel) protected readonly repository: Repository<Channel>) {
+    super(Channel, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<Channel[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 25 - 0
query-node/generated/graphql-server/src/modules/curator-group/curator-group.model.ts

@@ -0,0 +1,25 @@
+import { BaseModel, BooleanField, IntField, Model, OneToMany, CustomField, StringField } from 'warthog';
+
+import { Channel } from '../channel/channel.model';
+
+@Model({ api: {} })
+export class CuratorGroup extends BaseModel {
+  @CustomField({
+    db: { type: 'integer', array: true },
+    api: { type: 'integer', description: `Curators belonging to this group` },
+  })
+  curatorIds!: number[];
+
+  @BooleanField({
+    description: `Is group active or not`,
+  })
+  isActive!: boolean;
+
+  @OneToMany(() => Channel, (param: Channel) => param.ownerCuratorGroup, { cascade: ["insert", "update"] })
+  channels?: Channel[];
+
+  constructor(init?: Partial<CuratorGroup>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/curator-group/curator-group.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  CuratorGroupCreateInput,
+  CuratorGroupCreateManyArgs,
+  CuratorGroupUpdateArgs,
+  CuratorGroupWhereArgs,
+  CuratorGroupWhereInput,
+  CuratorGroupWhereUniqueInput,
+  CuratorGroupOrderByEnum,
+} from '../../../generated';
+
+import { CuratorGroup } from './curator-group.model';
+import { CuratorGroupService } from './curator-group.service';
+
+import { Channel } from '../channel/channel.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class CuratorGroupEdge {
+  @Field(() => CuratorGroup, { nullable: false })
+  node!: CuratorGroup;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class CuratorGroupConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [CuratorGroupEdge], { nullable: false })
+  edges!: CuratorGroupEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class CuratorGroupConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => CuratorGroupWhereInput, { nullable: true })
+  where?: CuratorGroupWhereInput;
+
+  @Field(() => CuratorGroupOrderByEnum, { nullable: true })
+  orderBy?: CuratorGroupOrderByEnum;
+}
+
+@Resolver(CuratorGroup)
+export class CuratorGroupResolver {
+  constructor(@Inject('CuratorGroupService') public readonly service: CuratorGroupService) {}
+
+  @Query(() => [CuratorGroup])
+  async curatorGroups(
+    @Args() { where, orderBy, limit, offset }: CuratorGroupWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<CuratorGroup[]> {
+    return this.service.find<CuratorGroupWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => CuratorGroup, { nullable: true })
+  async curatorGroupByUniqueInput(
+    @Arg('where') where: CuratorGroupWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<CuratorGroup | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => CuratorGroupConnection)
+  async curatorGroupsConnection(
+    @Args() { where, orderBy, ...pageOptions }: CuratorGroupConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<CuratorGroupConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<CuratorGroupWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<CuratorGroupConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channels(@Root() r: CuratorGroup): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(CuratorGroup)
+      .findOne(r.id, { relations: ['channels'] });
+    if (result && result.channels !== undefined) {
+      return result.channels;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/curator-group/curator-group.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { CuratorGroup } from './curator-group.model';
+
+@Service('CuratorGroupService')
+export class CuratorGroupService extends BaseService<CuratorGroup> {
+  constructor(@InjectRepository(CuratorGroup) protected readonly repository: Repository<CuratorGroup>) {
+    super(CuratorGroup, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<CuratorGroup[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 76 - 0
query-node/generated/graphql-server/src/modules/data-object/data-object.model.ts

@@ -0,0 +1,76 @@
+import { BaseModel, IntField, Model, OneToMany, EnumField, StringField } from 'warthog';
+
+import { Column } from 'typeorm';
+import { Field } from 'type-graphql';
+import { WarthogField } from 'warthog';
+
+import { DataObjectOwner } from '../variants/variants.model';
+
+import { Channel } from '../channel/channel.model';
+import { Video } from '../video/video.model';
+
+import { LiaisonJudgement } from '../enums/enums';
+export { LiaisonJudgement };
+
+@Model({ api: { description: `Manages content ids, type and storage provider decision about it` } })
+export class DataObject extends BaseModel {
+  @Column('jsonb')
+  @WarthogField('json')
+  @Field((type) => DataObjectOwner, {
+    description: `Content owner`,
+  })
+  owner!: typeof DataObjectOwner;
+
+  @IntField({
+    description: `Content added at`,
+  })
+  createdInBlock!: number;
+
+  @IntField({
+    description: `Content type id`,
+  })
+  typeId!: number;
+
+  @IntField({
+    description: `Content size in bytes`,
+  })
+  size!: number;
+
+  @IntField({
+    nullable: true,
+    description: `Storage provider id of the liaison`,
+  })
+  liaisonId?: number;
+
+  @EnumField('LiaisonJudgement', LiaisonJudgement, {
+    description: `Storage provider as liaison judgment`,
+  })
+  liaisonJudgement!: LiaisonJudgement;
+
+  @StringField({
+    description: `IPFS content id`,
+  })
+  ipfsContentId!: string;
+
+  @StringField({
+    description: `Joystream runtime content`,
+  })
+  joystreamContentId!: string;
+
+  @OneToMany(() => Channel, (param: Channel) => param.coverPhotoDataObject, { nullable: true, cascade: ["insert", "update"] })
+  channelcoverPhotoDataObject?: Channel[];
+
+  @OneToMany(() => Channel, (param: Channel) => param.avatarPhotoDataObject, { nullable: true, cascade: ["insert", "update"] })
+  channelavatarPhotoDataObject?: Channel[];
+
+  @OneToMany(() => Video, (param: Video) => param.thumbnailPhotoDataObject, { nullable: true, cascade: ["insert", "update"] })
+  videothumbnailPhotoDataObject?: Video[];
+
+  @OneToMany(() => Video, (param: Video) => param.mediaDataObject, { nullable: true, cascade: ["insert", "update"] })
+  videomediaDataObject?: Video[];
+
+  constructor(init?: Partial<DataObject>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 176 - 0
query-node/generated/graphql-server/src/modules/data-object/data-object.resolver.ts

@@ -0,0 +1,176 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  DataObjectCreateInput,
+  DataObjectCreateManyArgs,
+  DataObjectUpdateArgs,
+  DataObjectWhereArgs,
+  DataObjectWhereInput,
+  DataObjectWhereUniqueInput,
+  DataObjectOrderByEnum,
+} from '../../../generated';
+
+import { DataObject } from './data-object.model';
+import { DataObjectService } from './data-object.service';
+
+import { Channel } from '../channel/channel.model';
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class DataObjectEdge {
+  @Field(() => DataObject, { nullable: false })
+  node!: DataObject;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class DataObjectConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [DataObjectEdge], { nullable: false })
+  edges!: DataObjectEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class DataObjectConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => DataObjectWhereInput, { nullable: true })
+  where?: DataObjectWhereInput;
+
+  @Field(() => DataObjectOrderByEnum, { nullable: true })
+  orderBy?: DataObjectOrderByEnum;
+}
+
+@Resolver(DataObject)
+export class DataObjectResolver {
+  constructor(@Inject('DataObjectService') public readonly service: DataObjectService) {}
+
+  @Query(() => [DataObject])
+  async dataObjects(
+    @Args() { where, orderBy, limit, offset }: DataObjectWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<DataObject[]> {
+    return this.service.find<DataObjectWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => DataObject, { nullable: true })
+  async dataObjectByUniqueInput(
+    @Arg('where') where: DataObjectWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<DataObject | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => DataObjectConnection)
+  async dataObjectsConnection(
+    @Args() { where, orderBy, ...pageOptions }: DataObjectConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<DataObjectConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<DataObjectWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<DataObjectConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channelcoverPhotoDataObject(@Root() r: DataObject): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(DataObject)
+      .findOne(r.id, { relations: ['channelcoverPhotoDataObject'] });
+    if (result && result.channelcoverPhotoDataObject !== undefined) {
+      return result.channelcoverPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Channel)
+  async channelavatarPhotoDataObject(@Root() r: DataObject): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(DataObject)
+      .findOne(r.id, { relations: ['channelavatarPhotoDataObject'] });
+    if (result && result.channelavatarPhotoDataObject !== undefined) {
+      return result.channelavatarPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Video)
+  async videothumbnailPhotoDataObject(@Root() r: DataObject): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(DataObject)
+      .findOne(r.id, { relations: ['videothumbnailPhotoDataObject'] });
+    if (result && result.videothumbnailPhotoDataObject !== undefined) {
+      return result.videothumbnailPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Video)
+  async videomediaDataObject(@Root() r: DataObject): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(DataObject)
+      .findOne(r.id, { relations: ['videomediaDataObject'] });
+    if (result && result.videomediaDataObject !== undefined) {
+      return result.videomediaDataObject;
+    }
+    return null;
+  }
+}

+ 31 - 0
query-node/generated/graphql-server/src/modules/data-object/data-object.service.ts

@@ -0,0 +1,31 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { DataObject } from './data-object.model';
+
+@Service('DataObjectService')
+export class DataObjectService extends BaseService<DataObject> {
+  constructor(@InjectRepository(DataObject) protected readonly repository: Repository<DataObject>) {
+    super(DataObject, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<DataObject[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+    if (!f.includes('owner')) {
+      f = [...f, 'owner'];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 19 - 0
query-node/generated/graphql-server/src/modules/enums/enums.ts

@@ -0,0 +1,19 @@
+export enum Network {
+  BABYLON = 'BABYLON',
+  ALEXANDRIA = 'ALEXANDRIA',
+  ROME = 'ROME',
+}
+export enum MembershipEntryMethod {
+  PAID = 'PAID',
+  SCREENING = 'SCREENING',
+  GENESIS = 'GENESIS',
+}
+export enum AssetAvailability {
+  ACCEPTED = 'ACCEPTED',
+  PENDING = 'PENDING',
+  INVALID = 'INVALID',
+}
+export enum LiaisonJudgement {
+  PENDING = 'PENDING',
+  ACCEPTED = 'ACCEPTED',
+}

+ 14 - 0
query-node/generated/graphql-server/src/modules/featured-video/featured-video.model.ts

@@ -0,0 +1,14 @@
+import { BaseModel, Model, OneToOne, OneToOneJoin, StringField } from 'warthog';
+
+import { Video } from '../video/video.model';
+
+@Model({ api: {} })
+export class FeaturedVideo extends BaseModel {
+  @OneToOneJoin(() => Video, (param: Video) => param.featured, { cascade: ["insert", "update"] })
+  video!: Video;
+
+  constructor(init?: Partial<FeaturedVideo>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/featured-video/featured-video.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  FeaturedVideoCreateInput,
+  FeaturedVideoCreateManyArgs,
+  FeaturedVideoUpdateArgs,
+  FeaturedVideoWhereArgs,
+  FeaturedVideoWhereInput,
+  FeaturedVideoWhereUniqueInput,
+  FeaturedVideoOrderByEnum,
+} from '../../../generated';
+
+import { FeaturedVideo } from './featured-video.model';
+import { FeaturedVideoService } from './featured-video.service';
+
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class FeaturedVideoEdge {
+  @Field(() => FeaturedVideo, { nullable: false })
+  node!: FeaturedVideo;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class FeaturedVideoConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [FeaturedVideoEdge], { nullable: false })
+  edges!: FeaturedVideoEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class FeaturedVideoConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => FeaturedVideoWhereInput, { nullable: true })
+  where?: FeaturedVideoWhereInput;
+
+  @Field(() => FeaturedVideoOrderByEnum, { nullable: true })
+  orderBy?: FeaturedVideoOrderByEnum;
+}
+
+@Resolver(FeaturedVideo)
+export class FeaturedVideoResolver {
+  constructor(@Inject('FeaturedVideoService') public readonly service: FeaturedVideoService) {}
+
+  @Query(() => [FeaturedVideo])
+  async featuredVideos(
+    @Args() { where, orderBy, limit, offset }: FeaturedVideoWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<FeaturedVideo[]> {
+    return this.service.find<FeaturedVideoWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => FeaturedVideo, { nullable: true })
+  async featuredVideoByUniqueInput(
+    @Arg('where') where: FeaturedVideoWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<FeaturedVideo | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => FeaturedVideoConnection)
+  async featuredVideosConnection(
+    @Args() { where, orderBy, ...pageOptions }: FeaturedVideoConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<FeaturedVideoConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<FeaturedVideoWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<FeaturedVideoConnection>;
+  }
+
+  @FieldResolver(() => Video)
+  async video(@Root() r: FeaturedVideo): Promise<Video | null> {
+    const result = await getConnection()
+      .getRepository(FeaturedVideo)
+      .findOne(r.id, { relations: ['video'] });
+    if (result && result.video !== undefined) {
+      return result.video;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/featured-video/featured-video.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { FeaturedVideo } from './featured-video.model';
+
+@Service('FeaturedVideoService')
+export class FeaturedVideoService extends BaseService<FeaturedVideo> {
+  constructor(@InjectRepository(FeaturedVideo) protected readonly repository: Repository<FeaturedVideo>) {
+    super(FeaturedVideo, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<FeaturedVideo[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 26 - 0
query-node/generated/graphql-server/src/modules/language/language.model.ts

@@ -0,0 +1,26 @@
+import { BaseModel, IntField, Model, OneToMany, StringField } from 'warthog';
+
+import { Channel } from '../channel/channel.model';
+import { Video } from '../video/video.model';
+
+@Model({ api: {} })
+export class Language extends BaseModel {
+  @StringField({
+    description: `Language identifier ISO 639-1`,
+  })
+  iso!: string;
+
+  @IntField({})
+  createdInBlock!: number;
+
+  @OneToMany(() => Channel, (param: Channel) => param.language, { nullable: true, cascade: ["insert", "update"] })
+  channellanguage?: Channel[];
+
+  @OneToMany(() => Video, (param: Video) => param.language, { nullable: true, cascade: ["insert", "update"] })
+  videolanguage?: Video[];
+
+  constructor(init?: Partial<Language>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 154 - 0
query-node/generated/graphql-server/src/modules/language/language.resolver.ts

@@ -0,0 +1,154 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  LanguageCreateInput,
+  LanguageCreateManyArgs,
+  LanguageUpdateArgs,
+  LanguageWhereArgs,
+  LanguageWhereInput,
+  LanguageWhereUniqueInput,
+  LanguageOrderByEnum,
+} from '../../../generated';
+
+import { Language } from './language.model';
+import { LanguageService } from './language.service';
+
+import { Channel } from '../channel/channel.model';
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class LanguageEdge {
+  @Field(() => Language, { nullable: false })
+  node!: Language;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class LanguageConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [LanguageEdge], { nullable: false })
+  edges!: LanguageEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class LanguageConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => LanguageWhereInput, { nullable: true })
+  where?: LanguageWhereInput;
+
+  @Field(() => LanguageOrderByEnum, { nullable: true })
+  orderBy?: LanguageOrderByEnum;
+}
+
+@Resolver(Language)
+export class LanguageResolver {
+  constructor(@Inject('LanguageService') public readonly service: LanguageService) {}
+
+  @Query(() => [Language])
+  async languages(
+    @Args() { where, orderBy, limit, offset }: LanguageWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<Language[]> {
+    return this.service.find<LanguageWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => Language, { nullable: true })
+  async languageByUniqueInput(
+    @Arg('where') where: LanguageWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<Language | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => LanguageConnection)
+  async languagesConnection(
+    @Args() { where, orderBy, ...pageOptions }: LanguageConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<LanguageConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<LanguageWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<LanguageConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channellanguage(@Root() r: Language): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(Language)
+      .findOne(r.id, { relations: ['channellanguage'] });
+    if (result && result.channellanguage !== undefined) {
+      return result.channellanguage;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Video)
+  async videolanguage(@Root() r: Language): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(Language)
+      .findOne(r.id, { relations: ['videolanguage'] });
+    if (result && result.videolanguage !== undefined) {
+      return result.videolanguage;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/language/language.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { Language } from './language.model';
+
+@Service('LanguageService')
+export class LanguageService extends BaseService<Language> {
+  constructor(@InjectRepository(Language) protected readonly repository: Repository<Language>) {
+    super(Language, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<Language[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 32 - 0
query-node/generated/graphql-server/src/modules/license/license.model.ts

@@ -0,0 +1,32 @@
+import { BaseModel, IntField, Model, OneToMany, StringField } from 'warthog';
+
+import { Video } from '../video/video.model';
+
+@Model({ api: {} })
+export class License extends BaseModel {
+  @IntField({
+    nullable: true,
+    description: `License code defined by Joystream`,
+  })
+  code?: number;
+
+  @StringField({
+    nullable: true,
+    description: `Attribution (if required by the license)`,
+  })
+  attribution?: string;
+
+  @StringField({
+    nullable: true,
+    description: `Custom license content`,
+  })
+  customText?: string;
+
+  @OneToMany(() => Video, (param: Video) => param.license, { nullable: true, cascade: ["insert", "update"] })
+  videolicense?: Video[];
+
+  constructor(init?: Partial<License>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/license/license.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  LicenseCreateInput,
+  LicenseCreateManyArgs,
+  LicenseUpdateArgs,
+  LicenseWhereArgs,
+  LicenseWhereInput,
+  LicenseWhereUniqueInput,
+  LicenseOrderByEnum,
+} from '../../../generated';
+
+import { License } from './license.model';
+import { LicenseService } from './license.service';
+
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class LicenseEdge {
+  @Field(() => License, { nullable: false })
+  node!: License;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class LicenseConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [LicenseEdge], { nullable: false })
+  edges!: LicenseEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class LicenseConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => LicenseWhereInput, { nullable: true })
+  where?: LicenseWhereInput;
+
+  @Field(() => LicenseOrderByEnum, { nullable: true })
+  orderBy?: LicenseOrderByEnum;
+}
+
+@Resolver(License)
+export class LicenseResolver {
+  constructor(@Inject('LicenseService') public readonly service: LicenseService) {}
+
+  @Query(() => [License])
+  async licenses(
+    @Args() { where, orderBy, limit, offset }: LicenseWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<License[]> {
+    return this.service.find<LicenseWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => License, { nullable: true })
+  async licenseByUniqueInput(
+    @Arg('where') where: LicenseWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<License | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => LicenseConnection)
+  async licensesConnection(
+    @Args() { where, orderBy, ...pageOptions }: LicenseConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<LicenseConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<LicenseWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<LicenseConnection>;
+  }
+
+  @FieldResolver(() => Video)
+  async videolicense(@Root() r: License): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(License)
+      .findOne(r.id, { relations: ['videolicense'] });
+    if (result && result.videolicense !== undefined) {
+      return result.videolicense;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/license/license.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { License } from './license.model';
+
+@Service('LicenseService')
+export class LicenseService extends BaseService<License> {
+  constructor(@InjectRepository(License) protected readonly repository: Repository<License>) {
+    super(License, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<License[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 61 - 0
query-node/generated/graphql-server/src/modules/membership/membership.model.ts

@@ -0,0 +1,61 @@
+import { BaseModel, IntField, Model, OneToMany, EnumField, StringField } from 'warthog';
+
+import { Channel } from '../channel/channel.model';
+
+import { MembershipEntryMethod } from '../enums/enums';
+export { MembershipEntryMethod };
+
+@Model({ api: { description: `Stored information about a registered user` } })
+export class Membership extends BaseModel {
+  @StringField({
+    description: `The unique handle chosen by member`,
+    unique: true,
+  })
+  handle!: string;
+
+  @StringField({
+    nullable: true,
+    description: `A Url to member's Avatar image`,
+  })
+  avatarUri?: string;
+
+  @StringField({
+    nullable: true,
+    description: `Short text chosen by member to share information about themselves`,
+  })
+  about?: string;
+
+  @StringField({
+    description: `Member's controller account id`,
+  })
+  controllerAccount!: string;
+
+  @StringField({
+    description: `Member's root account id`,
+  })
+  rootAccount!: string;
+
+  @IntField({
+    description: `Blocknumber when member was registered`,
+  })
+  createdInBlock!: number;
+
+  @EnumField('MembershipEntryMethod', MembershipEntryMethod, {
+    description: `How the member was registered`,
+  })
+  entry!: MembershipEntryMethod;
+
+  @IntField({
+    nullable: true,
+    description: `The type of subscription the member has purchased if any.`,
+  })
+  subscription?: number;
+
+  @OneToMany(() => Channel, (param: Channel) => param.ownerMember, { cascade: ["insert", "update"] })
+  channels?: Channel[];
+
+  constructor(init?: Partial<Membership>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/membership/membership.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  MembershipCreateInput,
+  MembershipCreateManyArgs,
+  MembershipUpdateArgs,
+  MembershipWhereArgs,
+  MembershipWhereInput,
+  MembershipWhereUniqueInput,
+  MembershipOrderByEnum,
+} from '../../../generated';
+
+import { Membership } from './membership.model';
+import { MembershipService } from './membership.service';
+
+import { Channel } from '../channel/channel.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class MembershipEdge {
+  @Field(() => Membership, { nullable: false })
+  node!: Membership;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class MembershipConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [MembershipEdge], { nullable: false })
+  edges!: MembershipEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class MembershipConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => MembershipWhereInput, { nullable: true })
+  where?: MembershipWhereInput;
+
+  @Field(() => MembershipOrderByEnum, { nullable: true })
+  orderBy?: MembershipOrderByEnum;
+}
+
+@Resolver(Membership)
+export class MembershipResolver {
+  constructor(@Inject('MembershipService') public readonly service: MembershipService) {}
+
+  @Query(() => [Membership])
+  async memberships(
+    @Args() { where, orderBy, limit, offset }: MembershipWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<Membership[]> {
+    return this.service.find<MembershipWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => Membership, { nullable: true })
+  async membershipByUniqueInput(
+    @Arg('where') where: MembershipWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<Membership | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => MembershipConnection)
+  async membershipsConnection(
+    @Args() { where, orderBy, ...pageOptions }: MembershipConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<MembershipConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<MembershipWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<MembershipConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channels(@Root() r: Membership): Promise<Channel[] | null> {
+    const result = await getConnection()
+      .getRepository(Membership)
+      .findOne(r.id, { relations: ['channels'] });
+    if (result && result.channels !== undefined) {
+      return result.channels;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/membership/membership.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { Membership } from './membership.model';
+
+@Service('MembershipService')
+export class MembershipService extends BaseService<Membership> {
+  constructor(@InjectRepository(Membership) protected readonly repository: Repository<Membership>) {
+    super(Membership, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<Membership[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 46 - 0
query-node/generated/graphql-server/src/modules/queries/channelCategoriesByName.resolver.ts

@@ -0,0 +1,46 @@
+import { ObjectType, Field, Float, Int, Arg, Query, Resolver, createUnionType } from 'type-graphql';
+import { Inject } from 'typedi';
+import { ChannelCategory } from '../channel-category/channel-category.model';
+import { ChannelCategoriesByNameFTSService } from './channelCategoriesByName.service';
+
+import {  ChannelCategoryWhereInput,  } from '../../../generated';
+
+@ObjectType()
+export class ChannelCategoriesByNameFTSOutput {
+    @Field(type => ChannelCategoriesByNameSearchItem)
+    item!: typeof ChannelCategoriesByNameSearchItem
+
+    @Field(type => Float)
+    rank!: number
+
+    @Field(type => String)
+    isTypeOf!: string
+
+    @Field(type => String)
+    highlight!: string
+}
+
+export const ChannelCategoriesByNameSearchItem = createUnionType({
+    name: "ChannelCategoriesByNameSearchResult",
+    types: () => [
+        ChannelCategory,
+    ],
+});
+
+
+@Resolver()
+export default class ChannelCategoriesByNameFTSResolver {
+
+    constructor(@Inject('ChannelCategoriesByNameFTSService') readonly service: ChannelCategoriesByNameFTSService) {}
+
+    @Query(() => [ChannelCategoriesByNameFTSOutput])
+    async channelCategoriesByName(
+      @Arg('text') query: string, 
+      @Arg('limit', () => Int, { defaultValue: 5 }) limit: number,
+      @Arg('skip', () => Int, { defaultValue: 0 }) skip: number,
+      @Arg('whereChannelCategory', { nullable: true }) whereChannelCategory?: ChannelCategoryWhereInput,
+    ):Promise<Array<ChannelCategoriesByNameFTSOutput>>{
+      return this.service.search(query, limit, skip, whereChannelCategory,);
+    }
+
+}

+ 170 - 0
query-node/generated/graphql-server/src/modules/queries/channelCategoriesByName.service.ts

@@ -0,0 +1,170 @@
+import { Service, Inject } from 'typedi';
+import { ChannelCategory } from '../channel-category/channel-category.model';
+import { ChannelCategoryService } from '../channel-category/channel-category.service';
+
+import {  ChannelCategoryWhereInput,  } from '../../../generated';
+
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { Repository, getConnection, EntityManager } from 'typeorm';
+
+import { ChannelCategoriesByNameFTSOutput } from './channelCategoriesByName.resolver';
+
+interface RawSQLResult {
+    origin_table: string,
+    id: string,
+    rank: number,
+    highlight: string
+}
+
+@Service('ChannelCategoriesByNameFTSService')
+export class ChannelCategoriesByNameFTSService {
+    readonly channelCategoryRepository: Repository<ChannelCategory>;
+
+    constructor(
+      @InjectRepository(ChannelCategory) channelCategoryRepository: Repository<ChannelCategory>
+      ,@Inject('ChannelCategoryService') public readonly channelCategoryService: ChannelCategoryService 
+    ) {
+       this.channelCategoryRepository = channelCategoryRepository;  
+    }
+
+    /**
+    * It takes available where inputs for the full text search(fts), generates sql queries
+    * to be run with fts query.
+    * @param wheres WhereInput[]
+    */
+    private async processWheres(wheres: any[]): Promise<[string, any[], number]> {
+      const services: any[] = [this.channelCategoryService, ]
+      const repositories = [this.channelCategoryRepository, ]
+      let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+      const generateSqlQuery = (table: string, where: string) =>
+        `
+  SELECT '${table}_' || id AS unique_id FROM "${table}" ` + where;
+
+      wheres.map((w, index) => {
+        if (w) {
+          let WHERE = `WHERE `;
+          // Combine queries
+          if (queries !== ``) {
+            queries = queries.concat(`
+  UNION ALL`);
+          }
+
+          const qb = services[index].buildFindQuery(w as any, undefined, undefined, ['id']);
+          // Add query parameters to the parameters list
+          parameters.push(...qb.getQueryAndParameters()[1]);
+
+          // Remove the last item which is "table_name"."deleted_at" IS NULL
+          qb.expressionMap.wheres.pop();
+
+          // Combine conditions
+          qb.expressionMap.wheres.map((w: any, index: number) => {
+            let c = ``;
+
+            if (w.condition.includes(`IN (:...`)) {
+              // IN condition parameters
+              const params: any[] = qb.expressionMap.parameters[`param${index}`];
+
+              // Do nothing when IN condition has an empty list of values
+              if (params.length !== 0) {
+                const paramsAsString = params
+                  .map((_: any) => {
+                    parameterCounter += 1;
+                    return `$${parameterCounter}`;
+                  })
+                  .join(`, `);
+                c = w.condition.replace(`(:...param${index})`, `(${paramsAsString})`);
+              }
+            } else if (w.condition.includes(`->>`)) {
+              parameterCounter += 1;
+              const m = w.condition.match(/->>.*\s=\s:.*/g);
+              if (m === null)
+                throw Error(`Failed to construct where condition for json field: ${w.condition}`);
+              c = w.condition.replace(/=\s:.*/g, `= $${parameterCounter}`);
+            } else {
+              parameterCounter += 1;
+              c = w.condition.replace(`:param${index}`, `$${parameterCounter}`);
+            }
+            WHERE = WHERE.concat(c, ` `, w.type.toUpperCase(), ` `);
+          });
+
+          // Remove unnecessary AND at the end.
+          WHERE = WHERE.slice(0, -4);
+
+          // Add new query to queryString
+          queries = queries.concat(generateSqlQuery(repositories[index].metadata.tableName, WHERE));
+        }
+      });
+
+      queries = `
+  WITH selected_ids AS (`.concat(
+        queries,
+        `
+  )`
+      );
+      return [queries, parameters, parameterCounter];
+    }
+
+    async search(
+      text: string,
+      limit = 5,
+      skip = 0,
+      whereChannelCategory?: ChannelCategoryWhereInput,
+    ): Promise<ChannelCategoriesByNameFTSOutput[]> {
+        const wheres = [whereChannelCategory, ]
+        let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+        if (wheres.some(f => f !== undefined)) {
+          [queries, parameters, parameterCounter] = await this.processWheres(wheres);
+        }
+        parameters.push(...[text, limit, skip]);
+
+        return getConnection().transaction<ChannelCategoriesByNameFTSOutput[]>(
+          'REPEATABLE READ',
+          async (em: EntityManager) => {
+            const query = `
+              ${queries}
+              SELECT origin_table, id, 
+                  ts_rank(tsv, phraseto_tsquery('english', $${parameterCounter + 1})) as rank,
+                  ts_headline(document, phraseto_tsquery('english', $${parameterCounter +
+                    1})) as highlight
+              FROM channel_categories_by_name_view
+              WHERE phraseto_tsquery('english', $${parameterCounter + 1}) @@ tsv
+              ${
+                queries !== ``
+                  ? `AND unique_id IN (SELECT unique_id FROM selected_ids)`
+                  : ``
+              } 
+              ORDER BY rank DESC
+              LIMIT $${parameterCounter + 2}
+              OFFSET $${parameterCounter + 3}`;
+            const results = (await em.query(query, parameters)) as RawSQLResult[];
+
+            if (results.length === 0) {
+                return [];
+            }
+
+            const idMap:{ [id:string]: RawSQLResult } = {};
+            results.forEach(item => idMap[item.id] = item);
+            const ids: string[] = results.map(item => item.id);
+            
+            const channelCategorys: ChannelCategory[] = await em.createQueryBuilder<ChannelCategory>(ChannelCategory, 'ChannelCategory')
+                        .where("id IN (:...ids)", { ids }).getMany();
+
+            const enhancedEntities = [...channelCategorys ].map((e) => {
+                return { item: e, 
+                    rank: idMap[e.id].rank, 
+                    highlight: idMap[e.id].highlight,
+                    isTypeOf: idMap[e.id].origin_table } as ChannelCategoriesByNameFTSOutput;
+            });
+
+            return enhancedEntities.reduce((accum: ChannelCategoriesByNameFTSOutput[], entity) => {
+                if (entity.rank > 0) {
+                    accum.push(entity);
+                }
+                return accum;
+            }, []).sort((a,b) => b.rank - a.rank);
+
+        })
+    }
+}

+ 46 - 0
query-node/generated/graphql-server/src/modules/queries/membersByHandle.resolver.ts

@@ -0,0 +1,46 @@
+import { ObjectType, Field, Float, Int, Arg, Query, Resolver, createUnionType } from 'type-graphql';
+import { Inject } from 'typedi';
+import { Membership } from '../membership/membership.model';
+import { MembersByHandleFTSService } from './membersByHandle.service';
+
+import {  MembershipWhereInput,  } from '../../../generated';
+
+@ObjectType()
+export class MembersByHandleFTSOutput {
+    @Field(type => MembersByHandleSearchItem)
+    item!: typeof MembersByHandleSearchItem
+
+    @Field(type => Float)
+    rank!: number
+
+    @Field(type => String)
+    isTypeOf!: string
+
+    @Field(type => String)
+    highlight!: string
+}
+
+export const MembersByHandleSearchItem = createUnionType({
+    name: "MembersByHandleSearchResult",
+    types: () => [
+        Membership,
+    ],
+});
+
+
+@Resolver()
+export default class MembersByHandleFTSResolver {
+
+    constructor(@Inject('MembersByHandleFTSService') readonly service: MembersByHandleFTSService) {}
+
+    @Query(() => [MembersByHandleFTSOutput])
+    async membersByHandle(
+      @Arg('text') query: string, 
+      @Arg('limit', () => Int, { defaultValue: 5 }) limit: number,
+      @Arg('skip', () => Int, { defaultValue: 0 }) skip: number,
+      @Arg('whereMembership', { nullable: true }) whereMembership?: MembershipWhereInput,
+    ):Promise<Array<MembersByHandleFTSOutput>>{
+      return this.service.search(query, limit, skip, whereMembership,);
+    }
+
+}

+ 170 - 0
query-node/generated/graphql-server/src/modules/queries/membersByHandle.service.ts

@@ -0,0 +1,170 @@
+import { Service, Inject } from 'typedi';
+import { Membership } from '../membership/membership.model';
+import { MembershipService } from '../membership/membership.service';
+
+import {  MembershipWhereInput,  } from '../../../generated';
+
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { Repository, getConnection, EntityManager } from 'typeorm';
+
+import { MembersByHandleFTSOutput } from './membersByHandle.resolver';
+
+interface RawSQLResult {
+    origin_table: string,
+    id: string,
+    rank: number,
+    highlight: string
+}
+
+@Service('MembersByHandleFTSService')
+export class MembersByHandleFTSService {
+    readonly membershipRepository: Repository<Membership>;
+
+    constructor(
+      @InjectRepository(Membership) membershipRepository: Repository<Membership>
+      ,@Inject('MembershipService') public readonly membershipService: MembershipService 
+    ) {
+       this.membershipRepository = membershipRepository;  
+    }
+
+    /**
+    * It takes available where inputs for the full text search(fts), generates sql queries
+    * to be run with fts query.
+    * @param wheres WhereInput[]
+    */
+    private async processWheres(wheres: any[]): Promise<[string, any[], number]> {
+      const services: any[] = [this.membershipService, ]
+      const repositories = [this.membershipRepository, ]
+      let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+      const generateSqlQuery = (table: string, where: string) =>
+        `
+  SELECT '${table}_' || id AS unique_id FROM "${table}" ` + where;
+
+      wheres.map((w, index) => {
+        if (w) {
+          let WHERE = `WHERE `;
+          // Combine queries
+          if (queries !== ``) {
+            queries = queries.concat(`
+  UNION ALL`);
+          }
+
+          const qb = services[index].buildFindQuery(w as any, undefined, undefined, ['id']);
+          // Add query parameters to the parameters list
+          parameters.push(...qb.getQueryAndParameters()[1]);
+
+          // Remove the last item which is "table_name"."deleted_at" IS NULL
+          qb.expressionMap.wheres.pop();
+
+          // Combine conditions
+          qb.expressionMap.wheres.map((w: any, index: number) => {
+            let c = ``;
+
+            if (w.condition.includes(`IN (:...`)) {
+              // IN condition parameters
+              const params: any[] = qb.expressionMap.parameters[`param${index}`];
+
+              // Do nothing when IN condition has an empty list of values
+              if (params.length !== 0) {
+                const paramsAsString = params
+                  .map((_: any) => {
+                    parameterCounter += 1;
+                    return `$${parameterCounter}`;
+                  })
+                  .join(`, `);
+                c = w.condition.replace(`(:...param${index})`, `(${paramsAsString})`);
+              }
+            } else if (w.condition.includes(`->>`)) {
+              parameterCounter += 1;
+              const m = w.condition.match(/->>.*\s=\s:.*/g);
+              if (m === null)
+                throw Error(`Failed to construct where condition for json field: ${w.condition}`);
+              c = w.condition.replace(/=\s:.*/g, `= $${parameterCounter}`);
+            } else {
+              parameterCounter += 1;
+              c = w.condition.replace(`:param${index}`, `$${parameterCounter}`);
+            }
+            WHERE = WHERE.concat(c, ` `, w.type.toUpperCase(), ` `);
+          });
+
+          // Remove unnecessary AND at the end.
+          WHERE = WHERE.slice(0, -4);
+
+          // Add new query to queryString
+          queries = queries.concat(generateSqlQuery(repositories[index].metadata.tableName, WHERE));
+        }
+      });
+
+      queries = `
+  WITH selected_ids AS (`.concat(
+        queries,
+        `
+  )`
+      );
+      return [queries, parameters, parameterCounter];
+    }
+
+    async search(
+      text: string,
+      limit = 5,
+      skip = 0,
+      whereMembership?: MembershipWhereInput,
+    ): Promise<MembersByHandleFTSOutput[]> {
+        const wheres = [whereMembership, ]
+        let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+        if (wheres.some(f => f !== undefined)) {
+          [queries, parameters, parameterCounter] = await this.processWheres(wheres);
+        }
+        parameters.push(...[text, limit, skip]);
+
+        return getConnection().transaction<MembersByHandleFTSOutput[]>(
+          'REPEATABLE READ',
+          async (em: EntityManager) => {
+            const query = `
+              ${queries}
+              SELECT origin_table, id, 
+                  ts_rank(tsv, phraseto_tsquery('english', $${parameterCounter + 1})) as rank,
+                  ts_headline(document, phraseto_tsquery('english', $${parameterCounter +
+                    1})) as highlight
+              FROM members_by_handle_view
+              WHERE phraseto_tsquery('english', $${parameterCounter + 1}) @@ tsv
+              ${
+                queries !== ``
+                  ? `AND unique_id IN (SELECT unique_id FROM selected_ids)`
+                  : ``
+              } 
+              ORDER BY rank DESC
+              LIMIT $${parameterCounter + 2}
+              OFFSET $${parameterCounter + 3}`;
+            const results = (await em.query(query, parameters)) as RawSQLResult[];
+
+            if (results.length === 0) {
+                return [];
+            }
+
+            const idMap:{ [id:string]: RawSQLResult } = {};
+            results.forEach(item => idMap[item.id] = item);
+            const ids: string[] = results.map(item => item.id);
+            
+            const memberships: Membership[] = await em.createQueryBuilder<Membership>(Membership, 'Membership')
+                        .where("id IN (:...ids)", { ids }).getMany();
+
+            const enhancedEntities = [...memberships ].map((e) => {
+                return { item: e, 
+                    rank: idMap[e.id].rank, 
+                    highlight: idMap[e.id].highlight,
+                    isTypeOf: idMap[e.id].origin_table } as MembersByHandleFTSOutput;
+            });
+
+            return enhancedEntities.reduce((accum: MembersByHandleFTSOutput[], entity) => {
+                if (entity.rank > 0) {
+                    accum.push(entity);
+                }
+                return accum;
+            }, []).sort((a,b) => b.rank - a.rank);
+
+        })
+    }
+}

+ 49 - 0
query-node/generated/graphql-server/src/modules/queries/search.resolver.ts

@@ -0,0 +1,49 @@
+import { ObjectType, Field, Float, Int, Arg, Query, Resolver, createUnionType } from 'type-graphql';
+import { Inject } from 'typedi';
+import { Channel } from '../channel/channel.model';
+import { Video } from '../video/video.model';
+import { SearchFTSService } from './search.service';
+
+import {  ChannelWhereInput,  VideoWhereInput,  } from '../../../generated';
+
+@ObjectType()
+export class SearchFTSOutput {
+    @Field(type => SearchSearchItem)
+    item!: typeof SearchSearchItem
+
+    @Field(type => Float)
+    rank!: number
+
+    @Field(type => String)
+    isTypeOf!: string
+
+    @Field(type => String)
+    highlight!: string
+}
+
+export const SearchSearchItem = createUnionType({
+    name: "SearchSearchResult",
+    types: () => [
+        Channel,
+        Video,
+    ],
+});
+
+
+@Resolver()
+export default class SearchFTSResolver {
+
+    constructor(@Inject('SearchFTSService') readonly service: SearchFTSService) {}
+
+    @Query(() => [SearchFTSOutput])
+    async search(
+      @Arg('text') query: string, 
+      @Arg('limit', () => Int, { defaultValue: 5 }) limit: number,
+      @Arg('skip', () => Int, { defaultValue: 0 }) skip: number,
+      @Arg('whereChannel', { nullable: true }) whereChannel?: ChannelWhereInput,
+      @Arg('whereVideo', { nullable: true }) whereVideo?: VideoWhereInput,
+    ):Promise<Array<SearchFTSOutput>>{
+      return this.service.search(query, limit, skip, whereChannel,whereVideo,);
+    }
+
+}

+ 175 - 0
query-node/generated/graphql-server/src/modules/queries/search.service.ts

@@ -0,0 +1,175 @@
+import { Service, Inject } from 'typedi';
+import { Channel } from '../channel/channel.model';
+import { ChannelService } from '../channel/channel.service';
+import { Video } from '../video/video.model';
+import { VideoService } from '../video/video.service';
+
+import {  ChannelWhereInput,  VideoWhereInput,  } from '../../../generated';
+
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { Repository, getConnection, EntityManager } from 'typeorm';
+
+import { SearchFTSOutput } from './search.resolver';
+
+interface RawSQLResult {
+    origin_table: string,
+    id: string,
+    rank: number,
+    highlight: string
+}
+
+@Service('SearchFTSService')
+export class SearchFTSService {
+    readonly channelRepository: Repository<Channel>;
+    readonly videoRepository: Repository<Video>;
+
+    constructor(
+      @InjectRepository(Channel) channelRepository: Repository<Channel>,@InjectRepository(Video) videoRepository: Repository<Video>
+      ,@Inject('ChannelService') public readonly channelService: ChannelService ,@Inject('VideoService') public readonly videoService: VideoService 
+    ) {
+       this.channelRepository = channelRepository;  this.videoRepository = videoRepository;  
+    }
+
+    /**
+    * It takes available where inputs for the full text search(fts), generates sql queries
+    * to be run with fts query.
+    * @param wheres WhereInput[]
+    */
+    private async processWheres(wheres: any[]): Promise<[string, any[], number]> {
+      const services: any[] = [this.channelService, this.videoService, ]
+      const repositories = [this.channelRepository, this.videoRepository, ]
+      let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+      const generateSqlQuery = (table: string, where: string) =>
+        `
+  SELECT '${table}_' || id AS unique_id FROM "${table}" ` + where;
+
+      wheres.map((w, index) => {
+        if (w) {
+          let WHERE = `WHERE `;
+          // Combine queries
+          if (queries !== ``) {
+            queries = queries.concat(`
+  UNION ALL`);
+          }
+
+          const qb = services[index].buildFindQuery(w as any, undefined, undefined, ['id']);
+          // Add query parameters to the parameters list
+          parameters.push(...qb.getQueryAndParameters()[1]);
+
+          // Remove the last item which is "table_name"."deleted_at" IS NULL
+          qb.expressionMap.wheres.pop();
+
+          // Combine conditions
+          qb.expressionMap.wheres.map((w: any, index: number) => {
+            let c = ``;
+
+            if (w.condition.includes(`IN (:...`)) {
+              // IN condition parameters
+              const params: any[] = qb.expressionMap.parameters[`param${index}`];
+
+              // Do nothing when IN condition has an empty list of values
+              if (params.length !== 0) {
+                const paramsAsString = params
+                  .map((_: any) => {
+                    parameterCounter += 1;
+                    return `$${parameterCounter}`;
+                  })
+                  .join(`, `);
+                c = w.condition.replace(`(:...param${index})`, `(${paramsAsString})`);
+              }
+            } else if (w.condition.includes(`->>`)) {
+              parameterCounter += 1;
+              const m = w.condition.match(/->>.*\s=\s:.*/g);
+              if (m === null)
+                throw Error(`Failed to construct where condition for json field: ${w.condition}`);
+              c = w.condition.replace(/=\s:.*/g, `= $${parameterCounter}`);
+            } else {
+              parameterCounter += 1;
+              c = w.condition.replace(`:param${index}`, `$${parameterCounter}`);
+            }
+            WHERE = WHERE.concat(c, ` `, w.type.toUpperCase(), ` `);
+          });
+
+          // Remove unnecessary AND at the end.
+          WHERE = WHERE.slice(0, -4);
+
+          // Add new query to queryString
+          queries = queries.concat(generateSqlQuery(repositories[index].metadata.tableName, WHERE));
+        }
+      });
+
+      queries = `
+  WITH selected_ids AS (`.concat(
+        queries,
+        `
+  )`
+      );
+      return [queries, parameters, parameterCounter];
+    }
+
+    async search(
+      text: string,
+      limit = 5,
+      skip = 0,
+      whereChannel?: ChannelWhereInput,whereVideo?: VideoWhereInput,
+    ): Promise<SearchFTSOutput[]> {
+        const wheres = [whereChannel, whereVideo, ]
+        let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+        if (wheres.some(f => f !== undefined)) {
+          [queries, parameters, parameterCounter] = await this.processWheres(wheres);
+        }
+        parameters.push(...[text, limit, skip]);
+
+        return getConnection().transaction<SearchFTSOutput[]>(
+          'REPEATABLE READ',
+          async (em: EntityManager) => {
+            const query = `
+              ${queries}
+              SELECT origin_table, id, 
+                  ts_rank(tsv, phraseto_tsquery('english', $${parameterCounter + 1})) as rank,
+                  ts_headline(document, phraseto_tsquery('english', $${parameterCounter +
+                    1})) as highlight
+              FROM search_view
+              WHERE phraseto_tsquery('english', $${parameterCounter + 1}) @@ tsv
+              ${
+                queries !== ``
+                  ? `AND unique_id IN (SELECT unique_id FROM selected_ids)`
+                  : ``
+              } 
+              ORDER BY rank DESC
+              LIMIT $${parameterCounter + 2}
+              OFFSET $${parameterCounter + 3}`;
+            const results = (await em.query(query, parameters)) as RawSQLResult[];
+
+            if (results.length === 0) {
+                return [];
+            }
+
+            const idMap:{ [id:string]: RawSQLResult } = {};
+            results.forEach(item => idMap[item.id] = item);
+            const ids: string[] = results.map(item => item.id);
+            
+            const channels: Channel[] = await em.createQueryBuilder<Channel>(Channel, 'Channel')
+                        .where("id IN (:...ids)", { ids }).getMany();
+            const videos: Video[] = await em.createQueryBuilder<Video>(Video, 'Video')
+                        .where("id IN (:...ids)", { ids }).getMany();
+
+            const enhancedEntities = [...channels ,...videos ].map((e) => {
+                return { item: e, 
+                    rank: idMap[e.id].rank, 
+                    highlight: idMap[e.id].highlight,
+                    isTypeOf: idMap[e.id].origin_table } as SearchFTSOutput;
+            });
+
+            return enhancedEntities.reduce((accum: SearchFTSOutput[], entity) => {
+                if (entity.rank > 0) {
+                    accum.push(entity);
+                }
+                return accum;
+            }, []).sort((a,b) => b.rank - a.rank);
+
+        })
+    }
+}

+ 46 - 0
query-node/generated/graphql-server/src/modules/queries/videoCategoriesByName.resolver.ts

@@ -0,0 +1,46 @@
+import { ObjectType, Field, Float, Int, Arg, Query, Resolver, createUnionType } from 'type-graphql';
+import { Inject } from 'typedi';
+import { VideoCategory } from '../video-category/video-category.model';
+import { VideoCategoriesByNameFTSService } from './videoCategoriesByName.service';
+
+import {  VideoCategoryWhereInput,  } from '../../../generated';
+
+@ObjectType()
+export class VideoCategoriesByNameFTSOutput {
+    @Field(type => VideoCategoriesByNameSearchItem)
+    item!: typeof VideoCategoriesByNameSearchItem
+
+    @Field(type => Float)
+    rank!: number
+
+    @Field(type => String)
+    isTypeOf!: string
+
+    @Field(type => String)
+    highlight!: string
+}
+
+export const VideoCategoriesByNameSearchItem = createUnionType({
+    name: "VideoCategoriesByNameSearchResult",
+    types: () => [
+        VideoCategory,
+    ],
+});
+
+
+@Resolver()
+export default class VideoCategoriesByNameFTSResolver {
+
+    constructor(@Inject('VideoCategoriesByNameFTSService') readonly service: VideoCategoriesByNameFTSService) {}
+
+    @Query(() => [VideoCategoriesByNameFTSOutput])
+    async videoCategoriesByName(
+      @Arg('text') query: string, 
+      @Arg('limit', () => Int, { defaultValue: 5 }) limit: number,
+      @Arg('skip', () => Int, { defaultValue: 0 }) skip: number,
+      @Arg('whereVideoCategory', { nullable: true }) whereVideoCategory?: VideoCategoryWhereInput,
+    ):Promise<Array<VideoCategoriesByNameFTSOutput>>{
+      return this.service.search(query, limit, skip, whereVideoCategory,);
+    }
+
+}

+ 170 - 0
query-node/generated/graphql-server/src/modules/queries/videoCategoriesByName.service.ts

@@ -0,0 +1,170 @@
+import { Service, Inject } from 'typedi';
+import { VideoCategory } from '../video-category/video-category.model';
+import { VideoCategoryService } from '../video-category/video-category.service';
+
+import {  VideoCategoryWhereInput,  } from '../../../generated';
+
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { Repository, getConnection, EntityManager } from 'typeorm';
+
+import { VideoCategoriesByNameFTSOutput } from './videoCategoriesByName.resolver';
+
+interface RawSQLResult {
+    origin_table: string,
+    id: string,
+    rank: number,
+    highlight: string
+}
+
+@Service('VideoCategoriesByNameFTSService')
+export class VideoCategoriesByNameFTSService {
+    readonly videoCategoryRepository: Repository<VideoCategory>;
+
+    constructor(
+      @InjectRepository(VideoCategory) videoCategoryRepository: Repository<VideoCategory>
+      ,@Inject('VideoCategoryService') public readonly videoCategoryService: VideoCategoryService 
+    ) {
+       this.videoCategoryRepository = videoCategoryRepository;  
+    }
+
+    /**
+    * It takes available where inputs for the full text search(fts), generates sql queries
+    * to be run with fts query.
+    * @param wheres WhereInput[]
+    */
+    private async processWheres(wheres: any[]): Promise<[string, any[], number]> {
+      const services: any[] = [this.videoCategoryService, ]
+      const repositories = [this.videoCategoryRepository, ]
+      let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+      const generateSqlQuery = (table: string, where: string) =>
+        `
+  SELECT '${table}_' || id AS unique_id FROM "${table}" ` + where;
+
+      wheres.map((w, index) => {
+        if (w) {
+          let WHERE = `WHERE `;
+          // Combine queries
+          if (queries !== ``) {
+            queries = queries.concat(`
+  UNION ALL`);
+          }
+
+          const qb = services[index].buildFindQuery(w as any, undefined, undefined, ['id']);
+          // Add query parameters to the parameters list
+          parameters.push(...qb.getQueryAndParameters()[1]);
+
+          // Remove the last item which is "table_name"."deleted_at" IS NULL
+          qb.expressionMap.wheres.pop();
+
+          // Combine conditions
+          qb.expressionMap.wheres.map((w: any, index: number) => {
+            let c = ``;
+
+            if (w.condition.includes(`IN (:...`)) {
+              // IN condition parameters
+              const params: any[] = qb.expressionMap.parameters[`param${index}`];
+
+              // Do nothing when IN condition has an empty list of values
+              if (params.length !== 0) {
+                const paramsAsString = params
+                  .map((_: any) => {
+                    parameterCounter += 1;
+                    return `$${parameterCounter}`;
+                  })
+                  .join(`, `);
+                c = w.condition.replace(`(:...param${index})`, `(${paramsAsString})`);
+              }
+            } else if (w.condition.includes(`->>`)) {
+              parameterCounter += 1;
+              const m = w.condition.match(/->>.*\s=\s:.*/g);
+              if (m === null)
+                throw Error(`Failed to construct where condition for json field: ${w.condition}`);
+              c = w.condition.replace(/=\s:.*/g, `= $${parameterCounter}`);
+            } else {
+              parameterCounter += 1;
+              c = w.condition.replace(`:param${index}`, `$${parameterCounter}`);
+            }
+            WHERE = WHERE.concat(c, ` `, w.type.toUpperCase(), ` `);
+          });
+
+          // Remove unnecessary AND at the end.
+          WHERE = WHERE.slice(0, -4);
+
+          // Add new query to queryString
+          queries = queries.concat(generateSqlQuery(repositories[index].metadata.tableName, WHERE));
+        }
+      });
+
+      queries = `
+  WITH selected_ids AS (`.concat(
+        queries,
+        `
+  )`
+      );
+      return [queries, parameters, parameterCounter];
+    }
+
+    async search(
+      text: string,
+      limit = 5,
+      skip = 0,
+      whereVideoCategory?: VideoCategoryWhereInput,
+    ): Promise<VideoCategoriesByNameFTSOutput[]> {
+        const wheres = [whereVideoCategory, ]
+        let [queries, parameters, parameterCounter]: [string, any[], number] = [``, [], 0];
+
+        if (wheres.some(f => f !== undefined)) {
+          [queries, parameters, parameterCounter] = await this.processWheres(wheres);
+        }
+        parameters.push(...[text, limit, skip]);
+
+        return getConnection().transaction<VideoCategoriesByNameFTSOutput[]>(
+          'REPEATABLE READ',
+          async (em: EntityManager) => {
+            const query = `
+              ${queries}
+              SELECT origin_table, id, 
+                  ts_rank(tsv, phraseto_tsquery('english', $${parameterCounter + 1})) as rank,
+                  ts_headline(document, phraseto_tsquery('english', $${parameterCounter +
+                    1})) as highlight
+              FROM video_categories_by_name_view
+              WHERE phraseto_tsquery('english', $${parameterCounter + 1}) @@ tsv
+              ${
+                queries !== ``
+                  ? `AND unique_id IN (SELECT unique_id FROM selected_ids)`
+                  : ``
+              } 
+              ORDER BY rank DESC
+              LIMIT $${parameterCounter + 2}
+              OFFSET $${parameterCounter + 3}`;
+            const results = (await em.query(query, parameters)) as RawSQLResult[];
+
+            if (results.length === 0) {
+                return [];
+            }
+
+            const idMap:{ [id:string]: RawSQLResult } = {};
+            results.forEach(item => idMap[item.id] = item);
+            const ids: string[] = results.map(item => item.id);
+            
+            const videoCategorys: VideoCategory[] = await em.createQueryBuilder<VideoCategory>(VideoCategory, 'VideoCategory')
+                        .where("id IN (:...ids)", { ids }).getMany();
+
+            const enhancedEntities = [...videoCategorys ].map((e) => {
+                return { item: e, 
+                    rank: idMap[e.id].rank, 
+                    highlight: idMap[e.id].highlight,
+                    isTypeOf: idMap[e.id].origin_table } as VideoCategoriesByNameFTSOutput;
+            });
+
+            return enhancedEntities.reduce((accum: VideoCategoriesByNameFTSOutput[], entity) => {
+                if (entity.rank > 0) {
+                    accum.push(entity);
+                }
+                return accum;
+            }, []).sort((a,b) => b.rank - a.rank);
+
+        })
+    }
+}

+ 85 - 0
query-node/generated/graphql-server/src/modules/variants/variants.model.ts

@@ -0,0 +1,85 @@
+import {
+  BaseModel,
+  BooleanField,
+  DateField,
+  FloatField,
+  IntField,
+  NumericField,
+  JSONField,
+  BytesField,
+  EnumField,
+  StringField,
+} from 'warthog';
+
+import { ObjectType, Field, createUnionType } from 'type-graphql';
+
+@ObjectType()
+export class DataObjectOwnerChannel {
+  public isTypeOf: string = 'DataObjectOwnerChannel';
+
+  @IntField({
+    description: `Channel identifier`,
+  })
+  channel!: number;
+
+  @IntField({
+    nullable: true,
+    description: `Variant needs to have at least one property. This value is not used.`,
+  })
+  dummy?: number;
+}
+@ObjectType()
+export class DataObjectOwnerCouncil {
+  public isTypeOf: string = 'DataObjectOwnerCouncil';
+
+  @IntField({
+    nullable: true,
+    description: `Variant needs to have at least one property. This value is not used.`,
+  })
+  dummy?: number;
+}
+@ObjectType()
+export class DataObjectOwnerDao {
+  public isTypeOf: string = 'DataObjectOwnerDao';
+
+  @IntField({
+    description: `DAO identifier`,
+  })
+  dao!: number;
+}
+@ObjectType()
+export class DataObjectOwnerMember {
+  public isTypeOf: string = 'DataObjectOwnerMember';
+
+  @IntField({
+    description: `Member identifier`,
+  })
+  member!: number;
+
+  @IntField({
+    nullable: true,
+    description: `Variant needs to have at least one property. This value is not used.`,
+  })
+  dummy?: number;
+}
+@ObjectType()
+export class DataObjectOwnerWorkingGroup {
+  public isTypeOf: string = 'DataObjectOwnerWorkingGroup';
+
+  @IntField({
+    description: `Working group identifier`,
+  })
+  workingGroup!: number;
+}
+
+export const DataObjectOwner = createUnionType({
+  name: 'DataObjectOwner',
+  types: () => [
+    DataObjectOwnerMember,
+    DataObjectOwnerChannel,
+    DataObjectOwnerDao,
+    DataObjectOwnerCouncil,
+    DataObjectOwnerWorkingGroup,
+  ],
+  resolveType: (value) => (value.isTypeOf ? value.isTypeOf : undefined),
+});

+ 23 - 0
query-node/generated/graphql-server/src/modules/video-category/video-category.model.ts

@@ -0,0 +1,23 @@
+import { BaseModel, IntField, Model, OneToMany, StringField } from 'warthog';
+
+import { Video } from '../video/video.model';
+
+@Model({ api: {} })
+export class VideoCategory extends BaseModel {
+  @StringField({
+    nullable: true,
+    description: `The name of the category`,
+  })
+  name?: string;
+
+  @OneToMany(() => Video, (param: Video) => param.category, { cascade: ["insert", "update"] })
+  videos?: Video[];
+
+  @IntField({})
+  createdInBlock!: number;
+
+  constructor(init?: Partial<VideoCategory>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/video-category/video-category.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  VideoCategoryCreateInput,
+  VideoCategoryCreateManyArgs,
+  VideoCategoryUpdateArgs,
+  VideoCategoryWhereArgs,
+  VideoCategoryWhereInput,
+  VideoCategoryWhereUniqueInput,
+  VideoCategoryOrderByEnum,
+} from '../../../generated';
+
+import { VideoCategory } from './video-category.model';
+import { VideoCategoryService } from './video-category.service';
+
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class VideoCategoryEdge {
+  @Field(() => VideoCategory, { nullable: false })
+  node!: VideoCategory;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class VideoCategoryConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [VideoCategoryEdge], { nullable: false })
+  edges!: VideoCategoryEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class VideoCategoryConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => VideoCategoryWhereInput, { nullable: true })
+  where?: VideoCategoryWhereInput;
+
+  @Field(() => VideoCategoryOrderByEnum, { nullable: true })
+  orderBy?: VideoCategoryOrderByEnum;
+}
+
+@Resolver(VideoCategory)
+export class VideoCategoryResolver {
+  constructor(@Inject('VideoCategoryService') public readonly service: VideoCategoryService) {}
+
+  @Query(() => [VideoCategory])
+  async videoCategories(
+    @Args() { where, orderBy, limit, offset }: VideoCategoryWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<VideoCategory[]> {
+    return this.service.find<VideoCategoryWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => VideoCategory, { nullable: true })
+  async videoCategoryByUniqueInput(
+    @Arg('where') where: VideoCategoryWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<VideoCategory | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => VideoCategoryConnection)
+  async videoCategoriesConnection(
+    @Args() { where, orderBy, ...pageOptions }: VideoCategoryConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<VideoCategoryConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<VideoCategoryWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<VideoCategoryConnection>;
+  }
+
+  @FieldResolver(() => Video)
+  async videos(@Root() r: VideoCategory): Promise<Video[] | null> {
+    const result = await getConnection()
+      .getRepository(VideoCategory)
+      .findOne(r.id, { relations: ['videos'] });
+    if (result && result.videos !== undefined) {
+      return result.videos;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/video-category/video-category.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { VideoCategory } from './video-category.model';
+
+@Service('VideoCategoryService')
+export class VideoCategoryService extends BaseService<VideoCategory> {
+  constructor(@InjectRepository(VideoCategory) protected readonly repository: Repository<VideoCategory>) {
+    super(VideoCategory, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<VideoCategory[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 32 - 0
query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model.ts

@@ -0,0 +1,32 @@
+import { BaseModel, Model, OneToMany, StringField } from 'warthog';
+
+import { VideoMediaMetadata } from '../video-media-metadata/video-media-metadata.model';
+
+@Model({ api: {} })
+export class VideoMediaEncoding extends BaseModel {
+  @StringField({
+    nullable: true,
+    description: `Encoding of the video media object`,
+  })
+  codecName?: string;
+
+  @StringField({
+    nullable: true,
+    description: `Media container format`,
+  })
+  container?: string;
+
+  @StringField({
+    nullable: true,
+    description: `Content MIME type`,
+  })
+  mimeMediaType?: string;
+
+  @OneToMany(() => VideoMediaMetadata, (param: VideoMediaMetadata) => param.encoding, { nullable: true, cascade: ["insert", "update"] })
+  videomediametadataencoding?: VideoMediaMetadata[];
+
+  constructor(init?: Partial<VideoMediaEncoding>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 142 - 0
query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.resolver.ts

@@ -0,0 +1,142 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  VideoMediaEncodingCreateInput,
+  VideoMediaEncodingCreateManyArgs,
+  VideoMediaEncodingUpdateArgs,
+  VideoMediaEncodingWhereArgs,
+  VideoMediaEncodingWhereInput,
+  VideoMediaEncodingWhereUniqueInput,
+  VideoMediaEncodingOrderByEnum,
+} from '../../../generated';
+
+import { VideoMediaEncoding } from './video-media-encoding.model';
+import { VideoMediaEncodingService } from './video-media-encoding.service';
+
+import { VideoMediaMetadata } from '../video-media-metadata/video-media-metadata.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class VideoMediaEncodingEdge {
+  @Field(() => VideoMediaEncoding, { nullable: false })
+  node!: VideoMediaEncoding;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class VideoMediaEncodingConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [VideoMediaEncodingEdge], { nullable: false })
+  edges!: VideoMediaEncodingEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class VideoMediaEncodingConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => VideoMediaEncodingWhereInput, { nullable: true })
+  where?: VideoMediaEncodingWhereInput;
+
+  @Field(() => VideoMediaEncodingOrderByEnum, { nullable: true })
+  orderBy?: VideoMediaEncodingOrderByEnum;
+}
+
+@Resolver(VideoMediaEncoding)
+export class VideoMediaEncodingResolver {
+  constructor(@Inject('VideoMediaEncodingService') public readonly service: VideoMediaEncodingService) {}
+
+  @Query(() => [VideoMediaEncoding])
+  async videoMediaEncodings(
+    @Args() { where, orderBy, limit, offset }: VideoMediaEncodingWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<VideoMediaEncoding[]> {
+    return this.service.find<VideoMediaEncodingWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => VideoMediaEncoding, { nullable: true })
+  async videoMediaEncodingByUniqueInput(
+    @Arg('where') where: VideoMediaEncodingWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<VideoMediaEncoding | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => VideoMediaEncodingConnection)
+  async videoMediaEncodingsConnection(
+    @Args() { where, orderBy, ...pageOptions }: VideoMediaEncodingConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<VideoMediaEncodingConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<VideoMediaEncodingWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<VideoMediaEncodingConnection>;
+  }
+
+  @FieldResolver(() => VideoMediaMetadata)
+  async videomediametadataencoding(@Root() r: VideoMediaEncoding): Promise<VideoMediaMetadata[] | null> {
+    const result = await getConnection()
+      .getRepository(VideoMediaEncoding)
+      .findOne(r.id, { relations: ['videomediametadataencoding'] });
+    if (result && result.videomediametadataencoding !== undefined) {
+      return result.videomediametadataencoding;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { VideoMediaEncoding } from './video-media-encoding.model';
+
+@Service('VideoMediaEncodingService')
+export class VideoMediaEncodingService extends BaseService<VideoMediaEncoding> {
+  constructor(@InjectRepository(VideoMediaEncoding) protected readonly repository: Repository<VideoMediaEncoding>) {
+    super(VideoMediaEncoding, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<VideoMediaEncoding[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 43 - 0
query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.model.ts

@@ -0,0 +1,43 @@
+import { BaseModel, IntField, Model, ManyToOne, OneToOne, OneToOneJoin, StringField } from 'warthog';
+
+import { VideoMediaEncoding } from '../video-media-encoding/video-media-encoding.model';
+import { Video } from '../video/video.model';
+
+@Model({ api: {} })
+export class VideoMediaMetadata extends BaseModel {
+  @ManyToOne(() => VideoMediaEncoding, (param: VideoMediaEncoding) => param.videomediametadataencoding, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  encoding?: VideoMediaEncoding;
+
+  @IntField({
+    nullable: true,
+    description: `Video media width in pixels`,
+  })
+  pixelWidth?: number;
+
+  @IntField({
+    nullable: true,
+    description: `Video media height in pixels`,
+  })
+  pixelHeight?: number;
+
+  @IntField({
+    nullable: true,
+    description: `Video media size in bytes`,
+  })
+  size?: number;
+
+  @OneToOne(() => Video, (param: Video) => param.mediaMetadata, { nullable: true, cascade: ["insert", "update"] })
+  video?: Video;
+
+  @IntField({})
+  createdInBlock!: number;
+
+  constructor(init?: Partial<VideoMediaMetadata>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 154 - 0
query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.resolver.ts

@@ -0,0 +1,154 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  VideoMediaMetadataCreateInput,
+  VideoMediaMetadataCreateManyArgs,
+  VideoMediaMetadataUpdateArgs,
+  VideoMediaMetadataWhereArgs,
+  VideoMediaMetadataWhereInput,
+  VideoMediaMetadataWhereUniqueInput,
+  VideoMediaMetadataOrderByEnum,
+} from '../../../generated';
+
+import { VideoMediaMetadata } from './video-media-metadata.model';
+import { VideoMediaMetadataService } from './video-media-metadata.service';
+
+import { VideoMediaEncoding } from '../video-media-encoding/video-media-encoding.model';
+import { Video } from '../video/video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class VideoMediaMetadataEdge {
+  @Field(() => VideoMediaMetadata, { nullable: false })
+  node!: VideoMediaMetadata;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class VideoMediaMetadataConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [VideoMediaMetadataEdge], { nullable: false })
+  edges!: VideoMediaMetadataEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class VideoMediaMetadataConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => VideoMediaMetadataWhereInput, { nullable: true })
+  where?: VideoMediaMetadataWhereInput;
+
+  @Field(() => VideoMediaMetadataOrderByEnum, { nullable: true })
+  orderBy?: VideoMediaMetadataOrderByEnum;
+}
+
+@Resolver(VideoMediaMetadata)
+export class VideoMediaMetadataResolver {
+  constructor(@Inject('VideoMediaMetadataService') public readonly service: VideoMediaMetadataService) {}
+
+  @Query(() => [VideoMediaMetadata])
+  async videoMediaMetadata(
+    @Args() { where, orderBy, limit, offset }: VideoMediaMetadataWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<VideoMediaMetadata[]> {
+    return this.service.find<VideoMediaMetadataWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => VideoMediaMetadata, { nullable: true })
+  async videoMediaMetadataByUniqueInput(
+    @Arg('where') where: VideoMediaMetadataWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<VideoMediaMetadata | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => VideoMediaMetadataConnection)
+  async videoMediaMetadataConnection(
+    @Args() { where, orderBy, ...pageOptions }: VideoMediaMetadataConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<VideoMediaMetadataConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<VideoMediaMetadataWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<VideoMediaMetadataConnection>;
+  }
+
+  @FieldResolver(() => VideoMediaEncoding)
+  async encoding(@Root() r: VideoMediaMetadata): Promise<VideoMediaEncoding | null> {
+    const result = await getConnection()
+      .getRepository(VideoMediaMetadata)
+      .findOne(r.id, { relations: ['encoding'] });
+    if (result && result.encoding !== undefined) {
+      return result.encoding;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Video)
+  async video(@Root() r: VideoMediaMetadata): Promise<Video | null> {
+    const result = await getConnection()
+      .getRepository(VideoMediaMetadata)
+      .findOne(r.id, { relations: ['video'] });
+    if (result && result.video !== undefined) {
+      return result.video;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/video-media-metadata/video-media-metadata.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { VideoMediaMetadata } from './video-media-metadata.model';
+
+@Service('VideoMediaMetadataService')
+export class VideoMediaMetadataService extends BaseService<VideoMediaMetadata> {
+  constructor(@InjectRepository(VideoMediaMetadata) protected readonly repository: Repository<VideoMediaMetadata>) {
+    super(VideoMediaMetadata, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<VideoMediaMetadata[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 141 - 0
query-node/generated/graphql-server/src/modules/video/video.model.ts

@@ -0,0 +1,141 @@
+import {
+  BaseModel,
+  BooleanField,
+  IntField,
+  DateTimeField,
+  Model,
+  ManyToOne,
+  OneToOne,
+  OneToOneJoin,
+  CustomField,
+  EnumField,
+  StringField,
+} from 'warthog';
+
+import { Channel } from '../channel/channel.model';
+import { VideoCategory } from '../video-category/video-category.model';
+import { DataObject } from '../data-object/data-object.model';
+import { Language } from '../language/language.model';
+import { License } from '../license/license.model';
+import { VideoMediaMetadata } from '../video-media-metadata/video-media-metadata.model';
+import { FeaturedVideo } from '../featured-video/featured-video.model';
+
+import { AssetAvailability } from '../enums/enums';
+export { AssetAvailability };
+
+@Model({ api: {} })
+export class Video extends BaseModel {
+  @ManyToOne(() => Channel, (param: Channel) => param.videos, { skipGraphQLField: true, cascade: ["insert", "update"] })
+  channel!: Channel;
+
+  @ManyToOne(() => VideoCategory, (param: VideoCategory) => param.videos, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"] })
+  category?: VideoCategory;
+
+  @StringField({
+    nullable: true,
+    description: `The title of the video`,
+  })
+  title?: string;
+
+  @StringField({
+    nullable: true,
+    description: `The description of the Video`,
+  })
+  description?: string;
+
+  @IntField({
+    nullable: true,
+    description: `Video duration in seconds`,
+  })
+  duration?: number;
+
+  @ManyToOne(() => DataObject, (param: DataObject) => param.videothumbnailPhotoDataObject, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  thumbnailPhotoDataObject?: DataObject;
+
+  @CustomField({
+    db: { type: 'text', array: true },
+    api: { type: 'string', description: `URLs where the asset content can be accessed (if any)` },
+  })
+  thumbnailPhotoUrls!: string[];
+
+  @EnumField('AssetAvailability', AssetAvailability, {
+    description: `Availability meta information`,
+  })
+  thumbnailPhotoAvailability!: AssetAvailability;
+
+  @ManyToOne(() => Language, (param: Language) => param.videolanguage, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"] })
+  language?: Language;
+
+  @BooleanField({
+    nullable: true,
+    description: `Whether or not Video contains marketing`,
+  })
+  hasMarketing?: boolean;
+
+  @DateTimeField({
+    nullable: true,
+    description: `If the Video was published on other platform before beeing published on Joystream - the original publication date`,
+  })
+  publishedBeforeJoystream?: Date;
+
+  @BooleanField({
+    nullable: true,
+    description: `Whether the Video is supposed to be publically displayed`,
+  })
+  isPublic?: boolean;
+
+  @BooleanField({
+    description: `Flag signaling whether a video is censored.`,
+  })
+  isCensored!: boolean;
+
+  @BooleanField({
+    nullable: true,
+    description: `Whether the Video contains explicit material.`,
+  })
+  isExplicit?: boolean;
+
+  @ManyToOne(() => License, (param: License) => param.videolicense, { skipGraphQLField: true, nullable: true, cascade: ["insert", "update"] })
+  license?: License;
+
+  @ManyToOne(() => DataObject, (param: DataObject) => param.videomediaDataObject, {
+    skipGraphQLField: true,
+    nullable: true,
+    cascade: ["insert", "update"],
+  })
+  mediaDataObject?: DataObject;
+
+  @CustomField({
+    db: { type: 'text', array: true },
+    api: { type: 'string', description: `URLs where the asset content can be accessed (if any)` },
+  })
+  mediaUrls!: string[];
+
+  @EnumField('AssetAvailability', AssetAvailability, {
+    description: `Availability meta information`,
+  })
+  mediaAvailability!: AssetAvailability;
+
+  @OneToOneJoin(() => VideoMediaMetadata, (param: VideoMediaMetadata) => param.video, { nullable: true, cascade: ["insert", "update"] })
+  mediaMetadata?: VideoMediaMetadata;
+
+  @IntField({})
+  createdInBlock!: number;
+
+  @BooleanField({
+    description: `Is video featured or not`,
+  })
+  isFeatured!: boolean;
+
+  @OneToOne(() => FeaturedVideo, (param: FeaturedVideo) => param.video, { nullable: true, cascade: ["insert", "update"] })
+  featured?: FeaturedVideo;
+
+  constructor(init?: Partial<Video>) {
+    super();
+    Object.assign(this, init);
+  }
+}

+ 225 - 0
query-node/generated/graphql-server/src/modules/video/video.resolver.ts

@@ -0,0 +1,225 @@
+import {
+  Arg,
+  Args,
+  Mutation,
+  Query,
+  Root,
+  Resolver,
+  FieldResolver,
+  ObjectType,
+  Field,
+  Int,
+  ArgsType,
+  Info,
+} from 'type-graphql';
+import graphqlFields from 'graphql-fields';
+import { Inject } from 'typedi';
+import { Min } from 'class-validator';
+import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
+
+import {
+  VideoCreateInput,
+  VideoCreateManyArgs,
+  VideoUpdateArgs,
+  VideoWhereArgs,
+  VideoWhereInput,
+  VideoWhereUniqueInput,
+  VideoOrderByEnum,
+} from '../../../generated';
+
+import { Video } from './video.model';
+import { VideoService } from './video.service';
+
+import { Channel } from '../channel/channel.model';
+import { VideoCategory } from '../video-category/video-category.model';
+import { DataObject } from '../data-object/data-object.model';
+import { Language } from '../language/language.model';
+import { License } from '../license/license.model';
+import { VideoMediaMetadata } from '../video-media-metadata/video-media-metadata.model';
+import { FeaturedVideo } from '../featured-video/featured-video.model';
+import { getConnection } from 'typeorm';
+
+@ObjectType()
+export class VideoEdge {
+  @Field(() => Video, { nullable: false })
+  node!: Video;
+
+  @Field(() => String, { nullable: false })
+  cursor!: string;
+}
+
+@ObjectType()
+export class VideoConnection {
+  @Field(() => Int, { nullable: false })
+  totalCount!: number;
+
+  @Field(() => [VideoEdge], { nullable: false })
+  edges!: VideoEdge[];
+
+  @Field(() => PageInfo, { nullable: false })
+  pageInfo!: PageInfo;
+}
+
+@ArgsType()
+export class ConnectionPageInputOptions {
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  first?: number;
+
+  @Field(() => String, { nullable: true })
+  after?: string; // V3: TODO: should we make a RelayCursor scalar?
+
+  @Field(() => Int, { nullable: true })
+  @Min(0)
+  last?: number;
+
+  @Field(() => String, { nullable: true })
+  before?: string;
+}
+
+@ArgsType()
+export class VideoConnectionWhereArgs extends ConnectionPageInputOptions {
+  @Field(() => VideoWhereInput, { nullable: true })
+  where?: VideoWhereInput;
+
+  @Field(() => VideoOrderByEnum, { nullable: true })
+  orderBy?: VideoOrderByEnum;
+}
+
+@Resolver(Video)
+export class VideoResolver {
+  constructor(@Inject('VideoService') public readonly service: VideoService) {}
+
+  @Query(() => [Video])
+  async videos(
+    @Args() { where, orderBy, limit, offset }: VideoWhereArgs,
+    @Fields() fields: string[]
+  ): Promise<Video[]> {
+    return this.service.find<VideoWhereInput>(where, orderBy, limit, offset, fields);
+  }
+
+  @Query(() => Video, { nullable: true })
+  async videoByUniqueInput(
+    @Arg('where') where: VideoWhereUniqueInput,
+    @Fields() fields: string[]
+  ): Promise<Video | null> {
+    const result = await this.service.find(where, undefined, 1, 0, fields);
+    return result && result.length >= 1 ? result[0] : null;
+  }
+
+  @Query(() => VideoConnection)
+  async videosConnection(
+    @Args() { where, orderBy, ...pageOptions }: VideoConnectionWhereArgs,
+    @Info() info: any
+  ): Promise<VideoConnection> {
+    const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
+
+    let result: any = {
+      totalCount: 0,
+      edges: [],
+      pageInfo: {
+        hasNextPage: false,
+        hasPreviousPage: false,
+      },
+    };
+    // If the related database table does not have any records then an error is thrown to the client
+    // by warthog
+    try {
+      result = await this.service.findConnection<VideoWhereInput>(where, orderBy, pageOptions, rawFields);
+    } catch (err) {
+      console.log(err);
+      // TODO: should continue to return this on `Error: Items is empty` or throw the error
+      if (!(err.message as string).includes('Items is empty')) throw err;
+    }
+
+    return result as Promise<VideoConnection>;
+  }
+
+  @FieldResolver(() => Channel)
+  async channel(@Root() r: Video): Promise<Channel | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['channel'] });
+    if (result && result.channel !== undefined) {
+      return result.channel;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => VideoCategory)
+  async category(@Root() r: Video): Promise<VideoCategory | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['category'] });
+    if (result && result.category !== undefined) {
+      return result.category;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => DataObject)
+  async thumbnailPhotoDataObject(@Root() r: Video): Promise<DataObject | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['thumbnailPhotoDataObject'] });
+    if (result && result.thumbnailPhotoDataObject !== undefined) {
+      return result.thumbnailPhotoDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => Language)
+  async language(@Root() r: Video): Promise<Language | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['language'] });
+    if (result && result.language !== undefined) {
+      return result.language;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => License)
+  async license(@Root() r: Video): Promise<License | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['license'] });
+    if (result && result.license !== undefined) {
+      return result.license;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => DataObject)
+  async mediaDataObject(@Root() r: Video): Promise<DataObject | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['mediaDataObject'] });
+    if (result && result.mediaDataObject !== undefined) {
+      return result.mediaDataObject;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => VideoMediaMetadata)
+  async mediaMetadata(@Root() r: Video): Promise<VideoMediaMetadata | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['mediaMetadata'] });
+    if (result && result.mediaMetadata !== undefined) {
+      return result.mediaMetadata;
+    }
+    return null;
+  }
+
+  @FieldResolver(() => FeaturedVideo)
+  async featured(@Root() r: Video): Promise<FeaturedVideo | null> {
+    const result = await getConnection()
+      .getRepository(Video)
+      .findOne(r.id, { relations: ['featured'] });
+    if (result && result.featured !== undefined) {
+      return result.featured;
+    }
+    return null;
+  }
+}

+ 28 - 0
query-node/generated/graphql-server/src/modules/video/video.service.ts

@@ -0,0 +1,28 @@
+import { Service } from 'typedi';
+import { Repository } from 'typeorm';
+import { InjectRepository } from 'typeorm-typedi-extensions';
+import { BaseService, WhereInput } from 'warthog';
+
+import { Video } from './video.model';
+
+@Service('VideoService')
+export class VideoService extends BaseService<Video> {
+  constructor(@InjectRepository(Video) protected readonly repository: Repository<Video>) {
+    super(Video, repository);
+  }
+
+  async find<W extends WhereInput>(
+    where?: any,
+    orderBy?: string,
+    limit?: number,
+    offset?: number,
+    fields?: string[]
+  ): Promise<Video[]> {
+    let f = fields;
+    if (f == undefined) {
+      f = [];
+    }
+
+    return super.find<W>(where, orderBy, limit, offset, f);
+  }
+}

+ 38 - 0
query-node/generated/graphql-server/src/processor.resolver.ts

@@ -0,0 +1,38 @@
+import { Resolver, ObjectType, Field, Subscription, Root } from 'type-graphql'
+import { TOPICS } from './pubsub'
+
+@ObjectType()
+export class ProcessorState {
+  @Field()
+  lastCompleteBlock!: number
+
+  @Field()
+  lastProcessedEvent!: string
+
+  @Field()
+  indexerHead!: number
+
+  @Field()
+  chainHead!: number
+}
+
+@Resolver()
+export class ProcessorStateResolver {
+  @Subscription({ topics: TOPICS.processorState })
+  stateSubscription(
+    @Root()
+    state: {
+      lastScannedBlock?: number
+      lastProcessedEvent?: string
+      indexerHead?: number
+      chainHead?: number
+    }
+  ): ProcessorState {
+    return {
+      lastCompleteBlock: state.lastScannedBlock || -1,
+      lastProcessedEvent: state.lastProcessedEvent || 'NO_EVENTS',
+      indexerHead: state.indexerHead || -1,
+      chainHead: state.chainHead || -1,
+    }
+  }
+}

+ 52 - 0
query-node/generated/graphql-server/src/pubsub.ts

@@ -0,0 +1,52 @@
+import { PubSubEngine, PubSub } from 'graphql-subscriptions'
+
+import createSubscriber from 'pg-listen'
+import { Logger } from './logger'
+
+const pubSub: PubSubEngine = new PubSub()
+
+export enum TOPICS {
+  processorState = 'PROCESSOR_STATE',
+}
+
+export function getPubSub(): PubSubEngine {
+  return pubSub
+}
+
+export async function startPgSubsribers() {
+  // use PG_** env variables to connect
+  const subscriber = createSubscriber()
+  const channel = 'processed_events_log_update'
+
+  subscriber.notifications.on(channel, (payload: unknown) => {
+    const { data } = payload as {
+      data: {
+        event_id: string
+        last_scanned_block: number
+        indexer_head: number
+        chain_head: number
+      }
+    }
+
+    // Payload as passed to subscriber.notify() (see below)
+    pubSub.publish(TOPICS.processorState, {
+      lastProcessedEvent: data.event_id,
+      lastScannedBlock: data.last_scanned_block,
+      chainHead: data.chain_head,
+      indexerHead: data.indexer_head,
+    })
+  })
+
+  subscriber.events.on('error', (error) => {
+    Logger.error('Fatal database connection error:', error)
+    process.exit(1)
+  })
+
+  process.on('exit', () => {
+    Logger.log(`Closing the subscriber`)
+    subscriber.close()
+  })
+
+  await subscriber.connect()
+  await subscriber.listenTo(channel)
+}

+ 53 - 0
query-node/generated/graphql-server/src/server.ts

@@ -0,0 +1,53 @@
+import 'reflect-metadata';
+import { GraphQLID } from 'graphql';
+import { BaseContext, DataLoaderMiddleware, Server, ServerOptions } from 'warthog';
+import { DateResolver } from 'graphql-scalars';
+import { buildSchema } from 'type-graphql';
+
+import { Logger } from './logger';
+import { getPubSub } from './pubsub';
+
+interface Context extends BaseContext {
+  user: {
+    email: string;
+    id: string;
+    permissions: string;
+  };
+}
+
+export function getServer(AppOptions = {}, dbOptions = {}) {
+  return new Server<Context>(
+    {
+      introspection: true,
+      logger: Logger,
+      ...AppOptions,
+    },
+    dbOptions
+  );
+}
+
+export async function buildServerSchema<C extends BaseContext>(
+  server: Server<C>,
+  appOptions: ServerOptions<C> = {}
+): Promise<void> {
+  server.schema = await buildSchema({
+    authChecker: server.authChecker,
+    scalarsMap: [
+      {
+        type: 'ID' as any,
+        scalar: GraphQLID,
+      },
+      // Note: DateTime already included in type-graphql
+      {
+        type: 'DateOnlyString' as any,
+        scalar: DateResolver,
+      },
+    ],
+    container: server.container as any,
+    globalMiddlewares: [DataLoaderMiddleware, ...(appOptions.middlewares || [])],
+    resolvers: server.config.get('RESOLVERS_PATH'),
+    pubSub: getPubSub(),
+    // TODO: scalarsMap: [{ type: GraphQLDate, scalar: GraphQLDate }]
+    validate: server.config.get('VALIDATE_RESOLVERS') === 'true',
+  });
+}

+ 26 - 0
query-node/generated/graphql-server/tsconfig.json

@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "allowSyntheticDefaultImports": true,
+    "skipLibCheck": true,
+    "outDir": "./dist",
+    "lib": ["dom", "es5", "es6", "es7", "esnext"],
+    "target": "es5",
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "sourceMap": true,
+    "keyofStringsOnly": true,
+    "noImplicitAny": true,
+    "noImplicitReturns": true,
+    "noImplicitThis": true,
+    "noUnusedLocals": false,
+    "strict": true,
+    "strictNullChecks": true,
+    "types": ["isomorphic-fetch", "node"],
+    "esModuleInterop": true,
+    "declaration": true
+  },
+  "include": ["src/**/*", "db/**/*", "model/**/*"],
+  "exclude": ["node_modules/**/*", "generated/**/*", "tools/**/*"]
+}

+ 3 - 0
query-node/generated/graphql-server/warthog.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  cliGeneratePath: './src/modules/${kebabName}'
+};

+ 2477 - 0
query-node/generated/types/content.ts

@@ -0,0 +1,2477 @@
+import { createTypeUnsafe } from "@polkadot/types/create";
+import { SubstrateEvent, SubstrateExtrinsic } from "@dzlzv/hydra-common";
+import { Codec } from "@polkadot/types/types";
+import { typeRegistry } from ".";
+
+import {
+  Channel,
+  ChannelCategory,
+  ChannelCategoryCreationParameters,
+  ChannelCategoryId,
+  ChannelCategoryUpdateParameters,
+  ChannelCreationParameters,
+  ChannelId,
+  ChannelOwnershipTransferRequest,
+  ChannelOwnershipTransferRequestId,
+  ChannelUpdateParameters,
+  ContentActor,
+  ContentId,
+  CuratorGroupId,
+  CuratorId,
+  IsCensored,
+  PlaylistCreationParameters,
+  PlaylistId,
+  PlaylistUpdateParameters,
+  VideoCategoryCreationParameters,
+  VideoCategoryId,
+  VideoCategoryUpdateParameters,
+  VideoCreationParameters,
+  VideoId,
+  VideoUpdateParameters
+} from "@joystream/types/augment";
+import { Bytes, Vec, bool } from "@polkadot/types";
+
+export namespace Content {
+  export class CuratorGroupCreatedEvent {
+    public readonly expectedParamTypes = ["CuratorGroupId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): CuratorGroupCreated_Params {
+      return new CuratorGroupCreated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CuratorGroupCreated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.ctx.params[0].value]
+      );
+    }
+  }
+  export class CuratorGroupStatusSetEvent {
+    public readonly expectedParamTypes = ["CuratorGroupId", "bool"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): CuratorGroupStatusSet_Params {
+      return new CuratorGroupStatusSet_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CuratorGroupStatusSet_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get bool(): bool {
+      return createTypeUnsafe<bool & Codec>(typeRegistry, "bool", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+  export class CuratorAddedEvent {
+    public readonly expectedParamTypes = ["CuratorGroupId", "CuratorId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): CuratorAdded_Params {
+      return new CuratorAdded_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CuratorAdded_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get curatorId(): CuratorId {
+      return createTypeUnsafe<CuratorId & Codec>(typeRegistry, "CuratorId", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+  export class CuratorRemovedEvent {
+    public readonly expectedParamTypes = ["CuratorGroupId", "CuratorId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): CuratorRemoved_Params {
+      return new CuratorRemoved_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CuratorRemoved_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get curatorId(): CuratorId {
+      return createTypeUnsafe<CuratorId & Codec>(typeRegistry, "CuratorId", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+  export class ChannelCreatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelId",
+      "Channel",
+      "ChannelCreationParameters<ContentParameters, AccountId>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelCreated_Params {
+      return new ChannelCreated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelCreated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get channel(): Channel {
+      return createTypeUnsafe<Channel & Codec>(typeRegistry, "Channel", [
+        this.ctx.params[2].value
+      ]);
+    }
+
+    get channelCreationParameters(): ChannelCreationParameters {
+      return createTypeUnsafe<ChannelCreationParameters & Codec>(
+        typeRegistry,
+        "ChannelCreationParameters",
+        [this.ctx.params[3].value]
+      );
+    }
+  }
+  export class ChannelUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelId",
+      "Channel",
+      "ChannelUpdateParameters<ContentParameters, AccountId>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelUpdated_Params {
+      return new ChannelUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get channel(): Channel {
+      return createTypeUnsafe<Channel & Codec>(typeRegistry, "Channel", [
+        this.ctx.params[2].value
+      ]);
+    }
+
+    get channelUpdateParameters(): ChannelUpdateParameters {
+      return createTypeUnsafe<ChannelUpdateParameters & Codec>(
+        typeRegistry,
+        "ChannelUpdateParameters",
+        [this.ctx.params[3].value]
+      );
+    }
+  }
+  export class ChannelAssetsRemovedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelId",
+      "Vec<ContentId>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelAssetsRemoved_Params {
+      return new ChannelAssetsRemoved_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelAssetsRemoved_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get contentId(): Vec<ContentId> {
+      return createTypeUnsafe<Vec<ContentId> & Codec>(
+        typeRegistry,
+        "Vec<ContentId>",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class ChannelCensorshipStatusUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelId",
+      "IsCensored",
+      "Vec<u8>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelCensorshipStatusUpdated_Params {
+      return new ChannelCensorshipStatusUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelCensorshipStatusUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get isCensored(): IsCensored {
+      return createTypeUnsafe<IsCensored & Codec>(typeRegistry, "IsCensored", [
+        this.ctx.params[2].value
+      ]);
+    }
+
+    get bytes(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.ctx.params[3].value
+      ]);
+    }
+  }
+  export class ChannelOwnershipTransferRequestedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelOwnershipTransferRequestId",
+      "ChannelOwnershipTransferRequest"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelOwnershipTransferRequested_Params {
+      return new ChannelOwnershipTransferRequested_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelOwnershipTransferRequested_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelOwnershipTransferRequestId(): ChannelOwnershipTransferRequestId {
+      return createTypeUnsafe<ChannelOwnershipTransferRequestId & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequestId",
+        [this.ctx.params[1].value]
+      );
+    }
+
+    get channelOwnershipTransferRequest(): ChannelOwnershipTransferRequest {
+      return createTypeUnsafe<ChannelOwnershipTransferRequest & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequest",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class ChannelOwnershipTransferRequestWithdrawnEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelOwnershipTransferRequestId"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelOwnershipTransferRequestWithdrawn_Params {
+      return new ChannelOwnershipTransferRequestWithdrawn_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelOwnershipTransferRequestWithdrawn_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelOwnershipTransferRequestId(): ChannelOwnershipTransferRequestId {
+      return createTypeUnsafe<ChannelOwnershipTransferRequestId & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequestId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  export class ChannelOwnershipTransferredEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelOwnershipTransferRequestId"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelOwnershipTransferred_Params {
+      return new ChannelOwnershipTransferred_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelOwnershipTransferred_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelOwnershipTransferRequestId(): ChannelOwnershipTransferRequestId {
+      return createTypeUnsafe<ChannelOwnershipTransferRequestId & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequestId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  export class ChannelCategoryCreatedEvent {
+    public readonly expectedParamTypes = [
+      "ChannelCategoryId",
+      "ChannelCategory",
+      "ChannelCategoryCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelCategoryCreated_Params {
+      return new ChannelCategoryCreated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelCategoryCreated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get channelCategoryId(): ChannelCategoryId {
+      return createTypeUnsafe<ChannelCategoryId & Codec>(
+        typeRegistry,
+        "ChannelCategoryId",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelCategory(): ChannelCategory {
+      return createTypeUnsafe<ChannelCategory & Codec>(
+        typeRegistry,
+        "ChannelCategory",
+        [this.ctx.params[1].value]
+      );
+    }
+
+    get channelCategoryCreationParameters(): ChannelCategoryCreationParameters {
+      return createTypeUnsafe<ChannelCategoryCreationParameters & Codec>(
+        typeRegistry,
+        "ChannelCategoryCreationParameters",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class ChannelCategoryUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelCategoryId",
+      "ChannelCategoryUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelCategoryUpdated_Params {
+      return new ChannelCategoryUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelCategoryUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelCategoryId(): ChannelCategoryId {
+      return createTypeUnsafe<ChannelCategoryId & Codec>(
+        typeRegistry,
+        "ChannelCategoryId",
+        [this.ctx.params[1].value]
+      );
+    }
+
+    get channelCategoryUpdateParameters(): ChannelCategoryUpdateParameters {
+      return createTypeUnsafe<ChannelCategoryUpdateParameters & Codec>(
+        typeRegistry,
+        "ChannelCategoryUpdateParameters",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class ChannelCategoryDeletedEvent {
+    public readonly expectedParamTypes = ["ContentActor", "ChannelCategoryId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ChannelCategoryDeleted_Params {
+      return new ChannelCategoryDeleted_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChannelCategoryDeleted_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelCategoryId(): ChannelCategoryId {
+      return createTypeUnsafe<ChannelCategoryId & Codec>(
+        typeRegistry,
+        "ChannelCategoryId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  export class VideoCategoryCreatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "VideoCategoryId",
+      "VideoCategoryCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoCategoryCreated_Params {
+      return new VideoCategoryCreated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoCategoryCreated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoCategoryId(): VideoCategoryId {
+      return createTypeUnsafe<VideoCategoryId & Codec>(
+        typeRegistry,
+        "VideoCategoryId",
+        [this.ctx.params[1].value]
+      );
+    }
+
+    get videoCategoryCreationParameters(): VideoCategoryCreationParameters {
+      return createTypeUnsafe<VideoCategoryCreationParameters & Codec>(
+        typeRegistry,
+        "VideoCategoryCreationParameters",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class VideoCategoryUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "VideoCategoryId",
+      "VideoCategoryUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoCategoryUpdated_Params {
+      return new VideoCategoryUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoCategoryUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoCategoryId(): VideoCategoryId {
+      return createTypeUnsafe<VideoCategoryId & Codec>(
+        typeRegistry,
+        "VideoCategoryId",
+        [this.ctx.params[1].value]
+      );
+    }
+
+    get videoCategoryUpdateParameters(): VideoCategoryUpdateParameters {
+      return createTypeUnsafe<VideoCategoryUpdateParameters & Codec>(
+        typeRegistry,
+        "VideoCategoryUpdateParameters",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class VideoCategoryDeletedEvent {
+    public readonly expectedParamTypes = ["ContentActor", "VideoCategoryId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoCategoryDeleted_Params {
+      return new VideoCategoryDeleted_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoCategoryDeleted_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoCategoryId(): VideoCategoryId {
+      return createTypeUnsafe<VideoCategoryId & Codec>(
+        typeRegistry,
+        "VideoCategoryId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  export class VideoCreatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "ChannelId",
+      "VideoId",
+      "VideoCreationParameters<ContentParameters>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoCreated_Params {
+      return new VideoCreated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoCreated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.ctx.params[2].value
+      ]);
+    }
+
+    get videoCreationParameters(): VideoCreationParameters {
+      return createTypeUnsafe<VideoCreationParameters & Codec>(
+        typeRegistry,
+        "VideoCreationParameters",
+        [this.ctx.params[3].value]
+      );
+    }
+  }
+  export class VideoUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "VideoId",
+      "VideoUpdateParameters<ContentParameters>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoUpdated_Params {
+      return new VideoUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get videoUpdateParameters(): VideoUpdateParameters {
+      return createTypeUnsafe<VideoUpdateParameters & Codec>(
+        typeRegistry,
+        "VideoUpdateParameters",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class VideoDeletedEvent {
+    public readonly expectedParamTypes = ["ContentActor", "VideoId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoDeleted_Params {
+      return new VideoDeleted_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoDeleted_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+  export class VideoCensorshipStatusUpdatedEvent {
+    public readonly expectedParamTypes = [
+      "ContentActor",
+      "VideoId",
+      "IsCensored",
+      "Vec<u8>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): VideoCensorshipStatusUpdated_Params {
+      return new VideoCensorshipStatusUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class VideoCensorshipStatusUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get isCensored(): IsCensored {
+      return createTypeUnsafe<IsCensored & Codec>(typeRegistry, "IsCensored", [
+        this.ctx.params[2].value
+      ]);
+    }
+
+    get bytes(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.ctx.params[3].value
+      ]);
+    }
+  }
+  export class FeaturedVideosSetEvent {
+    public readonly expectedParamTypes = ["ContentActor", "Vec<VideoId>"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): FeaturedVideosSet_Params {
+      return new FeaturedVideosSet_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class FeaturedVideosSet_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentActor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get videoId(): Vec<VideoId> {
+      return createTypeUnsafe<Vec<VideoId> & Codec>(
+        typeRegistry,
+        "Vec<VideoId>",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+
+  /**
+   *  Add new curator group to runtime storage
+   */
+  export class CreateCuratorGroupCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreateCuratorGroup_Args {
+      return new CreateCuratorGroup_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreateCuratorGroup_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+  }
+  /**
+   *  Set `is_active` status for curator group under given `curator_group_id`
+   */
+  export class SetCuratorGroupStatusCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["CuratorGroupId", "bool"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): SetCuratorGroupStatus_Args {
+      return new SetCuratorGroupStatus_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class SetCuratorGroupStatus_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get isActive(): bool {
+      return createTypeUnsafe<bool & Codec>(typeRegistry, "bool", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  /**
+   *  Add curator to curator group under given `curator_group_id`
+   */
+  export class AddCuratorToGroupCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["CuratorGroupId", "CuratorId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): AddCuratorToGroup_Args {
+      return new AddCuratorToGroup_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class AddCuratorToGroup_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get curatorId(): CuratorId {
+      return createTypeUnsafe<CuratorId & Codec>(typeRegistry, "CuratorId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  /**
+   *  Remove curator from a given curator group
+   */
+  export class RemoveCuratorFromGroupCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["CuratorGroupId", "CuratorId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): RemoveCuratorFromGroup_Args {
+      return new RemoveCuratorFromGroup_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class RemoveCuratorFromGroup_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get curatorGroupId(): CuratorGroupId {
+      return createTypeUnsafe<CuratorGroupId & Codec>(
+        typeRegistry,
+        "CuratorGroupId",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get curatorId(): CuratorId {
+      return createTypeUnsafe<CuratorId & Codec>(typeRegistry, "CuratorId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  export class CreateChannelCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreateChannel_Args {
+      return new CreateChannel_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreateChannel_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get params(): ChannelCreationParameters {
+      return createTypeUnsafe<ChannelCreationParameters & Codec>(
+        typeRegistry,
+        "ChannelCreationParameters",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class UpdateChannelCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "ChannelUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateChannel_Args {
+      return new UpdateChannel_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateChannel_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get params(): ChannelUpdateParameters {
+      return createTypeUnsafe<ChannelUpdateParameters & Codec>(
+        typeRegistry,
+        "ChannelUpdateParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  /**
+   *  Remove assets of a channel from storage
+   */
+  export class RemoveChannelAssetsCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "Vec<ContentId>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): RemoveChannelAssets_Args {
+      return new RemoveChannelAssets_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class RemoveChannelAssets_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get assets(): Vec<ContentId> {
+      return createTypeUnsafe<Vec<ContentId> & Codec>(
+        typeRegistry,
+        "Vec<ContentId>",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class UpdateChannelCensorshipStatusCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "bool",
+      "Bytes"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateChannelCensorshipStatus_Args {
+      return new UpdateChannelCensorshipStatus_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateChannelCensorshipStatus_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get isCensored(): bool {
+      return createTypeUnsafe<bool & Codec>(typeRegistry, "bool", [
+        this.extrinsic.args[2].value
+      ]);
+    }
+
+    get rationale(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.extrinsic.args[3].value
+      ]);
+    }
+  }
+  export class CreateChannelCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelCategoryCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreateChannelCategory_Args {
+      return new CreateChannelCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreateChannelCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get params(): ChannelCategoryCreationParameters {
+      return createTypeUnsafe<ChannelCategoryCreationParameters & Codec>(
+        typeRegistry,
+        "ChannelCategoryCreationParameters",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class UpdateChannelCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelCategoryId",
+      "ChannelCategoryUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateChannelCategory_Args {
+      return new UpdateChannelCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateChannelCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get categoryId(): ChannelCategoryId {
+      return createTypeUnsafe<ChannelCategoryId & Codec>(
+        typeRegistry,
+        "ChannelCategoryId",
+        [this.extrinsic.args[1].value]
+      );
+    }
+
+    get params(): ChannelCategoryUpdateParameters {
+      return createTypeUnsafe<ChannelCategoryUpdateParameters & Codec>(
+        typeRegistry,
+        "ChannelCategoryUpdateParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class DeleteChannelCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ContentActor", "ChannelCategoryId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): DeleteChannelCategory_Args {
+      return new DeleteChannelCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class DeleteChannelCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get categoryId(): ChannelCategoryId {
+      return createTypeUnsafe<ChannelCategoryId & Codec>(
+        typeRegistry,
+        "ChannelCategoryId",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class RequestChannelTransferCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelOwnershipTransferRequest"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): RequestChannelTransfer_Args {
+      return new RequestChannelTransfer_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class RequestChannelTransfer_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get request(): ChannelOwnershipTransferRequest {
+      return createTypeUnsafe<ChannelOwnershipTransferRequest & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequest",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class CancelChannelTransferRequestCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ChannelOwnershipTransferRequestId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CancelChannelTransferRequest_Args {
+      return new CancelChannelTransferRequest_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CancelChannelTransferRequest_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get requestId(): ChannelOwnershipTransferRequestId {
+      return createTypeUnsafe<ChannelOwnershipTransferRequestId & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequestId",
+        [this.extrinsic.args[0].value]
+      );
+    }
+  }
+  export class AcceptChannelTransferCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelOwnershipTransferRequestId"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): AcceptChannelTransfer_Args {
+      return new AcceptChannelTransfer_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class AcceptChannelTransfer_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get requestId(): ChannelOwnershipTransferRequestId {
+      return createTypeUnsafe<ChannelOwnershipTransferRequestId & Codec>(
+        typeRegistry,
+        "ChannelOwnershipTransferRequestId",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class CreateVideoCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "VideoCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreateVideo_Args {
+      return new CreateVideo_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreateVideo_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get params(): VideoCreationParameters {
+      return createTypeUnsafe<VideoCreationParameters & Codec>(
+        typeRegistry,
+        "VideoCreationParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class UpdateVideoCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "VideoId",
+      "VideoUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateVideo_Args {
+      return new UpdateVideo_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateVideo_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get params(): VideoUpdateParameters {
+      return createTypeUnsafe<VideoUpdateParameters & Codec>(
+        typeRegistry,
+        "VideoUpdateParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class DeleteVideoCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ContentActor", "VideoId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): DeleteVideo_Args {
+      return new DeleteVideo_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class DeleteVideo_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  export class CreatePlaylistCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "PlaylistCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreatePlaylist_Args {
+      return new CreatePlaylist_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreatePlaylist_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get params(): PlaylistCreationParameters {
+      return createTypeUnsafe<PlaylistCreationParameters & Codec>(
+        typeRegistry,
+        "PlaylistCreationParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class UpdatePlaylistCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "PlaylistId",
+      "PlaylistUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdatePlaylist_Args {
+      return new UpdatePlaylist_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdatePlaylist_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get playlist(): PlaylistId {
+      return createTypeUnsafe<PlaylistId & Codec>(typeRegistry, "PlaylistId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get params(): PlaylistUpdateParameters {
+      return createTypeUnsafe<PlaylistUpdateParameters & Codec>(
+        typeRegistry,
+        "PlaylistUpdateParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class DeletePlaylistCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "ChannelId",
+      "PlaylistId"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): DeletePlaylist_Args {
+      return new DeletePlaylist_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class DeletePlaylist_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get channelId(): ChannelId {
+      return createTypeUnsafe<ChannelId & Codec>(typeRegistry, "ChannelId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get playlist(): PlaylistId {
+      return createTypeUnsafe<PlaylistId & Codec>(typeRegistry, "PlaylistId", [
+        this.extrinsic.args[2].value
+      ]);
+    }
+  }
+  export class SetFeaturedVideosCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ContentActor", "Vec<VideoId>"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): SetFeaturedVideos_Args {
+      return new SetFeaturedVideos_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class SetFeaturedVideos_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get list(): Vec<VideoId> {
+      return createTypeUnsafe<Vec<VideoId> & Codec>(
+        typeRegistry,
+        "Vec<VideoId>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class CreateVideoCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "VideoCategoryCreationParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): CreateVideoCategory_Args {
+      return new CreateVideoCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class CreateVideoCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get params(): VideoCategoryCreationParameters {
+      return createTypeUnsafe<VideoCategoryCreationParameters & Codec>(
+        typeRegistry,
+        "VideoCategoryCreationParameters",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class UpdateVideoCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "VideoCategoryId",
+      "VideoCategoryUpdateParameters"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateVideoCategory_Args {
+      return new UpdateVideoCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateVideoCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get categoryId(): VideoCategoryId {
+      return createTypeUnsafe<VideoCategoryId & Codec>(
+        typeRegistry,
+        "VideoCategoryId",
+        [this.extrinsic.args[1].value]
+      );
+    }
+
+    get params(): VideoCategoryUpdateParameters {
+      return createTypeUnsafe<VideoCategoryUpdateParameters & Codec>(
+        typeRegistry,
+        "VideoCategoryUpdateParameters",
+        [this.extrinsic.args[2].value]
+      );
+    }
+  }
+  export class DeleteVideoCategoryCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ContentActor", "VideoCategoryId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): DeleteVideoCategory_Args {
+      return new DeleteVideoCategory_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class DeleteVideoCategory_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get categoryId(): VideoCategoryId {
+      return createTypeUnsafe<VideoCategoryId & Codec>(
+        typeRegistry,
+        "VideoCategoryId",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  export class RemovePersonFromVideoCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ContentActor", "VideoId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): RemovePersonFromVideo_Args {
+      return new RemovePersonFromVideo_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class RemovePersonFromVideo_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  export class UpdateVideoCensorshipStatusCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ContentActor",
+      "VideoId",
+      "bool",
+      "Bytes"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateVideoCensorshipStatus_Args {
+      return new UpdateVideoCensorshipStatus_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateVideoCensorshipStatus_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get actor(): ContentActor {
+      return createTypeUnsafe<ContentActor & Codec>(
+        typeRegistry,
+        "ContentActor",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get videoId(): VideoId {
+      return createTypeUnsafe<VideoId & Codec>(typeRegistry, "VideoId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+
+    get isCensored(): bool {
+      return createTypeUnsafe<bool & Codec>(typeRegistry, "bool", [
+        this.extrinsic.args[2].value
+      ]);
+    }
+
+    get rationale(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.extrinsic.args[3].value
+      ]);
+    }
+  }
+}

+ 459 - 0
query-node/generated/types/data-directory.ts

@@ -0,0 +1,459 @@
+import { createTypeUnsafe } from "@polkadot/types/create";
+import { SubstrateEvent, SubstrateExtrinsic } from "@dzlzv/hydra-common";
+import { Codec } from "@polkadot/types/types";
+import { typeRegistry } from ".";
+
+import { Vec, bool } from "@polkadot/types";
+import {
+  ContentId,
+  ContentParameters,
+  ObjectOwner,
+  StorageObjectOwner,
+  StorageProviderId,
+  UploadingStatus
+} from "@joystream/types/augment";
+
+export namespace DataDirectory {
+  /**
+   *  Emits on adding of the content.
+   *  Params:
+   *  - Content parameters representation.
+   *  - StorageObjectOwner enum.
+   *
+   *  Event parameters: [Vec<ContentParameters>, StorageObjectOwner, ]
+   */
+  export class ContentAddedEvent {
+    public readonly expectedParamTypes = [
+      "Vec<ContentParameters>",
+      "StorageObjectOwner"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ContentAdded_Params {
+      return new ContentAdded_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ContentAdded_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentParameters(): Vec<ContentParameters> {
+      return createTypeUnsafe<Vec<ContentParameters> & Codec>(
+        typeRegistry,
+        "Vec<ContentParameters>",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get storageObjectOwner(): StorageObjectOwner {
+      return createTypeUnsafe<StorageObjectOwner & Codec>(
+        typeRegistry,
+        "StorageObjectOwner",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  /**
+   *  Emits on content removal.
+   *  Params:
+   *  - Content parameters representation.
+   *  - StorageObjectOwner enum.
+   *
+   *  Event parameters: [Vec<ContentId>, StorageObjectOwner, ]
+   */
+  export class ContentRemovedEvent {
+    public readonly expectedParamTypes = [
+      "Vec<ContentId>",
+      "StorageObjectOwner"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ContentRemoved_Params {
+      return new ContentRemoved_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ContentRemoved_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentId(): Vec<ContentId> {
+      return createTypeUnsafe<Vec<ContentId> & Codec>(
+        typeRegistry,
+        "Vec<ContentId>",
+        [this.ctx.params[0].value]
+      );
+    }
+
+    get storageObjectOwner(): StorageObjectOwner {
+      return createTypeUnsafe<StorageObjectOwner & Codec>(
+        typeRegistry,
+        "StorageObjectOwner",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  /**
+   *  Emits when the storage provider accepts a content.
+   *  Params:
+   *  - Id of the relationship.
+   *  - Id of the storage provider.
+   *
+   *  Event parameters: [ContentId, StorageProviderId, ]
+   */
+  export class ContentAcceptedEvent {
+    public readonly expectedParamTypes = ["ContentId", "StorageProviderId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ContentAccepted_Params {
+      return new ContentAccepted_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ContentAccepted_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentId(): ContentId {
+      return createTypeUnsafe<ContentId & Codec>(typeRegistry, "ContentId", [
+        this.ctx.params[0].value
+      ]);
+    }
+
+    get storageProviderId(): StorageProviderId {
+      return createTypeUnsafe<StorageProviderId & Codec>(
+        typeRegistry,
+        "StorageProviderId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  /**
+   *  Emits when the storage provider rejects a content.
+   *  Params:
+   *  - Id of the relationship.
+   *  - Id of the storage provider.
+   *
+   *  Event parameters: [ContentId, StorageProviderId, ]
+   */
+  export class ContentRejectedEvent {
+    public readonly expectedParamTypes = ["ContentId", "StorageProviderId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ContentRejected_Params {
+      return new ContentRejected_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ContentRejected_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get contentId(): ContentId {
+      return createTypeUnsafe<ContentId & Codec>(typeRegistry, "ContentId", [
+        this.ctx.params[0].value
+      ]);
+    }
+
+    get storageProviderId(): StorageProviderId {
+      return createTypeUnsafe<StorageProviderId & Codec>(
+        typeRegistry,
+        "StorageProviderId",
+        [this.ctx.params[1].value]
+      );
+    }
+  }
+  /**
+   *  Emits when the content uploading status update performed.
+   *  Params:
+   *  - UploadingStatus bool flag.
+   *
+   *  Event parameters: [UploadingStatus, ]
+   */
+  export class ContentUploadingStatusUpdatedEvent {
+    public readonly expectedParamTypes = ["UploadingStatus"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): ContentUploadingStatusUpdated_Params {
+      return new ContentUploadingStatusUpdated_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ContentUploadingStatusUpdated_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get uploadingStatus(): UploadingStatus {
+      return createTypeUnsafe<UploadingStatus & Codec>(
+        typeRegistry,
+        "UploadingStatus",
+        [this.ctx.params[0].value]
+      );
+    }
+  }
+
+  /**
+   *  Adds the content to the system. The created DataObject
+   *  awaits liaison to accept it.
+   */
+  export class AddContentCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "ObjectOwner",
+      "Vec<ContentParameters>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): AddContent_Args {
+      return new AddContent_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class AddContent_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get owner(): ObjectOwner {
+      return createTypeUnsafe<ObjectOwner & Codec>(
+        typeRegistry,
+        "ObjectOwner",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get content(): Vec<ContentParameters> {
+      return createTypeUnsafe<Vec<ContentParameters> & Codec>(
+        typeRegistry,
+        "Vec<ContentParameters>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  /**
+   *  Remove the content from the system.
+   */
+  export class RemoveContentCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["ObjectOwner", "Vec<ContentId>"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): RemoveContent_Args {
+      return new RemoveContent_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class RemoveContent_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get owner(): ObjectOwner {
+      return createTypeUnsafe<ObjectOwner & Codec>(
+        typeRegistry,
+        "ObjectOwner",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get contentIds(): Vec<ContentId> {
+      return createTypeUnsafe<Vec<ContentId> & Codec>(
+        typeRegistry,
+        "Vec<ContentId>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+  }
+  /**
+   *  Storage provider accepts a content. Requires signed storage provider account and its id.
+   *  The LiaisonJudgement can only be updated once from Pending to Accepted.
+   *  Subsequent calls are a no-op.
+   */
+  export class AcceptContentCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["StorageProviderId", "ContentId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): AcceptContent_Args {
+      return new AcceptContent_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class AcceptContent_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get storageProviderId(): StorageProviderId {
+      return createTypeUnsafe<StorageProviderId & Codec>(
+        typeRegistry,
+        "StorageProviderId",
+        [this.extrinsic.args[0].value]
+      );
+    }
+
+    get contentId(): ContentId {
+      return createTypeUnsafe<ContentId & Codec>(typeRegistry, "ContentId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  /**
+   *  Locks / unlocks content uploading
+   */
+  export class UpdateContentUploadingStatusCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["bool"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateContentUploadingStatus_Args {
+      return new UpdateContentUploadingStatus_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateContentUploadingStatus_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get isBlocked(): bool {
+      return createTypeUnsafe<bool & Codec>(typeRegistry, "bool", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+  }
+}

+ 14 - 0
query-node/generated/types/index.ts

@@ -0,0 +1,14 @@
+import { TypeRegistry } from "@polkadot/types";
+import path from "path";
+import fs from "fs";
+const typeRegistry = new TypeRegistry();
+
+typeRegistry.register(
+  JSON.parse(fs.readFileSync(path.join(__dirname, "typedefs.json"), "utf-8"))
+);
+
+export { typeRegistry };
+
+export * from "./members";
+export * from "./content";
+export * from "./data-directory";

+ 616 - 0
query-node/generated/types/members.ts

@@ -0,0 +1,616 @@
+import { createTypeUnsafe } from "@polkadot/types/create";
+import { SubstrateEvent, SubstrateExtrinsic } from "@dzlzv/hydra-common";
+import { Codec } from "@polkadot/types/types";
+import { typeRegistry } from ".";
+
+import { EntryMethod, MemberId, PaidTermId } from "@joystream/types/augment";
+import { AccountId, BalanceOf } from "@polkadot/types/interfaces";
+import { Bytes, Option } from "@polkadot/types";
+
+export namespace Members {
+  export class MemberRegisteredEvent {
+    public readonly expectedParamTypes = [
+      "MemberId",
+      "AccountId",
+      "EntryMethod<PaidTermId, AccountId>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberRegistered_Params {
+      return new MemberRegistered_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberRegistered_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+
+    get accountId(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.ctx.params[1].value
+      ]);
+    }
+
+    get entryMethod(): EntryMethod {
+      return createTypeUnsafe<EntryMethod & Codec>(
+        typeRegistry,
+        "EntryMethod",
+        [this.ctx.params[2].value]
+      );
+    }
+  }
+  export class MemberUpdatedAboutTextEvent {
+    public readonly expectedParamTypes = ["MemberId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberUpdatedAboutText_Params {
+      return new MemberUpdatedAboutText_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberUpdatedAboutText_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+  }
+  export class MemberUpdatedAvatarEvent {
+    public readonly expectedParamTypes = ["MemberId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberUpdatedAvatar_Params {
+      return new MemberUpdatedAvatar_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberUpdatedAvatar_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+  }
+  export class MemberUpdatedHandleEvent {
+    public readonly expectedParamTypes = ["MemberId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberUpdatedHandle_Params {
+      return new MemberUpdatedHandle_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberUpdatedHandle_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+  }
+  export class MemberSetRootAccountEvent {
+    public readonly expectedParamTypes = ["MemberId", "AccountId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberSetRootAccount_Params {
+      return new MemberSetRootAccount_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberSetRootAccount_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+
+    get accountId(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+  export class MemberSetControllerAccountEvent {
+    public readonly expectedParamTypes = ["MemberId", "AccountId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get data(): MemberSetControllerAccount_Params {
+      return new MemberSetControllerAccount_Params(this.ctx);
+    }
+
+    validateParams(): boolean {
+      if (this.expectedParamTypes.length !== this.ctx.params.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedParamTypes.forEach((type, i) => {
+        if (type !== this.ctx.params[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class MemberSetControllerAccount_Params {
+    constructor(public readonly ctx: SubstrateEvent) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.ctx.params[0].value
+      ]);
+    }
+
+    get accountId(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.ctx.params[1].value
+      ]);
+    }
+  }
+
+  /**
+   *  Non-members can buy membership
+   */
+  export class BuyMembershipCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "PaidTermId",
+      "Option<Bytes>",
+      "Option<Bytes>",
+      "Option<Bytes>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): BuyMembership_Args {
+      return new BuyMembership_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class BuyMembership_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get paidTermsId(): PaidTermId {
+      return createTypeUnsafe<PaidTermId & Codec>(typeRegistry, "PaidTermId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get handle(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+
+    get avatarUri(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[2].value]
+      );
+    }
+
+    get about(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[3].value]
+      );
+    }
+  }
+  /**
+   *  Screened members are awarded a initial locked balance that can only be slashed or used
+   *  for fees, and is not transferable. The screening authority must ensure that the provided
+   *  new_member_account was verified to avoid applying locks arbitrarily to accounts not controlled
+   *  by the member.
+   */
+  export class AddScreenedMemberCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "AccountId",
+      "Option<Bytes>",
+      "Option<Bytes>",
+      "Option<Bytes>",
+      "Option<BalanceOf>"
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): AddScreenedMember_Args {
+      return new AddScreenedMember_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class AddScreenedMember_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get newMemberAccount(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get handle(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+
+    get avatarUri(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[2].value]
+      );
+    }
+
+    get about(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[3].value]
+      );
+    }
+
+    get initialBalance(): Option<BalanceOf> {
+      return createTypeUnsafe<Option<BalanceOf> & Codec>(
+        typeRegistry,
+        "Option<BalanceOf>",
+        [this.extrinsic.args[4].value]
+      );
+    }
+  }
+  /**
+   *  Change member's about text
+   */
+  export class ChangeMemberAboutTextCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["MemberId", "Bytes"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): ChangeMemberAboutText_Args {
+      return new ChangeMemberAboutText_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChangeMemberAboutText_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get text(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  /**
+   *  Change member's avatar
+   */
+  export class ChangeMemberAvatarCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["MemberId", "Bytes"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): ChangeMemberAvatar_Args {
+      return new ChangeMemberAvatar_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChangeMemberAvatar_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get uri(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  /**
+   *  Change member's handle. Will ensure new handle is unique and old one will be available
+   *  for other members to use.
+   */
+  export class ChangeMemberHandleCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["MemberId", "Bytes"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): ChangeMemberHandle_Args {
+      return new ChangeMemberHandle_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class ChangeMemberHandle_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get handle(): Bytes {
+      return createTypeUnsafe<Bytes & Codec>(typeRegistry, "Bytes", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  export class SetRootAccountCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["MemberId", "AccountId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): SetRootAccount_Args {
+      return new SetRootAccount_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class SetRootAccount_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get newRootAccount(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+  export class SetControllerAccountCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = ["MemberId", "AccountId"];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): SetControllerAccount_Args {
+      return new SetControllerAccount_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class SetControllerAccount_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value
+      ]);
+    }
+
+    get newControllerAccount(): AccountId {
+      return createTypeUnsafe<AccountId & Codec>(typeRegistry, "AccountId", [
+        this.extrinsic.args[1].value
+      ]);
+    }
+  }
+}

+ 832 - 0
query-node/generated/types/typedefs.json

@@ -0,0 +1,832 @@
+{
+    "ChannelContentType": "Null",
+    "ChannelCurationStatus": "Null",
+    "ChannelPublicationStatus": "Null",
+    "CurationActor": "Null",
+    "Curator": "Null",
+    "CuratorApplication": "Null",
+    "CuratorApplicationId": "Null",
+    "CuratorApplicationIdSet": "Null",
+    "CuratorApplicationIdToCuratorIdMap": "Null",
+    "CuratorOpening": "Null",
+    "CuratorOpeningId": "Null",
+    "Lead": "Null",
+    "LeadId": "Null",
+    "OptionalText": "Null",
+    "Principal": "Null",
+    "PrincipalId": "Null",
+    "WorkingGroupUnstaker": "Null",
+    "Credential": "Null",
+    "CredentialSet": "Null",
+    "Nonce": "Null",
+    "EntityId": "Null",
+    "ClassId": "Null",
+    "VecMaxLength": "Null",
+    "TextMaxLength": "Null",
+    "HashedTextMaxLength": "Null",
+    "PropertyId": "Null",
+    "SchemaId": "Null",
+    "SameController": "Null",
+    "ClassPermissions": "Null",
+    "PropertyTypeSingle": "Null",
+    "PropertyTypeVector": "Null",
+    "PropertyType": "Null",
+    "PropertyLockingPolicy": "Null",
+    "Property": "Null",
+    "Schema": "Null",
+    "Class": "Null",
+    "ClassOf": "Null",
+    "EntityController": "Null",
+    "EntityPermissions": "Null",
+    "StoredValue": "Null",
+    "VecStoredValue": "Null",
+    "VecStoredPropertyValue": "Null",
+    "StoredPropertyValue": "Null",
+    "InboundReferenceCounter": "Null",
+    "Entity": "Null",
+    "EntityOf": "Null",
+    "EntityCreationVoucher": "Null",
+    "Actor": "Null",
+    "EntityReferenceCounterSideEffect": "Null",
+    "ReferenceCounterSideEffects": "Null",
+    "SideEffects": "Null",
+    "SideEffect": "Null",
+    "Status": "Null",
+    "InputValue": "Null",
+    "VecInputValue": "Null",
+    "InputPropertyValue": "Null",
+    "ParameterizedEntity": "Null",
+    "ParametrizedPropertyValue": "Null",
+    "ParametrizedClassPropertyValue": "Null",
+    "CreateEntityOperation": "Null",
+    "UpdatePropertyValuesOperation": "Null",
+    "AddSchemaSupportToEntityOperation": "Null",
+    "OperationType": "Null",
+    "InputEntityValuesMap": "Null",
+    "ClassPermissionsType": "Null",
+    "ClassPropertyValue": "Null",
+    "Operation": "Null",
+    "ReferenceConstraint": "Null",
+    "FailedAt": "Null",
+    "IPNSIdentity": "Null",
+    "ServiceProviderRecord": "Null",
+    "BlockAndTime": {
+        "block": "u32",
+        "time": "u64"
+    },
+    "ThreadId": "u64",
+    "PostId": "u64",
+    "InputValidationLengthConstraint": {
+        "min": "u16",
+        "max_min_diff": "u16"
+    },
+    "WorkingGroup": {
+        "_enum": [
+            "Storage",
+            "Content",
+            "Operations",
+            "Gateway"
+        ]
+    },
+    "SlashingTerms": {
+        "_enum": {
+            "Unslashable": "Null",
+            "Slashable": "SlashableTerms"
+        }
+    },
+    "SlashableTerms": {
+        "max_count": "u16",
+        "max_percent_pts_per_time": "u16"
+    },
+    "MemoText": "Text",
+    "Address": "AccountId",
+    "LookupSource": "AccountId",
+    "ChannelId": "u64",
+    "DAOId": "u64",
+    "Url": "Text",
+    "EntryMethod": {
+        "_enum": {
+            "Paid": "u64",
+            "Screening": "AccountId",
+            "Genesis": "Null"
+        }
+    },
+    "MemberId": "u64",
+    "PaidTermId": "u64",
+    "SubscriptionId": "u64",
+    "Membership": {
+        "handle": "Text",
+        "avatar_uri": "Text",
+        "about": "Text",
+        "registered_at_block": "u32",
+        "registered_at_time": "u64",
+        "entry": "EntryMethod",
+        "suspended": "bool",
+        "subscription": "Option<SubscriptionId>",
+        "root_account": "GenericAccountId",
+        "controller_account": "GenericAccountId"
+    },
+    "PaidMembershipTerms": {
+        "fee": "u128",
+        "text": "Text"
+    },
+    "ActorId": "u64",
+    "ElectionStage": {
+        "_enum": {
+            "Announcing": "u32",
+            "Voting": "u32",
+            "Revealing": "u32"
+        }
+    },
+    "ElectionStake": {
+        "new": "u128",
+        "transferred": "u128"
+    },
+    "SealedVote": {
+        "voter": "GenericAccountId",
+        "commitment": "Hash",
+        "stake": "ElectionStake",
+        "vote": "Option<GenericAccountId>"
+    },
+    "TransferableStake": {
+        "seat": "u128",
+        "backing": "u128"
+    },
+    "ElectionParameters": {
+        "announcing_period": "u32",
+        "voting_period": "u32",
+        "revealing_period": "u32",
+        "council_size": "u32",
+        "candidacy_limit": "u32",
+        "new_term_duration": "u32",
+        "min_council_stake": "u128",
+        "min_voting_stake": "u128"
+    },
+    "Seat": {
+        "member": "GenericAccountId",
+        "stake": "u128",
+        "backers": "Backers"
+    },
+    "Seats": "Vec<Seat>",
+    "Backer": {
+        "member": "GenericAccountId",
+        "stake": "u128"
+    },
+    "Backers": "Vec<Backer>",
+    "RoleParameters": {
+        "min_stake": "u128",
+        "min_actors": "u32",
+        "max_actors": "u32",
+        "reward": "u128",
+        "reward_period": "u32",
+        "bonding_period": "u32",
+        "unbonding_period": "u32",
+        "min_service_period": "u32",
+        "startup_grace_period": "u32",
+        "entry_request_fee": "u128"
+    },
+    "PostTextChange": {
+        "expired_at": "BlockAndTime",
+        "text": "Text"
+    },
+    "ModerationAction": {
+        "moderated_at": "BlockAndTime",
+        "moderator_id": "GenericAccountId",
+        "rationale": "Text"
+    },
+    "ChildPositionInParentCategory": {
+        "parent_id": "CategoryId",
+        "child_nr_in_parent_category": "u32"
+    },
+    "CategoryId": "u64",
+    "Category": {
+        "id": "CategoryId",
+        "title": "Text",
+        "description": "Text",
+        "created_at": "BlockAndTime",
+        "deleted": "bool",
+        "archived": "bool",
+        "num_direct_subcategories": "u32",
+        "num_direct_unmoderated_threads": "u32",
+        "num_direct_moderated_threads": "u32",
+        "position_in_parent_category": "Option<ChildPositionInParentCategory>",
+        "moderator_id": "GenericAccountId"
+    },
+    "Thread": {
+        "id": "ThreadId",
+        "title": "Text",
+        "category_id": "CategoryId",
+        "nr_in_category": "u32",
+        "moderation": "Option<ModerationAction>",
+        "num_unmoderated_posts": "u32",
+        "num_moderated_posts": "u32",
+        "created_at": "BlockAndTime",
+        "author_id": "GenericAccountId"
+    },
+    "Post": {
+        "id": "PostId",
+        "thread_id": "ThreadId",
+        "nr_in_thread": "u32",
+        "current_text": "Text",
+        "moderation": "Option<ModerationAction>",
+        "text_change_history": "Vec<PostTextChange>",
+        "created_at": "BlockAndTime",
+        "author_id": "GenericAccountId"
+    },
+    "ReplyId": "u64",
+    "Reply": {
+        "owner": "GenericAccountId",
+        "thread_id": "ThreadId",
+        "text": "Text",
+        "moderation": "Option<ModerationAction>"
+    },
+    "StakeId": "u64",
+    "Stake": {
+        "created": "u32",
+        "staking_status": "StakingStatus"
+    },
+    "StakingStatus": {
+        "_enum": {
+            "NotStaked": "Null",
+            "Staked": "Staked"
+        }
+    },
+    "Staked": {
+        "staked_amount": "u128",
+        "staked_status": "StakedStatus",
+        "next_slash_id": "u64",
+        "ongoing_slashes": "BTreeMap<u64,Slash>"
+    },
+    "StakedStatus": {
+        "_enum": {
+            "Normal": "Null",
+            "Unstaking": "Unstaking"
+        }
+    },
+    "Unstaking": {
+        "started_at_block": "u32",
+        "is_active": "bool",
+        "blocks_remaining_in_active_period_for_unstaking": "u32"
+    },
+    "Slash": {
+        "started_at_block": "u32",
+        "is_active": "bool",
+        "blocks_remaining_in_active_period_for_slashing": "u32",
+        "slash_amount": "u128"
+    },
+    "MintId": "u64",
+    "Mint": {
+        "capacity": "u128",
+        "next_adjustment": "Option<NextAdjustment>",
+        "created_at": "u32",
+        "total_minted": "u128"
+    },
+    "MintBalanceOf": "u128",
+    "BalanceOfMint": "u128",
+    "NextAdjustment": {
+        "adjustment": "AdjustOnInterval",
+        "at_block": "u32"
+    },
+    "AdjustOnInterval": {
+        "block_interval": "u32",
+        "adjustment_type": "AdjustCapacityBy"
+    },
+    "AdjustCapacityBy": {
+        "_enum": {
+            "Setting": "u128",
+            "Adding": "u128",
+            "Reducing": "u128"
+        }
+    },
+    "RecipientId": "u64",
+    "RewardRelationshipId": "u64",
+    "Recipient": {
+        "total_reward_received": "u128",
+        "total_reward_missed": "u128"
+    },
+    "RewardRelationship": {
+        "recipient": "RecipientId",
+        "mint_id": "MintId",
+        "account": "GenericAccountId",
+        "amount_per_payout": "u128",
+        "next_payment_at_block": "Option<u32>",
+        "payout_interval": "Option<u32>",
+        "total_reward_received": "u128",
+        "total_reward_missed": "u128"
+    },
+    "ApplicationId": "u64",
+    "OpeningId": "u64",
+    "Application": {
+        "opening_id": "OpeningId",
+        "application_index_in_opening": "u32",
+        "add_to_opening_in_block": "u32",
+        "active_role_staking_id": "Option<StakeId>",
+        "active_application_staking_id": "Option<StakeId>",
+        "stage": "ApplicationStage",
+        "human_readable_text": "Text"
+    },
+    "ApplicationStage": {
+        "_enum": {
+            "Active": "Null",
+            "Unstaking": "UnstakingApplicationStage",
+            "Inactive": "InactiveApplicationStage"
+        }
+    },
+    "ActivateOpeningAt": {
+        "_enum": {
+            "CurrentBlock": "Null",
+            "ExactBlock": "u32"
+        }
+    },
+    "ApplicationRationingPolicy": {
+        "max_active_applicants": "u32"
+    },
+    "OpeningStage": {
+        "_enum": {
+            "WaitingToBegin": "WaitingToBeingOpeningStageVariant",
+            "Active": "ActiveOpeningStageVariant"
+        }
+    },
+    "StakingPolicy": {
+        "amount": "u128",
+        "amount_mode": "StakingAmountLimitMode",
+        "crowded_out_unstaking_period_length": "Option<u32>",
+        "review_period_expired_unstaking_period_length": "Option<u32>"
+    },
+    "Opening": {
+        "created": "u32",
+        "stage": "OpeningStage",
+        "max_review_period_length": "u32",
+        "application_rationing_policy": "Option<ApplicationRationingPolicy>",
+        "application_staking_policy": "Option<StakingPolicy>",
+        "role_staking_policy": "Option<StakingPolicy>",
+        "human_readable_text": "Text"
+    },
+    "WaitingToBeingOpeningStageVariant": {
+        "begins_at_block": "u32"
+    },
+    "ActiveOpeningStageVariant": {
+        "stage": "ActiveOpeningStage",
+        "applications_added": "Vec<ApplicationId>",
+        "active_application_count": "u32",
+        "unstaking_application_count": "u32",
+        "deactivated_application_count": "u32"
+    },
+    "ActiveOpeningStage": {
+        "_enum": {
+            "AcceptingApplications": "AcceptingApplications",
+            "ReviewPeriod": "ReviewPeriod",
+            "Deactivated": "Deactivated"
+        }
+    },
+    "AcceptingApplications": {
+        "started_accepting_applicants_at_block": "u32"
+    },
+    "ReviewPeriod": {
+        "started_accepting_applicants_at_block": "u32",
+        "started_review_period_at_block": "u32"
+    },
+    "Deactivated": {
+        "cause": "OpeningDeactivationCause",
+        "deactivated_at_block": "u32",
+        "started_accepting_applicants_at_block": "u32",
+        "started_review_period_at_block": "Option<u32>"
+    },
+    "OpeningDeactivationCause": {
+        "_enum": [
+            "CancelledBeforeActivation",
+            "CancelledAcceptingApplications",
+            "CancelledInReviewPeriod",
+            "ReviewPeriodExpired",
+            "Filled"
+        ]
+    },
+    "InactiveApplicationStage": {
+        "deactivation_initiated": "u32",
+        "deactivated": "u32",
+        "cause": "ApplicationDeactivationCause"
+    },
+    "UnstakingApplicationStage": {
+        "deactivation_initiated": "u32",
+        "cause": "ApplicationDeactivationCause"
+    },
+    "ApplicationDeactivationCause": {
+        "_enum": [
+            "External",
+            "Hired",
+            "NotHired",
+            "CrowdedOut",
+            "OpeningCancelled",
+            "ReviewPeriodExpired",
+            "OpeningFilled"
+        ]
+    },
+    "StakingAmountLimitMode": {
+        "_enum": [
+            "AtLeast",
+            "Exact"
+        ]
+    },
+    "RationaleText": "Bytes",
+    "ApplicationOf": {
+        "role_account_id": "GenericAccountId",
+        "opening_id": "OpeningId",
+        "member_id": "MemberId",
+        "application_id": "ApplicationId"
+    },
+    "ApplicationIdSet": "BTreeSet<ApplicationId>",
+    "ApplicationIdToWorkerIdMap": "BTreeMap<ApplicationId,WorkerId>",
+    "WorkerId": "u64",
+    "WorkerOf": {
+        "member_id": "MemberId",
+        "role_account_id": "GenericAccountId",
+        "reward_relationship": "Option<RewardRelationshipId>",
+        "role_stake_profile": "Option<RoleStakeProfile>"
+    },
+    "OpeningOf": {
+        "hiring_opening_id": "OpeningId",
+        "applications": "Vec<ApplicationId>",
+        "policy_commitment": "OpeningPolicyCommitment",
+        "opening_type": "OpeningType"
+    },
+    "StorageProviderId": "u64",
+    "OpeningType": {
+        "_enum": {
+            "Leader": "Null",
+            "Worker": "Null"
+        }
+    },
+    "HiringApplicationId": "u64",
+    "RewardPolicy": {
+        "amount_per_payout": "u128",
+        "next_payment_at_block": "u32",
+        "payout_interval": "Option<u32>"
+    },
+    "OpeningPolicyCommitment": {
+        "application_rationing_policy": "Option<ApplicationRationingPolicy>",
+        "max_review_period_length": "u32",
+        "application_staking_policy": "Option<StakingPolicy>",
+        "role_staking_policy": "Option<StakingPolicy>",
+        "role_slashing_terms": "SlashingTerms",
+        "fill_opening_successful_applicant_application_stake_unstaking_period": "Option<u32>",
+        "fill_opening_failed_applicant_application_stake_unstaking_period": "Option<u32>",
+        "fill_opening_failed_applicant_role_stake_unstaking_period": "Option<u32>",
+        "terminate_application_stake_unstaking_period": "Option<u32>",
+        "terminate_role_stake_unstaking_period": "Option<u32>",
+        "exit_role_application_stake_unstaking_period": "Option<u32>",
+        "exit_role_stake_unstaking_period": "Option<u32>"
+    },
+    "RoleStakeProfile": {
+        "stake_id": "StakeId",
+        "termination_unstaking_period": "Option<u32>",
+        "exit_unstaking_period": "Option<u32>"
+    },
+    "ContentId": "[u8;32]",
+    "LiaisonJudgement": {
+        "_enum": [
+            "Pending",
+            "Accepted"
+        ]
+    },
+    "DataObject": {
+        "owner": "StorageObjectOwner",
+        "added_at": "BlockAndTime",
+        "type_id": "DataObjectTypeId",
+        "size": "u64",
+        "liaison": "Option<StorageProviderId>",
+        "liaison_judgement": "LiaisonJudgement",
+        "ipfs_content_id": "Text"
+    },
+    "DataObjectStorageRelationshipId": "u64",
+    "DataObjectStorageRelationship": {
+        "content_id": "ContentId",
+        "storage_provider": "StorageProviderId",
+        "ready": "bool"
+    },
+    "DataObjectTypeId": "u64",
+    "DataObjectType": {
+        "description": "Text",
+        "active": "bool"
+    },
+    "DataObjectsMap": "BTreeMap<ContentId,DataObject>",
+    "ContentParameters": {
+        "content_id": "ContentId",
+        "type_id": "DataObjectTypeId",
+        "size": "u64",
+        "ipfs_content_id": "Bytes"
+    },
+    "StorageObjectOwner": {
+        "_enum": {
+            "Member": "MemberId",
+            "Channel": "ChannelId",
+            "DAO": "DAOId",
+            "Council": "Null",
+            "WorkingGroup": "WorkingGroup"
+        }
+    },
+    "ObjectOwner": {
+        "_enum": {
+            "Member": "MemberId",
+            "Channel": "ChannelId",
+            "DAO": "DAOId",
+            "Council": "Null",
+            "WorkingGroup": "WorkingGroup"
+        }
+    },
+    "Voucher": {
+        "size_limit": "u64",
+        "objects_limit": "u64",
+        "size_used": "u64",
+        "objects_used": "u64"
+    },
+    "VoucherLimit": "u64",
+    "UploadingStatus": "bool",
+    "ProposalId": "u32",
+    "ProposalStatus": {
+        "_enum": {
+            "Active": "Option<ActiveStake>",
+            "Finalized": "Finalized"
+        }
+    },
+    "ProposalOf": {
+        "parameters": "ProposalParameters",
+        "proposerId": "MemberId",
+        "title": "Text",
+        "description": "Text",
+        "createdAt": "u32",
+        "status": "ProposalStatus",
+        "votingResults": "VotingResults"
+    },
+    "ProposalDetails": {
+        "_enum": {
+            "Text": "Text",
+            "RuntimeUpgrade": "Bytes",
+            "SetElectionParameters": "ElectionParameters",
+            "Spending": "(Balance,AccountId)",
+            "SetLead": "Option<SetLeadParams>",
+            "SetContentWorkingGroupMintCapacity": "u128",
+            "EvictStorageProvider": "GenericAccountId",
+            "SetValidatorCount": "u32",
+            "SetStorageRoleParameters": "RoleParameters",
+            "AddWorkingGroupLeaderOpening": "AddOpeningParameters",
+            "BeginReviewWorkingGroupLeaderApplication": "(OpeningId,WorkingGroup)",
+            "FillWorkingGroupLeaderOpening": "FillOpeningParameters",
+            "SetWorkingGroupMintCapacity": "(Balance,WorkingGroup)",
+            "DecreaseWorkingGroupLeaderStake": "(WorkerId,Balance,WorkingGroup)",
+            "SlashWorkingGroupLeaderStake": "(WorkerId,Balance,WorkingGroup)",
+            "SetWorkingGroupLeaderReward": "(WorkerId,Balance,WorkingGroup)",
+            "TerminateWorkingGroupLeaderRole": "TerminateRoleParameters"
+        }
+    },
+    "ProposalDetailsOf": {
+        "_enum": {
+            "Text": "Text",
+            "RuntimeUpgrade": "Bytes",
+            "SetElectionParameters": "ElectionParameters",
+            "Spending": "(Balance,AccountId)",
+            "SetLead": "Option<SetLeadParams>",
+            "SetContentWorkingGroupMintCapacity": "u128",
+            "EvictStorageProvider": "GenericAccountId",
+            "SetValidatorCount": "u32",
+            "SetStorageRoleParameters": "RoleParameters",
+            "AddWorkingGroupLeaderOpening": "AddOpeningParameters",
+            "BeginReviewWorkingGroupLeaderApplication": "(OpeningId,WorkingGroup)",
+            "FillWorkingGroupLeaderOpening": "FillOpeningParameters",
+            "SetWorkingGroupMintCapacity": "(Balance,WorkingGroup)",
+            "DecreaseWorkingGroupLeaderStake": "(WorkerId,Balance,WorkingGroup)",
+            "SlashWorkingGroupLeaderStake": "(WorkerId,Balance,WorkingGroup)",
+            "SetWorkingGroupLeaderReward": "(WorkerId,Balance,WorkingGroup)",
+            "TerminateWorkingGroupLeaderRole": "TerminateRoleParameters"
+        }
+    },
+    "VotingResults": {
+        "abstensions": "u32",
+        "approvals": "u32",
+        "rejections": "u32",
+        "slashes": "u32"
+    },
+    "ProposalParameters": {
+        "votingPeriod": "u32",
+        "gracePeriod": "u32",
+        "approvalQuorumPercentage": "u32",
+        "approvalThresholdPercentage": "u32",
+        "slashingQuorumPercentage": "u32",
+        "slashingThresholdPercentage": "u32",
+        "requiredStake": "Option<u128>"
+    },
+    "VoteKind": {
+        "_enum": [
+            "Approve",
+            "Reject",
+            "Slash",
+            "Abstain"
+        ]
+    },
+    "ThreadCounter": {
+        "author_id": "MemberId",
+        "counter": "u32"
+    },
+    "DiscussionThread": {
+        "title": "Bytes",
+        "created_at": "u32",
+        "author_id": "MemberId"
+    },
+    "DiscussionPost": {
+        "text": "Bytes",
+        "created_at": "u32",
+        "updated_at": "u32",
+        "author_id": "MemberId",
+        "thread_id": "ThreadId",
+        "edition_number": "u32"
+    },
+    "AddOpeningParameters": {
+        "activate_at": "ActivateOpeningAt",
+        "commitment": "OpeningPolicyCommitment",
+        "human_readable_text": "Bytes",
+        "working_group": "WorkingGroup"
+    },
+    "FillOpeningParameters": {
+        "opening_id": "OpeningId",
+        "successful_application_id": "ApplicationId",
+        "reward_policy": "Option<RewardPolicy>",
+        "working_group": "WorkingGroup"
+    },
+    "TerminateRoleParameters": {
+        "worker_id": "WorkerId",
+        "rationale": "Bytes",
+        "slash": "bool",
+        "working_group": "WorkingGroup"
+    },
+    "ActiveStake": {
+        "stake_id": "StakeId",
+        "source_account_id": "GenericAccountId"
+    },
+    "Finalized": {
+        "proposalStatus": "ProposalDecisionStatus",
+        "finalizedAt": "u32",
+        "encodedUnstakingErrorDueToBrokenRuntime": "Option<Vec<u8>>",
+        "stakeDataAfterUnstakingError": "Option<ActiveStake>"
+    },
+    "ProposalDecisionStatus": {
+        "_enum": {
+            "Canceled": "Null",
+            "Vetoed": "Null",
+            "Rejected": "Null",
+            "Slashed": "Null",
+            "Expired": "Null",
+            "Approved": "Approved"
+        }
+    },
+    "ExecutionFailed": {
+        "error": "Text"
+    },
+    "Approved": {
+        "_enum": {
+            "PendingExecution": "Null",
+            "Executed": "Null",
+            "ExecutionFailed": "ExecutionFailed"
+        }
+    },
+    "SetLeadParams": "(MemberId,GenericAccountId)",
+    "CuratorId": "u64",
+    "CuratorGroupId": "u64",
+    "CuratorGroup": {
+        "curators": "Vec<CuratorId>",
+        "active": "bool"
+    },
+    "ContentActor": {
+        "_enum": {
+            "Curator": "(CuratorGroupId,CuratorId)",
+            "Member": "MemberId",
+            "Lead": "Null"
+        }
+    },
+    "NewAsset": {
+        "_enum": {
+            "Upload": "ContentParameters",
+            "Urls": "Vec<Url>"
+        }
+    },
+    "Channel": {
+        "owner": "ChannelOwner",
+        "videos": "Vec<VideoId>",
+        "playlists": "Vec<PlaylistId>",
+        "series": "Vec<SeriesId>",
+        "is_censored": "bool",
+        "reward_account": "Option<GenericAccountId>"
+    },
+    "ChannelOwner": {
+        "_enum": {
+            "Member": "MemberId",
+            "Curators": "CuratorGroupId",
+            "Dao": "DAOId"
+        }
+    },
+    "ChannelCategoryId": "u64",
+    "ChannelCategory": {},
+    "ChannelCategoryCreationParameters": {
+        "meta": "Bytes"
+    },
+    "ChannelCategoryUpdateParameters": {
+        "new_meta": "Bytes"
+    },
+    "ChannelCreationParameters": {
+        "assets": "Vec<NewAsset>",
+        "meta": "Bytes",
+        "reward_account": "Option<GenericAccountId>"
+    },
+    "ChannelUpdateParameters": {
+        "assets": "Option<Vec<NewAsset>>",
+        "new_meta": "Option<Bytes>",
+        "reward_account": "Option<Option<GenericAccountId>>"
+    },
+    "ChannelOwnershipTransferRequestId": "u64",
+    "ChannelOwnershipTransferRequest": {
+        "channel_id": "ChannelId",
+        "new_owner": "ChannelOwner",
+        "payment": "u128",
+        "new_reward_account": "Option<GenericAccountId>"
+    },
+    "Video": {
+        "in_channel": "ChannelId",
+        "in_series": "Option<SeriesId>",
+        "is_censored": "bool"
+    },
+    "VideoId": "u64",
+    "VideoCategoryId": "u64",
+    "VideoCategory": {},
+    "VideoCategoryCreationParameters": {
+        "meta": "Bytes"
+    },
+    "VideoCategoryUpdateParameters": {
+        "new_meta": "Bytes"
+    },
+    "VideoCreationParameters": {
+        "assets": "Vec<NewAsset>",
+        "meta": "Bytes"
+    },
+    "VideoUpdateParameters": {
+        "assets": "Option<Vec<NewAsset>>",
+        "new_meta": "Option<Bytes>"
+    },
+    "Person": {
+        "controlled_by": "PersonController"
+    },
+    "PersonId": "u64",
+    "PersonController": {
+        "_enum": {
+            "Member": "MemberId",
+            "Curators": "Null"
+        }
+    },
+    "PersonActor": {
+        "_enum": {
+            "Member": "MemberId",
+            "Curator": "CuratorId"
+        }
+    },
+    "PersonCreationParameters": {
+        "assets": "Vec<NewAsset>",
+        "meta": "Bytes"
+    },
+    "PersonUpdateParameters": {
+        "assets": "Option<Vec<NewAsset>>",
+        "meta": "Option<Bytes>"
+    },
+    "Playlist": {
+        "in_channel": "ChannelId"
+    },
+    "PlaylistId": "u64",
+    "PlaylistCreationParameters": {
+        "meta": "Bytes"
+    },
+    "PlaylistUpdateParameters": {
+        "new_meta": "Bytes"
+    },
+    "SeriesId": "u64",
+    "Series": {
+        "in_channel": "ChannelId",
+        "seasons": "Vec<Season>"
+    },
+    "Season": {
+        "episodes": "Vec<VideoId>"
+    },
+    "SeriesParameters": {
+        "assets": "Option<Vec<NewAsset>>",
+        "seasons": "Option<Vec<Option<SeasonParameters>>>",
+        "meta": "Option<Bytes>"
+    },
+    "SeasonParameters": {
+        "assets": "Option<Vec<NewAsset>>",
+        "episodes": "Option<Vec<Option<EpisodeParemters>>>",
+        "meta": "Option<Bytes>"
+    },
+    "EpisodeParemters": {
+        "_enum": {
+            "NewVideo": "VideoCreationParameters",
+            "ExistingVideo": "VideoId"
+        }
+    },
+    "MaxNumber": "u32",
+    "IsCensored": "bool"
+}

+ 161 - 29
query-node/manifest.yml

@@ -1,41 +1,114 @@
 version: '0.1'
 description: Joystream query-node manifest file for sumer
 repository: https://github.com/Joystream/joystream
+hydraVersion: "2"
 dataSource:
-  kind: substrate 
+  kind: substrate
   chain: joystream
   indexerVersion: '0.1.6'
 entities:
-  - mappings/lib/generated/**/*.model.js
-metadata:
-  # TODO: update source and blockHash for sumer release
-  source: wss://babylon-sub-1.joystream.app/staging/rpc
-  blockHash: '0x206a6cca31333cb19ee120cde7455e13eea368ec3f6176d0cd48698228410489'
-events:
-  - members.MemberRegistered
-  - members.MemberUpdatedAboutText
-  - members.MemberUpdatedAvatar
-  - members.MemberUpdatedHandle
-  - members.MemberSetRootAccount
-  - members.MemberSetControllerAccount
-calls:
-  - members.buyMembership
-  - members.addScreenedMember
-outDir: ./mappings/generated/types
-customTypes:
-  lib: '@joystream/types/augment/all/types'
-  typedefsLoc: '../types/augment/all/defs.json'
+  - generated/graphql-server/dist/**/*.model.js
+typegen:
+  metadata:
+    source: wss://sumer-dev.joystream.app/rpc
+    #source: wss://sumer.joystream.app
+    #source: ws://localhost:9944 # use this to download types from local node (useful during development)
+  events:
+    # membership
+    - members.MemberRegistered
+    - members.MemberUpdatedAboutText
+    - members.MemberUpdatedAvatar
+    - members.MemberUpdatedHandle
+    - members.MemberSetRootAccount
+    - members.MemberSetControllerAccount
+
+    # content directory
+    - content.CuratorGroupCreated
+    - content.CuratorGroupStatusSet
+    - content.CuratorAdded
+    - content.CuratorRemoved
+    - content.ChannelCreated
+    - content.ChannelUpdated
+    - content.ChannelAssetsRemoved
+    - content.ChannelCensorshipStatusUpdated
+    - content.ChannelOwnershipTransferRequested
+    - content.ChannelOwnershipTransferRequestWithdrawn
+    - content.ChannelOwnershipTransferred
+    - content.ChannelCategoryCreated
+    - content.ChannelCategoryUpdated
+    - content.ChannelCategoryDeleted
+    - content.VideoCategoryCreated
+    - content.VideoCategoryUpdated
+    - content.VideoCategoryDeleted
+    - content.VideoCreated
+    - content.VideoUpdated
+    - content.VideoDeleted
+    - content.VideoCensorshipStatusUpdated
+    - content.FeaturedVideosSet
+
+    # storage
+    - data_directory.ContentAdded
+    - data_directory.ContentRemoved
+    - data_directory.ContentAccepted
+    - data_directory.ContentRejected
+    - data_directory.ContentUploadingStatusUpdated
+  calls:
+    # members
+    - members.buyMembership
+    - members.addScreenedMember
+    - members.changeMemberAboutText
+    - members.changeMemberAvatar
+    - members.changeMemberHandle
+    - members.setRootAccount
+    - members.setControllerAccount
+
+    # content directory
+    - content.create_curator_group
+    - content.set_curator_group_status
+    - content.add_curator_to_group
+    - content.remove_curator_from_group
+    - content.create_channel
+    - content.update_channel
+    - content.remove_channel_assets
+    - content.update_channel_censorship_status
+    - content.create_channel_category
+    - content.update_channel_category
+    - content.delete_channel_category
+    - content.request_channel_transfer
+    - content.cancel_channel_transfer_request
+    - content.accept_channel_transfer
+    - content.create_video
+    - content.update_video
+    - content.delete_video
+    - content.create_playlist
+    - content.update_playlist
+    - content.delete_playlist
+    - content.set_featured_videos
+    - content.create_video_category
+    - content.update_video_category
+    - content.delete_video_category
+    - content.remove_person_from_video
+    - content.update_video_censorship_status
+
+    # storage
+    - data_directory.add_content
+    - data_directory.remove_content
+    - data_directory.accept_content
+    - data_directory.update_content_uploading_status
+
+  outDir: ./generated/types
+  customTypes:
+    lib: '@joystream/types/augment'
+    typedefsLoc: '../types/augment/all/defs.json'
 mappings:
-  hydraCommonVersion: '0.0.3'
-    # process only blocks with height >= 1M 
-  blockInterval: '[1000000,]'
-  # js module that exports the handler functions 
-  mappingsModule: mappings/lib/mappings
+  # js module that exports the handler functions
+  mappingsModule: mappings
   # additinal libraries the processor loads
-  # typically it is a module with event and extrinsic types generated by hydra-typegen 
+  # typically it is a module with event and extrinsic types generated by hydra-typegen
   imports:
-    - mappings/lib/mappings/generated/types
+    - mappings/lib/generated/types
   eventHandlers:
+    # membership
     - event: members.MemberRegistered
       handler: members_MemberRegistered(DatabaseManager, SubstrateEvent)
     - event: members.MemberUpdatedAboutText
@@ -48,10 +121,69 @@ mappings:
       handler: members_MemberSetRootAccount(DatabaseManager, SubstrateEvent)
     - event: members.MemberSetControllerAccount
       handler: members_MemberSetControllerAccount(DatabaseManager, SubstrateEvent)
+
+    # content directory
+    - event: content.CuratorGroupCreated
+      handler: content_CuratorGroupCreated(DatabaseManager, SubstrateEvent)
+    - event: content.CuratorGroupStatusSet
+      handler: content_CuratorGroupStatusSet(DatabaseManager, SubstrateEvent)
+    - event: content.CuratorAdded
+      handler: content_CuratorAdded(DatabaseManager, SubstrateEvent)
+    - event: content.CuratorRemoved
+      handler: content_CuratorRemoved(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelCreated
+      handler: content_ChannelCreated(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelUpdated
+      handler: content_ChannelUpdated(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelAssetsRemoved
+      handler: content_ChannelAssetsRemoved(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelCensorshipStatusUpdated
+      handler: content_ChannelCensorshipStatusUpdated(DatabaseManager, SubstrateEvent)
+    # these events are defined in runtime but never calles (at the time of writing)
+    #- event: content.ChannelOwnershipTransferRequested
+    #  handler: content_ChannelOwnershipTransferRequested(DatabaseManager, SubstrateEvent)
+    #- event: content.ChannelOwnershipTransferRequestWithdrawn
+    #  handler: content_ChannelOwnershipTransferRequestWithdrawn(DatabaseManager, SubstrateEvent)
+    #- event: content.ChannelOwnershipTransferred
+    #  handler: content_ChannelOwnershipTransferred(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelCategoryCreated
+      handler: content_ChannelCategoryCreated(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelCategoryUpdated
+      handler: content_ChannelCategoryUpdated(DatabaseManager, SubstrateEvent)
+    - event: content.ChannelCategoryDeleted
+      handler: content_ChannelCategoryDeleted(DatabaseManager, SubstrateEvent)
+    - event: content.VideoCategoryCreated
+      handler: content_VideoCategoryCreated(DatabaseManager, SubstrateEvent)
+    - event: content.VideoCategoryUpdated
+      handler: content_VideoCategoryUpdated(DatabaseManager, SubstrateEvent)
+    - event: content.VideoCategoryDeleted
+      handler: content_VideoCategoryDeleted(DatabaseManager, SubstrateEvent)
+    - event: content.VideoCreated
+      handler: content_VideoCreated(DatabaseManager, SubstrateEvent)
+    - event: content.VideoUpdated
+      handler: content_VideoUpdated(DatabaseManager, SubstrateEvent)
+    - event: content.VideoDeleted
+      handler: content_VideoDeleted(DatabaseManager, SubstrateEvent)
+    - event: content.VideoCensorshipStatusUpdated
+      handler: content_VideoCensorshipStatusUpdated(DatabaseManager, SubstrateEvent)
+    - event: content.FeaturedVideosSet
+      handler: content_FeaturedVideosSet(DatabaseManager, SubstrateEvent)
+
+    # storage
+    - event: dataDirectory.ContentAdded
+      handler: dataDirectory_ContentAdded(DatabaseManager, SubstrateEvent)
+    - event: dataDirectory.ContentRemoved
+      handler: dataDirectory_ContentRemoved(DatabaseManager, SubstrateEvent)
+    - event: dataDirectory.ContentAccepted
+      handler: dataDirectory_ContentAccepted(DatabaseManager, SubstrateEvent)
+    # not handled at the moment
+    #- event: dataDirectory.ContentUploadingStatusUpdated
+    #  handler: data_directory_ContentUploadingStatusUpdated(DatabaseManager, SubstrateEvent)
+
   extrinsicHandlers:
     # infer defaults here
-    #- extrinsic: Balances.Transfer 
-    #- extrinsic: Sudo.batchCall 
+    #- extrinsic: Balances.Transfer
+    #- extrinsic: Sudo.batchCall
     #  handler: handleSudoCall(DatabaseManager,SubstrateEvent)
   preBlockHooks:
   postBlockHooks:

+ 0 - 1
query-node/mappings/index.ts

@@ -1 +0,0 @@
-export * from './mappings'

+ 0 - 26
query-node/mappings/mappings.ts

@@ -1,26 +0,0 @@
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberRegistered(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedAboutText(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedAvatar(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedHandle(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberSetRootAccount(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberSetControllerAccount(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-}

+ 10 - 4
query-node/mappings/package.json

@@ -1,17 +1,23 @@
 {
   "name": "query-node-mappings",
-  "version": "0.0.1",
+  "version": "0.1.0",
   "description": "Mappings for hydra-processor",
-  "main": "lib/mappings/index.js",
+  "main": "lib/mappings/src/index.js",
   "license": "MIT",
   "scripts": {
-    "build": "rm -rf lib && tsc --build tsconfig.json",
+    "build": "rm -rf lib && tsc --build tsconfig.json && yarn copy-types",
+    "copy-types": "cp ../../types/augment/all/defs.json lib/generated/types/typedefs.json",
     "lint": "echo \"Skippinng\"",
     "clean": "rm -rf lib"
   },
   "dependencies": {
-    "@dzlzv/hydra-common": "2.0.1-beta.9",
     "@polkadot/types": "4.2.1",
+    "@dzlzv/hydra-common": "2.1.0-beta.7",
+    "@dzlzv/hydra-db-utils": "2.1.0-beta.7",
+    "@joystream/content-metadata-protobuf": "^1.1.0",
+    "@joystream/types": "^0.16.0",
+    "iso-639-1": "^2.1.8",
+    "query-node": "^0.1.0",
     "warthog": "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz"
   },
   "devDependencies": {

+ 83 - 0
query-node/mappings/src/common.ts

@@ -0,0 +1,83 @@
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { u64 } from '@polkadot/types/primitive';
+
+// Asset
+import {
+  DataObjectOwner,
+  DataObject,
+  LiaisonJudgement,
+  Network,
+} from 'query-node'
+import {
+  ContentParameters,
+} from '@joystream/types/augment'
+
+import { ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
+import { registry } from '@joystream/types'
+
+const currentNetwork = Network.BABYLON
+
+/*
+  Reports that insurmountable inconsistent state has been encountered and throws an exception.
+*/
+export function inconsistentState(extraInfo: string, data?: unknown): void {
+  const errorMessage = 'Inconsistent state: ' + extraInfo
+
+  // log error
+  logger.error(errorMessage, data)
+}
+
+/*
+  Prepares data object from content parameters.
+*/
+export async function prepareDataObject(
+  contentParameters: ContentParameters,
+  blockNumber: number,
+  owner: typeof DataObjectOwner,
+): Promise<DataObject> {
+  // convert generic content parameters coming from processor to custom Joystream data type
+  const customContentParameters = new Custom_ContentParameters(registry, contentParameters.toJSON() as any)
+
+  const dataObject = new DataObject({
+    owner,
+    createdInBlock: blockNumber,
+    typeId: contentParameters.type_id.toNumber(),
+    size: customContentParameters.size_in_bytes.toNumber(),
+    liaisonJudgement: LiaisonJudgement.PENDING, // judgement is pending at start; liaison id is set when content is accepted/rejected
+    ipfsContentId: contentParameters.ipfs_content_id.toUtf8(),
+    joystreamContentId: customContentParameters.content_id.encode(),
+
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  return dataObject
+}
+
+/////////////////// Logger /////////////////////////////////////////////////////
+
+/*
+  Simple logger enabling error and informational reporting.
+
+  `Logger` class will not be needed in the future when Hydra v3 will be released.
+  Hydra will provide logger instance and relevant code using `Logger` should be refactored.
+*/
+class Logger {
+
+  /*
+    Log significant event.
+  */
+  info(message: string, data?: unknown) {
+    console.log(message, data)
+  }
+
+  /*
+    Log significant error.
+  */
+  error(message: string, data?: unknown) {
+    console.error(message, data)
+  }
+}
+
+export const logger = new Logger()

+ 323 - 0
query-node/mappings/src/content/channel.ts

@@ -0,0 +1,323 @@
+import { fixBlockTimestamp } from '../eventFix'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import ISO6391 from 'iso-639-1';
+import { FindConditions, In } from 'typeorm'
+
+import { AccountId } from "@polkadot/types/interfaces";
+import { Option } from '@polkadot/types/codec';
+import { Content } from '../../../generated/types'
+import {
+  readProtobuf,
+  readProtobufWithAssets,
+  convertContentActorToChannelOwner,
+  convertContentActorToDataObjectOwner,
+} from './utils'
+
+import {
+  Channel,
+  ChannelCategory,
+  DataObject,
+} from 'query-node'
+import {
+  inconsistentState,
+  logger,
+} from '../common'
+
+import {
+  AssetAvailability,
+} from 'query-node'
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelCreated(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const {channelId, channelCreationParameters, contentActor} = new Content.ChannelCreatedEvent(event).data
+
+  // read metadata
+  const protobufContent = await readProtobufWithAssets(
+    new Channel(),
+    {
+      metadata: channelCreationParameters.meta,
+      db,
+      blockNumber: event.blockNumber,
+      assets: channelCreationParameters.assets,
+      contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
+    }
+  )
+
+  // create entity
+  const channel = new Channel({
+    // main data
+    id: channelId.toString(),
+    isCensored: false,
+    videos: [],
+    createdInBlock: event.blockNumber,
+
+    // default values for properties that might or might not be filled by metadata
+    coverPhotoUrls: [],
+    coverPhotoAvailability: AssetAvailability.INVALID,
+    avatarPhotoUrls: [],
+    avatarPhotoAvailability: AssetAvailability.INVALID,
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+
+    // prepare channel owner (handles fields `ownerMember` and `ownerCuratorGroup`)
+    ...await convertContentActorToChannelOwner(db, contentActor),
+
+    // integrate metadata
+    ...protobufContent
+  })
+
+  // save entity
+  await db.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel has been created', {id: channel.id})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    channelId,
+    channelUpdateParameters,
+    contentActor,
+  } = new Content.ChannelUpdatedEvent(event).data
+
+  // load channel
+  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
+
+  // ensure channel exists
+  if (!channel) {
+    return inconsistentState('Non-existing channel update requested', channelId)
+  }
+
+  // prepare changed metadata
+  const newMetadata = channelUpdateParameters.new_meta.unwrapOr(null)
+
+  //  update metadata if it was changed
+  if (newMetadata) {
+    const protobufContent = await readProtobufWithAssets(
+      new Channel(),
+      {
+        metadata: newMetadata,
+        db,
+        blockNumber: event.blockNumber,
+        assets: channelUpdateParameters.assets.unwrapOr([]),
+        contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
+      }
+    )
+
+    // update all fields read from protobuf
+    for (let [key, value] of Object.entries(protobufContent)) {
+      channel[key] = value
+    }
+  }
+
+  // prepare changed reward account
+  const newRewardAccount = channelUpdateParameters.reward_account.unwrapOr(null)
+
+  // reward account change happened?
+  if (newRewardAccount) {
+    // this will change the `channel`!
+    handleChannelRewardAccountChange(channel, newRewardAccount)
+  }
+
+  // set last update time
+  channel.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save channel
+  await db.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel has been updated', {id: channel.id})
+}
+
+export async function content_ChannelAssetsRemoved(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {contentId: contentIds} = new Content.ChannelAssetsRemovedEvent(event).data
+
+  // load channel
+  const assets = await db.getMany(DataObject, { where: {
+    id: In(contentIds.toArray().map(item => item.toString()))
+  } as FindConditions<DataObject>})
+
+  // delete assets
+  for (const asset of assets) {
+    await db.remove<DataObject>(asset)
+  }
+
+  // emit log event
+  logger.info('Channel assets have been removed', {ids: contentIds})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelCensorshipStatusUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {channelId, isCensored} = new Content.ChannelCensorshipStatusUpdatedEvent(event).data
+
+  // load event
+  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
+
+  // ensure channel exists
+  if (!channel) {
+    return inconsistentState('Non-existing channel censoring requested', channelId)
+  }
+
+  // update channel
+  channel.isCensored = isCensored.isTrue;
+
+  // set last update time
+  channel.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save channel
+  await db.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel censorship status has been updated', {id: channelId, isCensored: isCensored.isTrue})
+}
+
+/////////////////// ChannelCategory ////////////////////////////////////////////
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelCategoryCreated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {channelCategoryCreationParameters, channelCategoryId} = new Content.ChannelCategoryCreatedEvent(event).data
+  const {actor: contentActor} = new Content.CreateChannelCategoryCall(event).args
+
+  // read metadata
+  const protobufContent = await readProtobuf(
+    new ChannelCategory(),
+    {
+      metadata: channelCategoryCreationParameters.meta,
+      db,
+      blockNumber: event.blockNumber,
+    }
+  )
+
+  // create new channel category
+  const channelCategory = new ChannelCategory({
+    // main data
+    id: channelCategoryId.toString(),
+    channels: [],
+    createdInBlock: event.blockNumber,
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+
+    // integrate metadata
+    ...protobufContent
+  })
+
+  // save channel
+  await db.save<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been created', {id: channelCategory.id})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelCategoryUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    channelCategoryId,
+    channelCategoryUpdateParameters,
+    contentActor,
+  } = new Content.ChannelCategoryUpdatedEvent(event).data
+
+  // load channel category
+  const channelCategory = await db.get(ChannelCategory, { where: {
+    id: channelCategoryId.toString()
+  } as FindConditions<ChannelCategory> })
+
+  // ensure channel exists
+  if (!channelCategory) {
+    return inconsistentState('Non-existing channel category update requested', channelCategoryId)
+  }
+
+  // read metadata
+  const protobufContent = await readProtobuf(
+    new ChannelCategory(),
+    {
+      metadata: channelCategoryUpdateParameters.new_meta,
+      db,
+      blockNumber: event.blockNumber,
+    }
+  )
+
+  // update all fields read from protobuf
+  for (let [key, value] of Object.entries(protobufContent)) {
+    channelCategory[key] = value
+  }
+
+  // set last update time
+  channelCategory.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save channel category
+  await db.save<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been updated', {id: channelCategory.id})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_ChannelCategoryDeleted(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {channelCategoryId} = new Content.ChannelCategoryDeletedEvent(event).data
+
+  // load channel category
+  const channelCategory = await db.get(ChannelCategory, { where: {
+    id: channelCategoryId.toString()
+  } as FindConditions<ChannelCategory> })
+
+  // ensure channel category exists
+  if (!channelCategory) {
+    return inconsistentState('Non-existing channel category deletion requested', channelCategoryId)
+  }
+
+  // delete channel category
+  await db.remove<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been deleted', {id: channelCategory.id})
+}
+
+/////////////////// Helpers ////////////////////////////////////////////////////
+
+function handleChannelRewardAccountChange(
+  channel: Channel, // will be modified inside of the function!
+  reward_account: Option<AccountId>
+) {
+  const rewardAccount = reward_account.unwrapOr(null)
+
+  // new different reward account set?
+  if (rewardAccount) {
+    channel.rewardAccount = rewardAccount.toString()
+    return
+  }
+
+  // reward account removed
+
+  channel.rewardAccount = undefined // plan deletion (will have effect when saved to db)
+}

+ 126 - 0
query-node/mappings/src/content/curatorGroup.ts

@@ -0,0 +1,126 @@
+import { fixBlockTimestamp } from '../eventFix'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { FindConditions } from 'typeorm'
+
+import { CuratorGroup } from 'query-node'
+import { Content } from '../../../generated/types'
+
+import {
+  inconsistentState,
+  logger,
+} from '../common'
+
+export async function content_CuratorGroupCreated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {curatorGroupId} = new Content.CuratorGroupCreatedEvent(event).data
+
+  // create new curator group
+  const curatorGroup = new CuratorGroup({
+    // main data
+    id: curatorGroupId.toString(),
+    curatorIds: [],
+    isActive: false, // runtime creates inactive curator groups by default
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+  })
+
+  // save curator group
+  await db.save<CuratorGroup>(curatorGroup)
+
+  // emit log event
+  logger.info('Curator group has been created', {id: curatorGroupId})
+}
+
+export async function content_CuratorGroupStatusSet(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {curatorGroupId, bool: isActive} = new Content.CuratorGroupStatusSetEvent(event).data
+
+  // load curator group
+  const curatorGroup = await db.get(CuratorGroup, { where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>})
+
+  // ensure curator group exists
+  if (!curatorGroup) {
+    return inconsistentState('Non-existing curator group status set requested', curatorGroupId)
+  }
+
+  // update curator group
+  curatorGroup.isActive = isActive.isTrue
+
+  // set last update time
+  curatorGroup.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save curator group
+  await db.save<CuratorGroup>(curatorGroup)
+
+  // emit log event
+  logger.info('Curator group status has been set', {id: curatorGroupId, isActive})
+}
+
+export async function content_CuratorAdded(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {curatorGroupId, curatorId} = new Content.CuratorAddedEvent(event).data
+
+  // load curator group
+  const curatorGroup = await db.get(CuratorGroup, { where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>})
+
+  // ensure curator group exists
+  if (!curatorGroup) {
+    return inconsistentState('Curator add to non-existing curator group requested', curatorGroupId)
+  }
+
+  // update curator group
+  curatorGroup.curatorIds.push(curatorId.toNumber())
+
+  // set last update time
+  curatorGroup.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save curator group
+  await db.save<CuratorGroup>(curatorGroup)
+
+  // emit log event
+  logger.info('Curator has been added to curator group', {id: curatorGroupId, curatorId})
+}
+
+export async function content_CuratorRemoved(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {curatorGroupId, curatorId} = new Content.CuratorAddedEvent(event).data
+
+  // load curator group
+  const curatorGroup = await db.get(CuratorGroup, { where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>})
+
+  // ensure curator group exists
+  if (!curatorGroup) {
+    return inconsistentState('Non-existing curator group removal requested', curatorGroupId)
+  }
+
+  const curatorIndex = curatorGroup.curatorIds.indexOf(curatorId.toNumber())
+
+  // ensure curator group exists
+  if (curatorIndex < 0) {
+    return inconsistentState('Non-associated curator removal from curator group requested', curatorId)
+  }
+
+  // update curator group
+  curatorGroup.curatorIds.splice(curatorIndex, 1)
+
+  // save curator group
+  await db.save<CuratorGroup>(curatorGroup)
+
+  // emit log event
+  logger.info('Curator has been removed from curator group', {id: curatorGroupId, curatorId})
+}

+ 3 - 0
query-node/mappings/src/content/index.ts

@@ -0,0 +1,3 @@
+export * from './channel'
+export * from './curatorGroup'
+export * from './video'

+ 613 - 0
query-node/mappings/src/content/utils.ts

@@ -0,0 +1,613 @@
+// TODO: finish db cascade on save/remove; right now there is manually added `cascade: ["insert", "update"]` directive
+//       to all relations in `query-node/generated/graphql-server/src/modules/**/*.model.ts`. That should ensure all records
+//       are saved on one `db.save(...)` call. Missing features
+//       - find a proper way to cascade on remove or implement custom removals for every entity
+//       - convert manual changes done to `*model.ts` file into some patch or bash commands that can be executed
+//         every time query node codegen is run (that will overwrite said manual changes)
+//       - verify in integration tests that the records are trully created/updated/removed as expected
+
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { Bytes } from '@polkadot/types'
+import ISO6391 from 'iso-639-1';
+import { u64 } from '@polkadot/types/primitive';
+import { FindConditions } from 'typeorm'
+import * as jspb from "google-protobuf";
+
+// protobuf definitions
+import {
+  ChannelMetadata,
+  ChannelCategoryMetadata,
+  PublishedBeforeJoystream as PublishedBeforeJoystreamMetadata,
+  License as LicenseMetadata,
+  MediaType as MediaTypeMetadata,
+  VideoMetadata,
+  VideoCategoryMetadata,
+} from '@joystream/content-metadata-protobuf'
+
+import {
+  Content,
+} from '../../../generated/types'
+
+import {
+  inconsistentState,
+  logger,
+  prepareDataObject,
+} from '../common'
+
+
+import {
+  // primary entities
+  CuratorGroup,
+  Channel,
+  ChannelCategory,
+  Video,
+  VideoCategory,
+
+  // secondary entities
+  Language,
+  License,
+  VideoMediaEncoding,
+  VideoMediaMetadata,
+
+  // asset
+  DataObjectOwner,
+  DataObjectOwnerMember,
+  DataObjectOwnerChannel,
+  DataObject,
+  LiaisonJudgement,
+  AssetAvailability,
+
+  Membership,
+} from 'query-node'
+
+// Joystream types
+import {
+  ChannelId,
+  ContentParameters,
+  NewAsset,
+  ContentActor,
+} from '@joystream/types/augment'
+
+import { ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
+import { registry } from '@joystream/types'
+
+/*
+  Asset either stored in storage or describing list of URLs.
+*/
+type AssetStorageOrUrls = DataObject | string[]
+
+/*
+  Type guard differentiating asset stored in storage from asset describing a list of URLs.
+*/
+function isAssetInStorage(dataObject: AssetStorageOrUrls): dataObject is DataObject {
+  if (Array.isArray(dataObject)) {
+    return false
+  }
+
+  return true
+}
+
+export interface IReadProtobufArguments {
+  metadata: Bytes
+  db: DatabaseManager
+  blockNumber: number
+}
+
+export interface IReadProtobufArgumentsWithAssets extends IReadProtobufArguments {
+  assets: NewAsset[] // assets provided in event
+  contentOwner: typeof DataObjectOwner
+}
+
+/*
+  Reads information from the event and protobuf metadata and constructs changeset that's fit to be used when saving to db.
+*/
+export async function readProtobuf<T extends ChannelCategory | VideoCategory>(
+  type: T,
+  parameters: IReadProtobufArguments,
+): Promise<Partial<T>> {
+  // true option here is crucial, it indicates that we want just the underlying bytes (by default it will also include bytes encoding the length)
+  const metaU8a = parameters.metadata.toU8a(true);
+
+  // process channel category
+  if (type instanceof ChannelCategory) {
+    const meta = ChannelCategoryMetadata.deserializeBinary(metaU8a)
+    const result = convertMetadataToObject<ChannelCategoryMetadata.AsObject>(meta) as Partial<T>
+
+    return result
+  }
+
+  // process video category
+  if (type instanceof VideoCategory) {
+    const meta = VideoCategoryMetadata.deserializeBinary(metaU8a)
+    const result = convertMetadataToObject<VideoCategoryMetadata.AsObject>(meta) as Partial<T>
+
+    return result
+  }
+
+  // this should never happen
+  logger.error('Not implemented metadata type', {type})
+  throw `Not implemented metadata type`
+}
+
+/*
+  Reads information from the event and protobuf metadata and constructs changeset that's fit to be used when saving to db.
+  In addition it handles any assets associated with the metadata.
+*/
+
+export async function readProtobufWithAssets<T extends Channel | Video>(
+  type: T,
+  parameters: IReadProtobufArgumentsWithAssets,
+): Promise<Partial<T>> {
+  // true option here is crucial, it indicates that we want just the underlying bytes (by default it will also include bytes encoding the length)
+  const metaU8a = parameters.metadata.toU8a(true);
+
+  // process channel
+  if (type instanceof Channel) {
+    const meta = ChannelMetadata.deserializeBinary(metaU8a)
+    const metaAsObject = convertMetadataToObject<ChannelMetadata.AsObject>(meta)
+    const result = metaAsObject as any as Partial<Channel>
+
+    // prepare cover photo asset if needed
+    if ('coverPhoto' in metaAsObject) {
+      const asset = await extractAsset({
+        //assetIndex: metaAsObject.coverPhoto,
+        assetIndex: metaAsObject.coverPhoto,
+        assets: parameters.assets,
+        db: parameters.db,
+        blockNumber: parameters.blockNumber,
+        contentOwner: parameters.contentOwner,
+      })
+      integrateAsset('coverPhoto', result, asset) // changes `result` inline!
+      delete metaAsObject.coverPhoto
+    }
+
+    // prepare avatar photo asset if needed
+    if ('avatarPhoto' in metaAsObject) {
+      const asset = await extractAsset({
+        assetIndex: metaAsObject.avatarPhoto,
+        assets: parameters.assets,
+        db: parameters.db,
+        blockNumber: parameters.blockNumber,
+        contentOwner: parameters.contentOwner,
+      })
+      integrateAsset('avatarPhoto', result, asset) // changes `result` inline!
+      delete metaAsObject.avatarPhoto
+    }
+
+    // prepare language if needed
+    if ('language' in metaAsObject) {
+      result.language = await prepareLanguage(metaAsObject.language, parameters.db, parameters.blockNumber)
+    }
+
+    return result as Partial<T>
+  }
+
+  // process video
+  if (type instanceof Video) {
+    const meta = VideoMetadata.deserializeBinary(metaU8a)
+    const metaAsObject = convertMetadataToObject<VideoMetadata.AsObject>(meta)
+    const result = metaAsObject as any as Partial<Video>
+
+    // prepare video category if needed
+    if ('category' in metaAsObject) {
+      result.category = await prepareVideoCategory(metaAsObject.category, parameters.db)
+    }
+
+    // prepare media meta information if needed
+    if ('mediaType' in metaAsObject) {
+      // prepare video file size if poosible
+      const videoSize = await extractVideoSize(parameters.assets, metaAsObject.video)
+
+      result.mediaMetadata = await prepareVideoMetadata(metaAsObject, videoSize, parameters.blockNumber)
+      delete metaAsObject.mediaType
+    }
+
+    // prepare license if needed
+    if ('license' in metaAsObject) {
+      result.license = await prepareLicense(metaAsObject.license)
+    }
+
+    // prepare thumbnail photo asset if needed
+    if ('thumbnailPhoto' in metaAsObject) {
+      const asset = await extractAsset({
+        assetIndex: metaAsObject.thumbnailPhoto,
+        assets: parameters.assets,
+        db: parameters.db,
+        blockNumber: parameters.blockNumber,
+        contentOwner: parameters.contentOwner,
+      })
+      integrateAsset('thumbnail', result, asset) // changes `result` inline!
+      delete metaAsObject.thumbnailPhoto
+    }
+
+    // prepare video asset if needed
+    if ('video' in metaAsObject) {
+      const asset = await extractAsset({
+        assetIndex: metaAsObject.video,
+        assets: parameters.assets,
+        db: parameters.db,
+        blockNumber: parameters.blockNumber,
+        contentOwner: parameters.contentOwner,
+      })
+      integrateAsset('media', result, asset) // changes `result` inline!
+      delete metaAsObject.video
+    }
+
+    // prepare language if needed
+    if ('language' in metaAsObject) {
+      result.language = await prepareLanguage(metaAsObject.language, parameters.db, parameters.blockNumber)
+    }
+
+    // prepare information about media published somewhere else before Joystream if needed.
+    if (metaAsObject.publishedBeforeJoystream && metaAsObject.publishedBeforeJoystream.isPublished) {
+      // this will change the `channel`!
+      handlePublishedBeforeJoystream(result, metaAsObject.publishedBeforeJoystream.date)
+    } else {
+      delete metaAsObject.publishedBeforeJoystream // make sure the object is unset
+    }
+
+    return result as Partial<T>
+  }
+
+  // this should never happen
+  logger.error('Not implemented metadata type', {type})
+  throw `Not implemented metadata type`
+}
+
+export async function convertContentActorToChannelOwner(db: DatabaseManager, contentActor: ContentActor): Promise<{
+  ownerMember?: Membership,
+  ownerCuratorGroup?: CuratorGroup,
+}> {
+  if (contentActor.isMember) {
+    const memberId = contentActor.asMember.toNumber()
+    const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+    // ensure member exists
+    if (!member) {
+      inconsistentState(`Actor is non-existing member`, memberId)
+      return {
+        // this will clear fields
+        ownerMember: undefined,
+        ownerCuratorGroup: undefined,
+      }
+    }
+
+    return {
+      ownerMember: member,
+      ownerCuratorGroup: undefined, // this will clear the field
+    }
+  }
+
+  if (contentActor.isCurator) {
+    const curatorGroupId = contentActor.asCurator[0].toNumber()
+    const curatorGroup = await db.get(CuratorGroup, { where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup> })
+
+    // ensure curator group exists
+    if (!curatorGroup) {
+      inconsistentState('Actor is non-existing curator group', curatorGroupId)
+      return {
+        // this will clear fields
+        ownerMember: undefined,
+        ownerCuratorGroup: undefined,
+      }
+    }
+
+    return {
+      ownerMember: undefined, // this will clear the field
+      ownerCuratorGroup: curatorGroup,
+    }
+  }
+
+  // TODO: contentActor.isLead
+
+  logger.error('Not implemented ContentActor type', {contentActor: contentActor.toString()})
+  throw 'Not-implemented ContentActor type used'
+}
+
+export function convertContentActorToDataObjectOwner(contentActor: ContentActor, channelId: number): typeof DataObjectOwner {
+  const owner = new DataObjectOwnerChannel()
+  owner.channel = channelId
+
+  return owner
+
+  /* contentActor is irrelevant now -> all video/channel content belongs to the channel
+  if (contentActor.isMember) {
+    const owner = new DataObjectOwnerMember()
+    owner.member = contentActor.asMember.toBn()
+
+    return owner
+  }
+
+  if (contentActor.isLead || contentActor.isCurator) {
+    const owner = new DataObjectOwnerChannel()
+    owner.channel = channelId
+
+    return owner
+  }
+
+  logger.error('Not implemented ContentActor type', {contentActor: contentActor.toString()})
+  throw 'Not-implemented ContentActor type used'
+  */
+}
+
+function handlePublishedBeforeJoystream(video: Partial<Video>, publishedAtString?: string) {
+  // published elsewhere before Joystream
+  if (publishedAtString) {
+    video.publishedBeforeJoystream = new Date(publishedAtString)
+
+    return
+  }
+
+  // unset publish info
+  video.publishedBeforeJoystream = undefined // plan deletion (will have effect when saved to db)
+}
+
+interface IConvertAssetParameters {
+  rawAsset: NewAsset
+  db: DatabaseManager
+  blockNumber: number
+  contentOwner: typeof DataObjectOwner
+}
+
+/*
+  Converts event asset into data object or list of URLs fit to be saved to db.
+*/
+async function convertAsset(parameters: IConvertAssetParameters): Promise<AssetStorageOrUrls> {
+  // is asset describing list of URLs?
+  if (parameters.rawAsset.isUrls) {
+    const urls = parameters.rawAsset.asUrls.toArray().map(item => item.toString())
+
+    return urls
+  }
+
+  // !parameters.rawAsset.isUrls && parameters.rawAsset.isUpload // asset is in storage
+
+  // prepare data object
+  const contentParameters: ContentParameters = parameters.rawAsset.asUpload
+  const dataObject = await prepareDataObject(contentParameters, parameters.blockNumber, parameters.contentOwner)
+
+  return dataObject
+}
+
+interface IExtractAssetParameters {
+  assetIndex: number | undefined
+  assets: NewAsset[]
+  db: DatabaseManager
+  blockNumber: number
+  contentOwner: typeof DataObjectOwner
+}
+
+/*
+  Selects asset from provided set of assets and prepares asset data fit to be saved to db.
+*/
+async function extractAsset(parameters: IExtractAssetParameters): Promise<AssetStorageOrUrls | undefined> {
+  // is asset being unset?
+  if (parameters.assetIndex === undefined) {
+    return undefined
+  }
+
+  // ensure asset index is valid
+  if (parameters.assetIndex >= parameters.assets.length) {
+    inconsistentState(`Non-existing asset extraction requested`, {
+      assetsProvided: parameters.assets.length,
+      assetIndex: parameters.assetIndex,
+    })
+    return undefined
+  }
+
+  // convert asset to data object record
+  return convertAsset({
+    rawAsset: parameters.assets[parameters.assetIndex],
+    db: parameters.db,
+    blockNumber: parameters.blockNumber,
+    contentOwner: parameters.contentOwner,
+  })
+}
+
+/*
+  As a temporary messure to overcome yet-to-be-implemented features in Hydra, we are using redudant information
+  to describe asset state. This function introduces all redudant data needed to be saved to db.
+
+  Changes `result` argument!
+*/
+function integrateAsset<T>(propertyName: string, result: Object, asset: AssetStorageOrUrls | undefined) {
+  // helpers - property names
+  const nameUrl = propertyName + 'Urls'
+  const nameDataObject = propertyName + 'DataObject'
+  const nameAvailability = propertyName + 'Availability'
+
+  if (asset === undefined) {
+    result[nameUrl] = []
+    result[nameAvailability] = AssetAvailability.INVALID
+    result[nameDataObject] = undefined // plan deletion (will have effect when saved to db)
+
+    return result
+  }
+
+  // is asset saved in storage?
+  if (!isAssetInStorage(asset)) {
+    // (un)set asset's properties
+    result[nameUrl] = asset
+    result[nameAvailability] = AssetAvailability.ACCEPTED
+    result[nameDataObject] = undefined // plan deletion (will have effect when saved to db)
+
+    return result
+  }
+
+  // prepare conversion table between liaison judgment and asset availability
+  const conversionTable = {
+    [LiaisonJudgement.ACCEPTED]: AssetAvailability.ACCEPTED,
+    [LiaisonJudgement.PENDING]: AssetAvailability.PENDING,
+  }
+
+  // (un)set asset's properties
+  result[nameUrl] = [] // plan deletion (will have effect when saved to db)
+  result[nameAvailability] = conversionTable[asset.liaisonJudgement]
+  result[nameDataObject] = asset
+}
+
+async function extractVideoSize(assets: NewAsset[], assetIndex: number | undefined): Promise<number | undefined> {
+  // escape if no asset is required
+  if (assetIndex === undefined) {
+    return undefined
+  }
+
+  // ensure asset index is valid
+  if (assetIndex > assets.length) {
+    inconsistentState(`Non-existing asset video size extraction requested`, {assetsProvided: assets.length, assetIndex})
+    return undefined
+  }
+
+  const rawAsset = assets[assetIndex]
+
+  // escape if asset is describing URLs (can't get size)
+  if (rawAsset.isUrls) {
+    return undefined
+  }
+
+  // !rawAsset.isUrls && rawAsset.isUpload // asset is in storage
+
+  // convert generic content parameters coming from processor to custom Joystream data type
+  const customContentParameters = new Custom_ContentParameters(registry, rawAsset.asUpload.toJSON() as any)
+  // extract video size
+  const videoSize = customContentParameters.size_in_bytes.toNumber()
+
+  return videoSize
+}
+
+async function prepareLanguage(languageIso: string | undefined, db: DatabaseManager, blockNumber: number): Promise<Language | undefined> {
+  // is language being unset?
+  if (languageIso === undefined) {
+    return undefined
+  }
+
+  // validate language string
+  const isValidIso = ISO6391.validate(languageIso);
+
+  // ensure language string is valid
+  if (!isValidIso) {
+    inconsistentState(`Invalid language ISO-639-1 provided`, languageIso)
+    return undefined
+  }
+
+  // load language
+  const language = await db.get(Language, { where: { iso: languageIso } as FindConditions<Language> })
+
+  // return existing language if any
+  if (language) {
+    return language;
+  }
+
+
+  // create new language
+  const newLanguage = new Language({
+    iso: languageIso,
+    createdInBlock: blockNumber,
+
+    // TODO: remove these lines after Hydra auto-fills the values when cascading save (remove them on all places)
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  await db.save<Language>(newLanguage)
+
+  return newLanguage
+}
+
+async function prepareLicense(licenseProtobuf: LicenseMetadata.AsObject | undefined): Promise<License | undefined> {
+  // NOTE: Deletion of any previous license should take place in appropriate event handling function
+  //       and not here even it might appear so.
+
+  // is license being unset?
+  if (licenseProtobuf === undefined) {
+    return undefined
+  }
+
+  // crete new license
+  const license = new License({
+    ...licenseProtobuf,
+
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  return license
+}
+
+async function prepareVideoMetadata(videoProtobuf: VideoMetadata.AsObject, videoSize: number | undefined, blockNumber: number): Promise<VideoMediaMetadata> {
+  // create new encoding info
+  const encoding = new VideoMediaEncoding({
+    ...videoProtobuf.mediaType,
+
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  // create new video metadata
+  const videoMeta = new VideoMediaMetadata({
+    encoding,
+    pixelWidth: videoProtobuf.mediaPixelWidth,
+    pixelHeight: videoProtobuf.mediaPixelHeight,
+    createdInBlock: blockNumber,
+
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  // fill in video size if provided
+  if (videoSize !== undefined) {
+    videoMeta.size = videoSize
+  }
+
+  return videoMeta
+}
+
+async function prepareVideoCategory(categoryId: number | undefined, db: DatabaseManager): Promise<VideoCategory | undefined> {
+  // is category being unset?
+  if (categoryId === undefined) {
+    return undefined
+  }
+
+  // load video category
+  const category = await db.get(VideoCategory, { where: { id: categoryId.toString() } as FindConditions<VideoCategory> })
+
+  // ensure video category exists
+  if (!category) {
+    inconsistentState('Non-existing video category association with video requested', categoryId)
+    return undefined
+  }
+
+  return category
+}
+
+function convertMetadataToObject<T extends Object>(metadata: jspb.Message): T {
+  const metaAsObject = metadata.toObject()
+  const result = {} as T
+
+  for (const key in metaAsObject) {
+    const funcNameBase = key.charAt(0).toUpperCase() + key.slice(1)
+    const hasFuncName = 'has' + funcNameBase
+    const isSet = funcNameBase == 'PersonsList' // there is no `VideoMetadata.hasPersonsList` method from unkown reason -> create exception
+      ? true
+      : metadata[hasFuncName]()
+
+    if (!isSet) {
+      continue
+    }
+
+
+    const getFuncName = 'get' + funcNameBase
+    const value = metadata[getFuncName]()
+
+    // TODO: check that recursion trully works
+    if (value instanceof jspb.Message) {
+      result[key] = convertMetadataToObject(value)
+      continue
+    }
+
+    result[key] = metaAsObject[key]
+  }
+
+  return result
+}

+ 394 - 0
query-node/mappings/src/content/video.ts

@@ -0,0 +1,394 @@
+import BN from 'bn.js'
+import { fixBlockTimestamp } from '../eventFix'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { FindConditions, In } from 'typeorm'
+
+import {
+  Content,
+} from '../../../generated/types'
+
+import {
+  inconsistentState,
+  logger,
+} from '../common'
+
+import {
+  convertContentActorToDataObjectOwner,
+  readProtobuf,
+  readProtobufWithAssets
+} from './utils'
+
+// primary entities
+import {
+  AssetAvailability,
+  Channel,
+  Video,
+  VideoCategory,
+} from 'query-node'
+
+// secondary entities
+import { License } from 'query-node'
+
+// Joystream types
+import {
+  ChannelId,
+} from '@joystream/types/augment'
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoCategoryCreated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    videoCategoryId,
+    videoCategoryCreationParameters,
+    contentActor,
+  } = new Content.VideoCategoryCreatedEvent(event).data
+
+  // read metadata
+  const protobufContent = await readProtobuf(
+    new VideoCategory(),
+    {
+      metadata: videoCategoryCreationParameters.meta,
+      db,
+      blockNumber: event.blockNumber,
+    }
+  )
+
+  // create new video category
+  const videoCategory = new VideoCategory({
+    // main data
+    id: videoCategoryId.toString(),
+    videos: [],
+    createdInBlock: event.blockNumber,
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+
+    // integrate metadata
+    ...protobufContent
+  })
+
+  // save video category
+  await db.save<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been created', {id: videoCategoryId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoCategoryUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    videoCategoryId,
+    videoCategoryUpdateParameters,
+    contentActor,
+  } = new Content.VideoCategoryUpdatedEvent(event).data
+
+  // load video category
+  const videoCategory = await db.get(VideoCategory, { where: { id: videoCategoryId.toString() } as FindConditions<VideoCategory> })
+
+  // ensure video category exists
+  if (!videoCategory) {
+    return inconsistentState('Non-existing video category update requested', videoCategoryId)
+  }
+
+  // read metadata
+  const protobufContent = await readProtobuf(
+    new VideoCategory(),
+    {
+      metadata: videoCategoryUpdateParameters.new_meta,
+      db,
+      blockNumber: event.blockNumber,
+    }
+  )
+
+  // update all fields read from protobuf
+  for (let [key, value] of Object.entries(protobufContent)) {
+    videoCategory[key] = value
+  }
+
+  // set last update time
+  videoCategory.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save video category
+  await db.save<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been updated', {id: videoCategoryId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoCategoryDeleted(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {videoCategoryId} = new Content.VideoCategoryDeletedEvent(event).data
+
+  // load video category
+  const videoCategory = await db.get(VideoCategory, { where: { id: videoCategoryId.toString() } as FindConditions<VideoCategory> })
+
+  // ensure video category exists
+  if (!videoCategory) {
+    return inconsistentState('Non-existing video category deletion requested', videoCategoryId)
+  }
+
+  // remove video category
+  await db.remove<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been deleted', {id: videoCategoryId})
+}
+
+/////////////////// Video //////////////////////////////////////////////////////
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoCreated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    channelId,
+    videoId,
+    videoCreationParameters,
+    contentActor,
+  } = new Content.VideoCreatedEvent(event).data
+
+  // read metadata
+  const protobufContent = await readProtobufWithAssets(
+    new Video(),
+    {
+      metadata: videoCreationParameters.meta,
+      db,
+      blockNumber: event.blockNumber,
+      assets: videoCreationParameters.assets,
+      contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
+    }
+  )
+
+  // load channel
+  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
+
+  // ensure channel exists
+  if (!channel) {
+    inconsistentState('Trying to add video to non-existing channel', channelId)
+  }
+
+  // create new video
+  const video = new Video({
+    // main data
+    id: videoId.toString(),
+    isCensored: false,
+    channel,
+    createdInBlock: event.blockNumber,
+    isFeatured: false,
+
+    // default values for properties that might or might not be filled by metadata
+    thumbnailPhotoUrls: [],
+    thumbnailPhotoAvailability: AssetAvailability.INVALID,
+    mediaUrls: [],
+    mediaAvailability: AssetAvailability.INVALID,
+
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+
+    // integrate metadata
+    ...protobufContent
+  })
+
+  // save video
+  await db.save<Video>(video)
+
+  // emit log event
+  logger.info('Video has been created', {id: videoId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {
+    videoId,
+    videoUpdateParameters,
+    contentActor,
+  } = new Content.VideoUpdatedEvent(event).data
+
+  // load video
+  const video = await db.get(Video, { where: { id: videoId.toString() } as FindConditions<Video> })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video update requested', videoId)
+  }
+
+  // prepare changed metadata
+  const newMetadata = videoUpdateParameters.new_meta.unwrapOr(null)
+
+  // update metadata if it was changed
+  if (newMetadata) {
+    const protobufContent = await readProtobufWithAssets(
+      new Video(),
+      {
+        metadata: newMetadata,
+        db,
+        blockNumber: event.blockNumber,
+        assets: videoUpdateParameters.assets.unwrapOr([]),
+        contentOwner: convertContentActorToDataObjectOwner(contentActor, (new BN(video.channel.id)).toNumber()),
+      }
+    )
+
+    // remember original license
+    const originalLicense = video.license
+
+    // update all fields read from protobuf
+    for (let [key, value] of Object.entries(protobufContent)) {
+      video[key] = value
+    }
+
+    // license has changed - delete old license
+    if (originalLicense && video.license != originalLicense) {
+      await db.remove<License>(originalLicense)
+    }
+  }
+
+  // set last update time
+  video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save video
+  await db.save<Video>(video)
+
+  // emit log event
+  logger.info('Video has been updated', {id: videoId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoDeleted(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {videoId} = new Content.VideoDeletedEvent(event).data
+
+  // load video
+  const video = await db.get(Video, { where: { id: videoId.toString() } as FindConditions<Video> })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video deletion requested', videoId)
+  }
+
+  // remove video
+  await db.remove<Video>(video)
+
+  // emit log event
+  logger.info('Video has been deleted', {id: videoId})
+}
+
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_VideoCensorshipStatusUpdated(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {videoId, isCensored} = new Content.VideoCensorshipStatusUpdatedEvent(event).data
+
+  // load video
+  const video = await db.get(Video, { where: { id: videoId.toString() } as FindConditions<Video> })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video censoring requested', videoId)
+  }
+
+  // update video
+  video.isCensored = isCensored.isTrue;
+
+  // set last update time
+  video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save video
+  await db.save<Video>(video)
+
+  // emit log event
+  logger.info('Video censorship status has been updated', {id: videoId, isCensored: isCensored.isTrue})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function content_FeaturedVideosSet(
+  db: DatabaseManager,
+  event: SubstrateEvent
+) {
+  // read event data
+  const {videoId: videoIds} = new Content.FeaturedVideosSetEvent(event).data
+
+  // load old featured videos
+  const existingFeaturedVideos = await db.getMany(Video, { where: { isFeatured: true } as FindConditions<Video> })
+
+  // comparsion utility
+  const isSame = (videoIdA: string) => (videoIdB: string) => videoIdA == videoIdB
+
+  // calculate diff sets
+  const toRemove = existingFeaturedVideos.filter(existingFV =>
+    !videoIds
+      .map(item => item.toHex())
+      .some(isSame(existingFV.id))
+  )
+  const toAdd = videoIds.filter(video =>
+    !existingFeaturedVideos
+      .map(item => item.id)
+      .some(isSame(video.toHex()))
+  )
+
+  // mark previously featured videos as not-featured
+  for (let video of toRemove) {
+    video.isFeatured = false;
+
+    // set last update time
+    video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+    await db.save<Video>(video)
+  }
+
+  // escape if no featured video needs to be added
+  if (!toAdd) {
+    // emit log event
+    logger.info('Featured videos unchanged')
+
+    return
+  }
+
+  // read videos previously not-featured videos that are meant to be featured
+  const videosToAdd = await db.getMany(Video, { where: {
+    id: In(toAdd.map(item => item.toString()))
+  } as FindConditions<Video> })
+
+  if (videosToAdd.length != toAdd.length) {
+    inconsistentState('At least one non-existing video featuring requested', toAdd)
+  }
+
+  // mark previously not-featured videos as featured
+  for (let video of videosToAdd) {
+    video.isFeatured = true;
+
+    // set last update time
+    video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+    await db.save<Video>(video)
+  }
+
+  // emit log event
+  logger.info('New featured videos have been set', {videoIds})
+}

+ 6 - 0
query-node/mappings/src/eventFix.ts

@@ -0,0 +1,6 @@
+import BN from 'bn.js'
+
+// Workaround for https://github.com/Joystream/hydra/issues/326 . This file can be removed after it's fixed
+export function fixBlockTimestamp(blockTimestamp: unknown): BN {
+    return new BN(blockTimestamp as string)
+}

+ 3 - 0
query-node/mappings/src/index.ts

@@ -0,0 +1,3 @@
+export * from './content'
+export * from './membership'
+export * from './storage'

+ 209 - 0
query-node/mappings/src/membership.ts

@@ -0,0 +1,209 @@
+import { fixBlockTimestamp } from './eventFix'
+import BN from 'bn.js'
+import { Bytes } from '@polkadot/types'
+import { MemberId } from '@joystream/types/members'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { FindConditions } from 'typeorm'
+
+import {
+  inconsistentState,
+  logger,
+} from './common'
+import { Members } from '../../generated/types'
+import { MembershipEntryMethod, Membership } from 'query-node'
+import { EntryMethod } from '@joystream/types/augment'
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberRegistered(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { accountId, memberId, entryMethod } = new Members.MemberRegisteredEvent(event).data
+  const { avatarUri, about, handle } = new Members.BuyMembershipCall(event).args
+
+  // create new membership
+  const member = new Membership({
+    // main data
+    id: memberId.toString(),
+    rootAccount: accountId.toString(),
+    controllerAccount: accountId.toString(),
+    handle: convertBytesToString(handle.unwrapOr(null)),
+    about: convertBytesToString(about.unwrapOr(null)),
+    avatarUri: convertBytesToString(avatarUri.unwrapOr(null)),
+    createdInBlock: event.blockNumber,
+    entry: convertEntryMethod(entryMethod),
+
+    // fill in auto-generated fields
+    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+  })
+
+  // save membership
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info('Member has been registered', {ids: memberId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberUpdatedAboutText(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { text, memberId } = new Members.ChangeMemberAboutTextCall(event).args
+
+  // load member
+  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+  // ensure member exists
+  if (!member) {
+    return inconsistentState(`Non-existing member about text update requested`, memberId)
+  }
+
+  // update member
+  member.about = convertBytesToString(text)
+
+  // set last update time
+  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save member
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info("Member's about text has been updated", {ids: memberId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { uri, memberId } = new Members.ChangeMemberAvatarCall(event).args
+
+  // load member
+  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+  // ensure member exists
+  if (!member) {
+    return inconsistentState(`Non-existing member avatar update requested`, memberId)
+  }
+
+  // update member
+  member.avatarUri = convertBytesToString(uri)
+
+  // set last update time
+  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save member
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info("Member's avatar has been updated", {ids: memberId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberUpdatedHandle(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { handle, memberId } = new Members.ChangeMemberHandleCall(event).args
+
+  // load member
+  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+  // ensure member exists
+  if (!member) {
+    return inconsistentState(`Non-existing member handle update requested`, memberId)
+  }
+
+  // update member
+  member.handle = convertBytesToString(handle)
+
+  // set last update time
+  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save member
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info("Member's avatar has been updated", {ids: memberId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberSetRootAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { newRootAccount, memberId } = new Members.SetRootAccountCall(event).args
+
+  // load member
+  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+  // ensure member exists
+  if (!member) {
+    return inconsistentState(`Non-existing member root account update requested`, memberId)
+  }
+
+  // update member
+  member.rootAccount = newRootAccount.toString()
+
+  // set last update time
+  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save member
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info("Member's root has been updated", {ids: memberId})
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export async function members_MemberSetControllerAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const { newControllerAccount, memberId } = new Members.SetControllerAccountCall(event).args
+
+  // load member
+  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+  // ensure member exists
+  if (!member) {
+    return inconsistentState(`Non-existing member controller account update requested`, memberId)
+  }
+
+  // update member
+  member.controllerAccount = newControllerAccount.toString()
+
+  // set last update time
+  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save member
+  await db.save<Membership>(member)
+
+  // emit log event
+  logger.info("Member's controller has been updated", {ids: memberId})
+}
+
+/////////////////// Helpers ////////////////////////////////////////////////////
+
+/*
+  Helper for converting Bytes type to string
+*/
+function convertBytesToString(b: Bytes | null): string {
+  if (!b) {
+    return ''
+  }
+
+  return Buffer.from(b.toU8a(true)).toString()
+}
+
+function convertEntryMethod(entryMethod: EntryMethod): MembershipEntryMethod {
+  // paid membership?
+  if (entryMethod.isPaid) {
+    return MembershipEntryMethod.PAID
+  }
+
+  // paid membership?
+  if (entryMethod.isScreening) {
+    return MembershipEntryMethod.SCREENING
+  }
+
+  // paid membership?
+  if (entryMethod.isGenesis) {
+    return MembershipEntryMethod.GENESIS
+  }
+
+  // should never happen
+  logger.error('Not implemented entry method', {entryMethod: entryMethod.toString()})
+  throw 'Not implemented entry method'
+}

+ 192 - 0
query-node/mappings/src/storage.ts

@@ -0,0 +1,192 @@
+import { fixBlockTimestamp } from './eventFix'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { FindConditions, In } from 'typeorm'
+
+import {
+  inconsistentState,
+  logger,
+  prepareDataObject,
+} from './common'
+
+import {
+  DataDirectory,
+} from '../../generated/types'
+import {
+  ContentId,
+  ContentParameters,
+  StorageObjectOwner,
+} from '@joystream/types/augment'
+
+import { ContentId as Custom_ContentId, ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
+import { registry } from '@joystream/types'
+
+import {
+  Channel,
+  Video,
+  AssetAvailability,
+
+  DataObject,
+  DataObjectOwner,
+  DataObjectOwnerMember,
+  DataObjectOwnerChannel,
+  DataObjectOwnerDao,
+  DataObjectOwnerCouncil,
+  DataObjectOwnerWorkingGroup,
+  LiaisonJudgement,
+} from 'query-node'
+
+export async function dataDirectory_ContentAdded(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const {contentParameters, storageObjectOwner} = new DataDirectory.ContentAddedEvent(event).data
+
+  // save all content objects
+  for (let parameters of contentParameters) {
+    const owner = convertStorageObjectOwner(storageObjectOwner)
+    const dataObject = await prepareDataObject(parameters, event.blockNumber, owner)
+
+    // fill in auto-generated fields
+    dataObject.createdAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+    dataObject.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+    await db.save<DataObject>(dataObject)
+  }
+
+  // emit log event
+  logger.info("Storage content has beed added", {ids: contentParameters.map(item => encodeContentId(item.content_id))})
+}
+
+export async function dataDirectory_ContentRemoved(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const {contentId: contentIds} = new DataDirectory.ContentRemovedEvent(event).data
+
+  // load assets
+  const dataObjects = await db.getMany(DataObject, { where: {
+    joystreamContentId: In(contentIds.map(item => encodeContentId(item)))
+  } as FindConditions<DataObject> })
+
+  // remove assets from database
+  for (let item of dataObjects) {
+      await db.remove<DataObject>(item)
+  }
+
+  // emit log event
+  logger.info("Storage content have been removed", {id: contentIds, dataObjectIds: dataObjects.map(item => item.id)})
+}
+
+export async function dataDirectory_ContentAccepted(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+  // read event data
+  const {contentId, storageProviderId} = new DataDirectory.ContentAcceptedEvent(event).data
+  const encodedContentId = encodeContentId(contentId)
+
+  // load asset
+  const dataObject = await db.get(DataObject, { where: { joystreamContentId: encodedContentId } as FindConditions<DataObject>})
+
+  // ensure object exists
+  if (!dataObject) {
+    return inconsistentState('Non-existing content acceptation requested', encodedContentId)
+  }
+
+  // update object
+  dataObject.liaisonId = storageProviderId.toNumber()
+  dataObject.liaisonJudgement = LiaisonJudgement.ACCEPTED
+
+  // set last update time
+  dataObject.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+
+  // save object
+  await db.save<DataObject>(dataObject)
+
+  // emit log event
+  logger.info("Storage content has been accepted", {id: encodedContentId})
+
+  // update asset availability for all connected channels and videos
+  // this will not be needed after redudant AssetAvailability will be removed (after some Hydra upgrades)
+  await updateConnectedAssets(db, dataObject)
+}
+
+/////////////////// Updating connected entities ////////////////////////////////
+
+async function updateConnectedAssets(db: DatabaseManager, dataObject: DataObject) {
+  await updateSingleConnectedAsset(db, new Channel(), 'avatarPhoto', dataObject)
+  await updateSingleConnectedAsset(db, new Channel(), 'coverPhoto', dataObject)
+
+  await updateSingleConnectedAsset(db, new Video(), 'thumbnailPhoto', dataObject)
+  await updateSingleConnectedAsset(db, new Video(), 'media', dataObject)
+}
+
+//async function updateSingleConnectedAsset(db: DatabaseManager, type: typeof Channel | typeof Video, propertyName: string, dataObject: DataObject) {
+async function updateSingleConnectedAsset<T extends Channel | Video>(db: DatabaseManager, type: T, propertyName: string, dataObject: DataObject) {
+  // prepare lookup condition
+  const condition = {
+    where: {
+      [propertyName + 'DataObject']: dataObject
+    }
+  } // as FindConditions<T>
+
+  // in therory the following condition(s) can be generalized `... db.get(type, ...` but in practice it doesn't work :-\
+  const items = type instanceof Channel
+    ? await db.getMany(Channel, condition)
+    : await db.getMany(Video, condition)
+
+  for (const item of items) {
+    item[propertyName + 'Availability'] = AssetAvailability.ACCEPTED
+
+    if (type instanceof Channel) {
+      await db.save<Channel>(item)
+
+      // emit log event
+      logger.info("Channel using Content has been accepted", {channelId: item.id.toString(), joystreamContentId: dataObject.joystreamContentId})
+    } else {
+      await db.save<Video>(item)
+
+      // emit log event
+      logger.info("Video using Content has been accepted", {videoId: item.id.toString(), joystreamContentId: dataObject.joystreamContentId})
+    }
+  }
+}
+
+/////////////////// Helpers ////////////////////////////////////////////////////
+
+function convertStorageObjectOwner(objectOwner: StorageObjectOwner): typeof DataObjectOwner {
+  if (objectOwner.isMember) {
+    const owner = new DataObjectOwnerMember()
+    owner.member = objectOwner.asMember.toNumber()
+
+    return owner
+  }
+
+  if (objectOwner.isChannel) {
+    const owner = new DataObjectOwnerChannel()
+    owner.channel = objectOwner.asChannel.toNumber()
+
+    return owner
+  }
+
+  if (objectOwner.isDao) {
+    const owner = new DataObjectOwnerDao()
+    owner.dao = objectOwner.asDao.toNumber()
+
+    return owner
+  }
+
+  if (objectOwner.isCouncil) {
+    return new DataObjectOwnerCouncil()
+  }
+
+  if (objectOwner.isWorkingGroup) {
+    const owner = new DataObjectOwnerWorkingGroup()
+    owner.workingGroup = objectOwner.asWorkingGroup.toNumber()
+
+    return owner
+  }
+
+  logger.error('Not implemented StorageObjectOwner type', {objectOwner: objectOwner.toString()})
+  throw 'Not implemented StorageObjectOwner type'
+}
+
+function encodeContentId(contentId: ContentId) {
+  const customContentId = new Custom_ContentId(registry, contentId);
+
+  return customContentId.encode()
+}

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