Browse Source

Merge remote-tracking branch 'upstream/babylon' into qnode-license-attribution

metmirr 4 years ago
parent
commit
dd32f719ba

+ 6 - 0
query-node/mappings/content-directory/content-dir-consts.ts

@@ -14,6 +14,7 @@ export enum ContentDirectoryKnownClasses {
   VIDEO = 'Video',
   VIDEOMEDIA = 'VideoMedia',
   VIDEOMEDIAENCODING = 'VideoMediaEncoding',
+  FEATUREDVIDEOS = 'FeaturedVideo',
 }
 
 // Predefined content-directory classes, classId may change after the runtime seeding
@@ -30,6 +31,7 @@ export const contentDirectoryClassNamesWithId: { classId: number; name: string }
   { name: ContentDirectoryKnownClasses.VIDEO, classId: 10 },
   { name: ContentDirectoryKnownClasses.VIDEOMEDIA, classId: 11 },
   { name: ContentDirectoryKnownClasses.VIDEOMEDIAENCODING, classId: 12 },
+  { name: ContentDirectoryKnownClasses.FEATUREDVIDEOS, classId: 13 },
 ]
 
 export const categoryPropertyNamesWithId: IPropertyWithId = {
@@ -115,3 +117,7 @@ export const videoPropertyNamesWithId: IPropertyWithId = {
   13: { name: 'license', type: 'number', required: true },
   14: { name: 'isCurated', type: 'boolean', required: true },
 }
+
+export const featuredVideoPropertyNamesWithId: IPropertyWithId = {
+  0: { name: 'video', type: 'number', required: true },
+}

+ 27 - 0
query-node/mappings/content-directory/entity/create.ts

@@ -13,6 +13,7 @@ import { VideoMediaEncoding } from '../../../generated/graphql-server/src/module
 import { ClassEntity } from '../../../generated/graphql-server/src/modules/class-entity/class-entity.model'
 import { LicenseEntity } from '../../../generated/graphql-server/src/modules/license-entity/license-entity.model'
 import { MediaLocationEntity } from '../../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
+import { FeaturedVideo } from '../../../generated/graphql-server/src/modules/featured-video/featured-video.model'
 
 import { contentDirectoryClassNamesWithId } from '../content-dir-consts'
 import {
@@ -22,6 +23,7 @@ import {
   ICreateEntityOperation,
   IDBBlockId,
   IEntity,
+  IFeaturedVideo,
   IHttpMediaLocation,
   IJoystreamMediaLocation,
   IKnownLicense,
@@ -244,6 +246,7 @@ async function createVideo(
   video.skippableIntroDuration = p.skippableIntroDuration
   video.thumbnailUrl = p.thumbnailUrl
   video.version = block
+  video.isFeatured = false
 
   const { language, license, category, channel, media } = p
   if (language !== undefined) {
@@ -389,6 +392,29 @@ async function createMediaLocation(
   return location
 }
 
+async function createFeaturedVideo(
+  { db, block, id }: IDBBlockId,
+  classEntityMap: ClassEntityMap,
+  p: IFeaturedVideo,
+  nextEntityIdBeforeTransaction: number
+): Promise<void> {
+  const featuredVideo = new FeaturedVideo()
+
+  featuredVideo.video = await getOrCreate.video(
+    { db, block, id },
+    classEntityMap,
+    p.video!,
+    nextEntityIdBeforeTransaction
+  )
+
+  featuredVideo.id = id
+  featuredVideo.version = block
+  featuredVideo.video.isFeatured = true
+
+  await db.save<Video>(featuredVideo.video)
+  await db.save<FeaturedVideo>(featuredVideo)
+}
+
 async function getClassName(
   db: DB,
   entity: IEntity,
@@ -430,4 +456,5 @@ export {
   createMediaLocation,
   createBlockOrGetFromDatabase,
   getClassName,
+  createFeaturedVideo,
 }

+ 26 - 0
query-node/mappings/content-directory/entity/index.ts

@@ -16,6 +16,7 @@ import {
   updateVideoMediaEncodingEntityPropertyValues,
   updateLicenseEntityPropertyValues,
   updateMediaLocationEntityPropertyValues,
+  updateFeaturedVideoEntityPropertyValues,
 } from './update'
 import {
   removeCategory,
@@ -30,6 +31,7 @@ import {
   removeVideoMediaEncoding,
   removeLicense,
   removeMediaLocation,
+  removeFeaturedVideo,
 } from './remove'
 import {
   createCategory,
@@ -43,6 +45,7 @@ import {
   createLanguage,
   createVideoMediaEncoding,
   createBlockOrGetFromDatabase,
+  createFeaturedVideo,
 } from './create'
 import {
   categoryPropertyNamesWithId,
@@ -56,6 +59,7 @@ import {
   videoPropertyNamesWithId,
   contentDirectoryClassNamesWithId,
   ContentDirectoryKnownClasses,
+  featuredVideoPropertyNamesWithId,
 } from '../content-dir-consts'
 
 import {
@@ -74,6 +78,7 @@ import {
   IEntity,
   ILicense,
   IMediaLocation,
+  IFeaturedVideo,
 } from '../../types'
 import { getOrCreate } from '../get-or-create'
 
@@ -168,6 +173,14 @@ async function contentDirectory_EntitySchemaSupportAdded(db: DB, event: Substrat
         decode.setProperties<IVideoMediaEncoding>(event, videoMediaEncodingPropertyNamesWithId)
       )
       break
+    case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
+      await createFeaturedVideo(
+        arg,
+        new Map<string, IEntity[]>(),
+        decode.setProperties<IFeaturedVideo>(event, featuredVideoPropertyNamesWithId),
+        0
+      )
+      break
 
     default:
       throw new Error(`Unknown class name: ${cls.name}`)
@@ -241,6 +254,10 @@ async function contentDirectory_EntityRemoved(db: DB, event: SubstrateEvent): Pr
       await removeMediaLocation(db, where)
       break
 
+    case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
+      await removeFeaturedVideo(db, where)
+      break
+
     default:
       throw new Error(`Unknown class name: ${cls.name}`)
   }
@@ -379,6 +396,15 @@ async function contentDirectory_EntityPropertyValuesUpdated(db: DB, event: Subst
       )
       break
 
+    case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
+      await updateFeaturedVideoEntityPropertyValues(
+        db,
+        where,
+        decode.setProperties<IFeaturedVideo>(event, featuredVideoPropertyNamesWithId),
+        0
+      )
+      break
+
     default:
       throw new Error(`Unknown class name: ${cls.name}`)
   }

+ 18 - 0
query-node/mappings/content-directory/entity/remove.ts

@@ -1,3 +1,5 @@
+import Debug from 'debug'
+
 import { DB } from '../../../generated/indexer'
 import { Channel } from '../../../generated/graphql-server/src/modules/channel/channel.model'
 import { Category } from '../../../generated/graphql-server/src/modules/category/category.model'
@@ -11,15 +13,19 @@ import { Language } from '../../../generated/graphql-server/src/modules/language
 import { VideoMediaEncoding } from '../../../generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model'
 import { LicenseEntity } from '../../../generated/graphql-server/src/modules/license-entity/license-entity.model'
 import { MediaLocationEntity } from '../../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
+import { FeaturedVideo } from '../../../generated/graphql-server/src/modules/featured-video/featured-video.model'
 
 import { IWhereCond } from '../../types'
 
+const debug = Debug('mappings:remove-entity')
+
 async function removeChannel(db: DB, where: IWhereCond): Promise<void> {
   const record = await db.get(Channel, where)
   if (record === undefined) throw Error(`Channel not found`)
   if (record.videos) record.videos.map(async (v) => await removeVideo(db, { where: { id: v.id } }))
   await db.remove<Channel>(record)
 }
+
 async function removeCategory(db: DB, where: IWhereCond): Promise<void> {
   const record = await db.get(Category, where)
   if (record === undefined) throw Error(`Category not found`)
@@ -108,6 +114,17 @@ async function removeVideoMediaEncoding(db: DB, where: IWhereCond): Promise<void
   await db.remove<VideoMediaEncoding>(record)
 }
 
+async function removeFeaturedVideo(db: DB, where: IWhereCond): Promise<void> {
+  const record = await db.get(FeaturedVideo, { ...where, relations: ['video'] })
+  if (!record) throw Error(`FeaturedVideo not found. id: ${where.where.id}`)
+
+  record.video.isFeatured = false
+  record.video.featured = undefined
+
+  await db.save<Video>(record.video)
+  await db.remove<FeaturedVideo>(record)
+}
+
 export {
   removeCategory,
   removeChannel,
@@ -121,4 +138,5 @@ export {
   removeVideoMediaEncoding,
   removeMediaLocation,
   removeLicense,
+  removeFeaturedVideo,
 }

+ 29 - 0
query-node/mappings/content-directory/entity/update.ts

@@ -11,10 +11,12 @@ import { LicenseEntity } from '../../../generated/graphql-server/src/modules/lic
 import { MediaLocationEntity } from '../../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
 import { HttpMediaLocationEntity } from '../../../generated/graphql-server/src/modules/http-media-location-entity/http-media-location-entity.model'
 import { JoystreamMediaLocationEntity } from '../../../generated/graphql-server/src/modules/joystream-media-location-entity/joystream-media-location-entity.model'
+import { FeaturedVideo } from '../../../generated/graphql-server/src/modules/featured-video/featured-video.model'
 
 import {
   ICategory,
   IChannel,
+  IFeaturedVideo,
   IHttpMediaLocation,
   IJoystreamMediaLocation,
   IKnownLicense,
@@ -291,6 +293,32 @@ async function updateVideoMediaEncodingEntityPropertyValues(
   await db.save<VideoMediaEncoding>(record)
 }
 
+async function updateFeaturedVideoEntityPropertyValues(
+  db: DB,
+  where: IWhereCond,
+  props: IFeaturedVideo,
+  entityIdBeforeTransaction: number
+): Promise<void> {
+  const record = await db.get(FeaturedVideo, { ...where, relations: ['video'] })
+  if (record === undefined) throw Error(`FeaturedVideo entity not found: ${where.where.id}`)
+
+  if (props.video) {
+    const id = getEntityIdFromReferencedField(props.video, entityIdBeforeTransaction)
+    const video = await db.get(Video, { where: { id } })
+    if (!video) throw Error(`Video entity not found: ${id}`)
+
+    // Update old video isFeatured to false
+    record.video.isFeatured = false
+    await db.save<Video>(record.video)
+
+    video.isFeatured = true
+    record.video = video
+
+    await db.save<Video>(video)
+    await db.save<FeaturedVideo>(record)
+  }
+}
+
 export {
   updateCategoryEntityPropertyValues,
   updateChannelEntityPropertyValues,
@@ -304,4 +332,5 @@ export {
   updateVideoMediaEncodingEntityPropertyValues,
   updateLicenseEntityPropertyValues,
   updateMediaLocationEntityPropertyValues,
+  updateFeaturedVideoEntityPropertyValues,
 }

+ 30 - 0
query-node/mappings/content-directory/get-or-create.ts

@@ -9,6 +9,7 @@ import { Language } from '../../generated/graphql-server/src/modules/language/la
 import { VideoMediaEncoding } from '../../generated/graphql-server/src/modules/video-media-encoding/video-media-encoding.model'
 import { LicenseEntity } from '../../generated/graphql-server/src/modules/license-entity/license-entity.model'
 import { MediaLocationEntity } from '../../generated/graphql-server/src/modules/media-location-entity/media-location-entity.model'
+import { Video } from '../../generated/graphql-server/src/modules/video/video.model'
 import { NextEntityId } from '../../generated/graphql-server/src/modules/next-entity-id/next-entity-id.model'
 
 import { decode } from './decode'
@@ -39,6 +40,7 @@ import {
   IMediaLocation,
   IReference,
   IUserDefinedLicense,
+  IVideo,
   IVideoMedia,
   IVideoMediaEncoding,
 } from '../types'
@@ -55,6 +57,7 @@ import {
   createVideoMediaEncoding,
   createLicense,
   createMediaLocation,
+  createVideo,
 } from './entity/create'
 
 import { DB } from '../../generated/indexer'
@@ -394,6 +397,32 @@ async function mediaLocation(
   )
 }
 
+async function video(
+  { db, block }: IDBBlockId,
+  classEntityMap: ClassEntityMap,
+  video: IReference,
+  nextEntityIdBeforeTransaction: number
+): Promise<Video> {
+  const { existing, entityId } = video
+  if (existing) {
+    const v = await db.get(Video, { where: { id: entityId.toString() } })
+    if (!v) throw Error(`Video not found. id ${entityId}`)
+    return v
+  }
+
+  const id = generateEntityIdFromIndex(nextEntityIdBeforeTransaction + entityId)
+  const v = await db.get(Video, { where: { id } })
+  if (v) return v
+
+  const { properties } = findEntity(entityId, 'MediaVideo', classEntityMap)
+  return await createVideo(
+    { db, block, id },
+    classEntityMap,
+    decode.setEntityPropertyValues<IVideo>(properties, videoPropertyNamesWithId),
+    nextEntityIdBeforeTransaction
+  )
+}
+
 export const getOrCreate = {
   language,
   videoMediaEncoding,
@@ -407,4 +436,5 @@ export const getOrCreate = {
   license,
   mediaLocation,
   nextEntityId,
+  video,
 }

+ 21 - 0
query-node/mappings/content-directory/transaction.ts

@@ -12,6 +12,7 @@ import {
   ICreateEntityOperation,
   IDBBlockId,
   IEntity,
+  IFeaturedVideo,
   IHttpMediaLocation,
   IJoystreamMediaLocation,
   IKnownLicense,
@@ -38,6 +39,7 @@ import {
   ContentDirectoryKnownClasses,
   licensePropertyNamesWithId,
   mediaLocationPropertyNamesWithId,
+  featuredVideoPropertyNamesWithId,
 } from './content-dir-consts'
 import {
   updateCategoryEntityPropertyValues,
@@ -52,6 +54,7 @@ import {
   updateVideoMediaEncodingEntityPropertyValues,
   updateLicenseEntityPropertyValues,
   updateMediaLocationEntityPropertyValues,
+  updateFeaturedVideoEntityPropertyValues,
 } from './entity/update'
 
 import {
@@ -69,6 +72,7 @@ import {
   createLicense,
   createMediaLocation,
   createBlockOrGetFromDatabase,
+  createFeaturedVideo,
 } from './entity/create'
 import { getOrCreate } from './get-or-create'
 
@@ -256,6 +260,15 @@ async function batchAddSchemaSupportToEntity(
           )
           break
 
+        case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
+          await createFeaturedVideo(
+            arg,
+            classEntityMap,
+            decode.setEntityPropertyValues<IFeaturedVideo>(properties, featuredVideoPropertyNamesWithId),
+            nextEntityIdBeforeTransaction
+          )
+          break
+
         default:
           console.log(`Unknown class name: ${className}`)
           break
@@ -384,6 +397,14 @@ async function batchUpdatePropertyValue(db: DB, createEntityOperations: ICreateE
           entityIdBeforeTransaction
         )
         break
+      case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
+        await updateFeaturedVideoEntityPropertyValues(
+          db,
+          where,
+          decode.setEntityPropertyValues<IFeaturedVideo>(properties, featuredVideoPropertyNamesWithId),
+          entityIdBeforeTransaction
+        )
+        break
 
       default:
         console.log(`Unknown class name: ${className}`)

+ 4 - 0
query-node/mappings/types.ts

@@ -198,3 +198,7 @@ export interface IDBBlockId {
 }
 
 export type ClassEntityMap = Map<string, IEntity[]>
+
+export interface IFeaturedVideo {
+  video?: IReference
+}

+ 1 - 1
query-node/package.json

@@ -24,7 +24,7 @@
 	"author": "",
 	"license": "ISC",
 	"devDependencies": {
-		"@dzlzv/hydra-cli": "^0.0.23"
+		"@dzlzv/hydra-cli": "^0.0.24"
 	},
 	"dependencies": {
 		"@dzlzv/hydra-indexer-lib": "^0.0.20-legacy.1.26.1",

+ 13 - 0
query-node/schema.graphql

@@ -278,6 +278,11 @@ type Video @entity {
   license: LicenseEntity!
 
   happenedIn: Block!
+
+  "Is video featured or not"
+  isFeatured: Boolean!
+
+  featured: FeaturedVideo @derivedFrom(field: "video")
 }
 
 type JoystreamMediaLocation @variant {
@@ -327,3 +332,11 @@ type LicenseEntity @entity {
 
   happenedIn: Block!
 }
+
+type FeaturedVideo @entity {
+  "Runtime entity identifier (EntityId)"
+  id: ID!
+
+  "Reference to a video"
+  video: Video!
+}

+ 4 - 4
yarn.lock

@@ -1388,10 +1388,10 @@
     ajv "^6.12.0"
     ajv-keywords "^3.4.1"
 
-"@dzlzv/hydra-cli@^0.0.23":
-  version "0.0.23"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-0.0.23.tgz#b483280c3b0137347f85158a89481990757e0e21"
-  integrity sha512-Ua11sQRRcGOcItvvXRHPxababZ7aSRV9BbUGpFKA3k+fr7dSbjT2v66RSix1+ktzQ1TUPUVwNYP2XZuHkq0FcQ==
+"@dzlzv/hydra-cli@^0.0.24":
+  version "0.0.24"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-0.0.24.tgz#ec56e89f97ce85e7f1f717a0a8cf7022831c3455"
+  integrity sha512-jdL13WdjBW7bXFAwb4m7twFPbxjzlWzHw9q7C/4j2zNN45BPH2izXipue3oFinvLCUOqiBqTQuslIR6G/Cu3/g==
   dependencies:
     "@oclif/command" "^1.5.20"
     "@oclif/config" "^1"