123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- import Debug from 'debug'
- import { DB, SubstrateEvent } from '../../generated/indexer'
- import { NextEntityId } from '../../generated/graphql-server/src/modules/next-entity-id/next-entity-id.model'
- import { ClassEntity } from '../../generated/graphql-server/src/modules/class-entity/class-entity.model'
- import { decode } from './decode'
- import {
- ClassEntityMap,
- IBatchOperation,
- ICategory,
- IChannel,
- ICreateEntityOperation,
- IDBBlockId,
- IEntity,
- IFeaturedVideo,
- IHttpMediaLocation,
- IJoystreamMediaLocation,
- IKnownLicense,
- ILanguage,
- ILicense,
- IMediaLocation,
- IUserDefinedLicense,
- IVideo,
- IVideoMedia,
- IVideoMediaEncoding,
- IWhereCond,
- } from '../types'
- import {
- categoryPropertyNamesWithId,
- channelPropertyNamesWithId,
- knownLicensePropertyNamesWIthId,
- userDefinedLicensePropertyNamesWithId,
- joystreamMediaLocationPropertyNamesWithId,
- httpMediaLocationPropertyNamesWithId,
- videoMediaPropertyNamesWithId,
- videoMediaEncodingPropertyNamesWithId,
- videoPropertyNamesWithId,
- languagePropertyNamesWIthId,
- ContentDirectoryKnownClasses,
- licensePropertyNamesWithId,
- mediaLocationPropertyNamesWithId,
- featuredVideoPropertyNamesWithId,
- } from './content-dir-consts'
- import {
- updateCategoryEntityPropertyValues,
- updateChannelEntityPropertyValues,
- updateVideoMediaEntityPropertyValues,
- updateVideoEntityPropertyValues,
- updateUserDefinedLicenseEntityPropertyValues,
- updateHttpMediaLocationEntityPropertyValues,
- updateJoystreamMediaLocationEntityPropertyValues,
- updateKnownLicenseEntityPropertyValues,
- updateLanguageEntityPropertyValues,
- updateVideoMediaEncodingEntityPropertyValues,
- updateLicenseEntityPropertyValues,
- updateMediaLocationEntityPropertyValues,
- updateFeaturedVideoEntityPropertyValues,
- } from './entity/update'
- import {
- createCategory,
- createChannel,
- createVideoMedia,
- createVideo,
- createUserDefinedLicense,
- createKnownLicense,
- createHttpMediaLocation,
- createJoystreamMediaLocation,
- createLanguage,
- createVideoMediaEncoding,
- getClassName,
- createLicense,
- createMediaLocation,
- createBlockOrGetFromDatabase,
- createFeaturedVideo,
- } from './entity/create'
- import { getOrCreate } from './get-or-create'
- const debug = Debug('mappings:cd:transaction')
- async function getNextEntityId(db: DB): Promise<number> {
- const e = await db.get(NextEntityId, { where: { id: '1' } })
- // Entity creation happens before addSchemaSupport so this should never happen
- if (!e) throw Error(`NextEntityId table doesn't have any record`)
- return e.nextId
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function contentDirectory_TransactionFailed(db: DB, event: SubstrateEvent): Promise<void> {
- debug(`TransactionFailed event: ${JSON.stringify(event)}`)
- const failedOperationIndex = event.params[1].value as number
- const operations = decode.getOperations(event)
- const successfulOperations = operations.toArray().slice(0, failedOperationIndex)
- if (!successfulOperations.length) return // No succesfull operations
- await applyOperations(decode.getOperationsByTypes(successfulOperations), db, event)
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function contentDirectory_TransactionCompleted(db: DB, event: SubstrateEvent): Promise<void> {
- debug(`TransactionCompleted event: ${JSON.stringify(event)}`)
- const operations = decode.getOperations(event)
- await applyOperations(decode.getOperationsByTypes(operations), db, event)
- }
- async function applyOperations(operations: IBatchOperation, db: DB, event: SubstrateEvent) {
- const { addSchemaSupportToEntityOperations, createEntityOperations, updatePropertyValuesOperations } = operations
- // Create entities before adding schema support
- // We need this to know which entity belongs to which class(we will need to know to update/create
- // Channel, Video etc.). For example if there is a property update operation there is no class id
- await batchCreateClassEntities(db, event.blockNumber, createEntityOperations)
- await batchAddSchemaSupportToEntity(db, createEntityOperations, addSchemaSupportToEntityOperations, event.blockNumber)
- await batchUpdatePropertyValue(db, createEntityOperations, updatePropertyValuesOperations)
- }
- async function batchCreateClassEntities(db: DB, block: number, operations: ICreateEntityOperation[]): Promise<void> {
- const nId = await db.get(NextEntityId, { where: { id: '1' } })
- let nextId = nId ? nId.nextId : 1 // start entity id from 1
- for (const { classId } of operations) {
- const c = new ClassEntity({
- id: nextId.toString(), // entity id
- classId: classId,
- version: block,
- happenedIn: await createBlockOrGetFromDatabase(db, block),
- })
- await db.save<ClassEntity>(c)
- nextId++
- }
- await getOrCreate.nextEntityId(db, nextId)
- }
- /**
- *
- * @param db database connection
- * @param createEntityOperations: Entity creations with in the same transaction
- * @param entities List of entities that schema support is added for
- * @param block block number
- */
- async function batchAddSchemaSupportToEntity(
- db: DB,
- createEntityOperations: ICreateEntityOperation[],
- entities: IEntity[],
- block: number
- ) {
- const classEntityMap: ClassEntityMap = new Map<string, IEntity[]>()
- for (const entity of entities) {
- const className = await getClassName(db, entity, createEntityOperations)
- if (className !== undefined) {
- const es = classEntityMap.get(className)
- classEntityMap.set(className, es ? [...es, entity] : [entity])
- }
- }
- // This is a copy of classEntityMap, we will use it to keep track of items.
- // We will remove items from this list whenever we insert them into db
- const doneList: ClassEntityMap = new Map(classEntityMap.entries())
- const nextEntityIdBeforeTransaction = (await getNextEntityId(db)) - createEntityOperations.length
- for (const [className, entities] of classEntityMap) {
- for (const entity of entities) {
- const { entityId, indexOf, properties } = entity
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const id = entityId !== undefined ? entityId : indexOf! + nextEntityIdBeforeTransaction
- const arg: IDBBlockId = { db, block, id: id.toString() }
- switch (className) {
- case ContentDirectoryKnownClasses.CATEGORY:
- await createCategory(arg, decode.setEntityPropertyValues<ICategory>(properties, categoryPropertyNamesWithId))
- break
- case ContentDirectoryKnownClasses.CHANNEL:
- await createChannel(
- arg,
- doneList,
- decode.setEntityPropertyValues<IChannel>(properties, channelPropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.KNOWNLICENSE:
- await createKnownLicense(
- arg,
- decode.setEntityPropertyValues<IKnownLicense>(properties, knownLicensePropertyNamesWIthId)
- )
- break
- case ContentDirectoryKnownClasses.USERDEFINEDLICENSE:
- await createUserDefinedLicense(
- arg,
- decode.setEntityPropertyValues<IUserDefinedLicense>(properties, userDefinedLicensePropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.JOYSTREAMMEDIALOCATION:
- await createJoystreamMediaLocation(
- arg,
- decode.setEntityPropertyValues<IJoystreamMediaLocation>(
- properties,
- joystreamMediaLocationPropertyNamesWithId
- )
- )
- break
- case ContentDirectoryKnownClasses.HTTPMEDIALOCATION:
- await createHttpMediaLocation(
- arg,
- decode.setEntityPropertyValues<IHttpMediaLocation>(properties, httpMediaLocationPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.VIDEOMEDIA:
- await createVideoMedia(
- arg,
- doneList,
- decode.setEntityPropertyValues<IVideoMedia>(properties, videoMediaPropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.VIDEO:
- await createVideo(
- arg,
- doneList,
- decode.setEntityPropertyValues<IVideo>(properties, videoPropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.LANGUAGE:
- await createLanguage(arg, decode.setEntityPropertyValues<ILanguage>(properties, languagePropertyNamesWIthId))
- break
- case ContentDirectoryKnownClasses.VIDEOMEDIAENCODING:
- await createVideoMediaEncoding(
- arg,
- decode.setEntityPropertyValues<IVideoMediaEncoding>(properties, videoMediaEncodingPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.LICENSE:
- await createLicense(
- arg,
- classEntityMap,
- decode.setEntityPropertyValues<ILicense>(properties, licensePropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.MEDIALOCATION:
- await createMediaLocation(
- arg,
- classEntityMap,
- decode.setEntityPropertyValues<IMediaLocation>(properties, mediaLocationPropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
- await createFeaturedVideo(
- arg,
- classEntityMap,
- decode.setEntityPropertyValues<IFeaturedVideo>(properties, featuredVideoPropertyNamesWithId),
- nextEntityIdBeforeTransaction
- )
- break
- default:
- console.log(`Unknown class name: ${className}`)
- break
- }
- }
- }
- }
- /**
- * Batch update operations for entity properties values update
- * @param db database connection
- * @param createEntityOperations Entity creations with in the same transaction
- * @param entities list of entities those properties values updated
- */
- async function batchUpdatePropertyValue(db: DB, createEntityOperations: ICreateEntityOperation[], entities: IEntity[]) {
- const entityIdBeforeTransaction = (await getNextEntityId(db)) - createEntityOperations.length
- for (const entity of entities) {
- const { entityId, indexOf, properties } = entity
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const id = entityId ? entityId.toString() : entityIdBeforeTransaction - indexOf!
- const where: IWhereCond = { where: { id: id.toString() } }
- const className = await getClassName(db, entity, createEntityOperations)
- if (className === undefined) {
- console.log(`Can not update entity properties values. Unknown class name`)
- return
- }
- switch (className) {
- case ContentDirectoryKnownClasses.CHANNEL:
- await updateChannelEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IChannel>(properties, channelPropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.CATEGORY:
- await updateCategoryEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<ICategory>(properties, categoryPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.KNOWNLICENSE:
- await updateKnownLicenseEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IKnownLicense>(properties, knownLicensePropertyNamesWIthId)
- )
- break
- case ContentDirectoryKnownClasses.USERDEFINEDLICENSE:
- await updateUserDefinedLicenseEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IUserDefinedLicense>(properties, userDefinedLicensePropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.JOYSTREAMMEDIALOCATION:
- await updateJoystreamMediaLocationEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IJoystreamMediaLocation>(properties, joystreamMediaLocationPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.HTTPMEDIALOCATION:
- await updateHttpMediaLocationEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IHttpMediaLocation>(properties, httpMediaLocationPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.VIDEOMEDIA:
- await updateVideoMediaEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IVideoMedia>(properties, videoPropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.VIDEO:
- await updateVideoEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IVideo>(properties, videoPropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.LANGUAGE:
- await updateLanguageEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<ILanguage>(properties, languagePropertyNamesWIthId)
- )
- break
- case ContentDirectoryKnownClasses.VIDEOMEDIAENCODING:
- await updateVideoMediaEncodingEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IVideoMediaEncoding>(properties, videoMediaEncodingPropertyNamesWithId)
- )
- break
- case ContentDirectoryKnownClasses.LICENSE:
- await updateLicenseEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<ILicense>(properties, licensePropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.MEDIALOCATION:
- await updateMediaLocationEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IMediaLocation>(properties, mediaLocationPropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- case ContentDirectoryKnownClasses.FEATUREDVIDEOS:
- await updateFeaturedVideoEntityPropertyValues(
- db,
- where,
- decode.setEntityPropertyValues<IFeaturedVideo>(properties, featuredVideoPropertyNamesWithId),
- entityIdBeforeTransaction
- )
- break
- default:
- console.log(`Unknown class name: ${className}`)
- break
- }
- }
- }
|