Browse Source

query node - graceful inconsistent state overcome

ondratra 3 years ago
parent
commit
b4af533352

+ 1 - 4
query-node/mappings/src/common.ts

@@ -18,14 +18,11 @@ const currentNetwork = Network.BABYLON
 /*
   Reports that insurmountable inconsistent state has been encountered and throws an exception.
 */
-export function inconsistentState(extraInfo: string, data?: unknown): never {
+export function inconsistentState(extraInfo: string, data?: unknown): void {
   const errorMessage = 'Inconsistent state: ' + extraInfo
 
   // log error
   logger.error(errorMessage, data)
-
-  // throw exception
-  throw errorMessage
 }
 
 /*

+ 32 - 10
query-node/mappings/src/content/utils.ts

@@ -260,7 +260,12 @@ export async function convertContentActorToChannelOwner(db: DatabaseManager, con
 
     // ensure member exists
     if (!member) {
-      return inconsistentState(`Actor is non-existing member`, memberId)
+      inconsistentState(`Actor is non-existing member`, memberId)
+      return {
+        // this will clear fields
+        ownerMember: undefined,
+        ownerCuratorGroup: undefined,
+      }
     }
 
     return {
@@ -275,7 +280,12 @@ export async function convertContentActorToChannelOwner(db: DatabaseManager, con
 
     // ensure curator group exists
     if (!curatorGroup) {
-      return inconsistentState('Actor is non-existing curator group', curatorGroupId)
+      inconsistentState('Actor is non-existing curator group', curatorGroupId)
+      return {
+        // this will clear fields
+        ownerMember: undefined,
+        ownerCuratorGroup: undefined,
+      }
     }
 
     return {
@@ -366,13 +376,14 @@ interface IExtractAssetParameters {
 /*
   Selects asset from provided set of assets and prepares asset data fit to be saved to db.
 */
-async function extractAsset(parameters: IExtractAssetParameters): Promise<AssetStorageOrUrls> {
+async function extractAsset(parameters: IExtractAssetParameters): Promise<AssetStorageOrUrls | undefined> {
   // ensure asset index is valid
   if (parameters.assetIndex > parameters.assets.length) {
-    return inconsistentState(`Non-existing asset extraction requested`, {
+    inconsistentState(`Non-existing asset extraction requested`, {
       assetsProvided: parameters.assets.length,
       assetIndex: parameters.assetIndex,
     })
+    return undefined
   }
 
   // convert asset to data object record
@@ -390,12 +401,20 @@ async function extractAsset(parameters: IExtractAssetParameters): Promise<AssetS
 
   Changes `result` argument!
 */
-function integrateAsset<T>(propertyName: string, result: Object, asset: AssetStorageOrUrls) {
+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
@@ -426,7 +445,8 @@ async function extractVideoSize(assets: NewAsset[], assetIndex: number | undefin
 
   // ensure asset index is valid
   if (assetIndex > assets.length) {
-    return inconsistentState(`Non-existing asset video size extraction requested`, {assetsProvided: assets.length, assetIndex})
+    inconsistentState(`Non-existing asset video size extraction requested`, {assetsProvided: assets.length, assetIndex})
+    return undefined
   }
 
   const rawAsset = assets[assetIndex]
@@ -447,13 +467,14 @@ async function extractVideoSize(assets: NewAsset[], assetIndex: number | undefin
   return videoSize
 }
 
-async function prepareLanguage(languageIso: string, db: DatabaseManager, blockNumber: number): Promise<Language> {
+async function prepareLanguage(languageIso: string, db: DatabaseManager, blockNumber: number): Promise<Language | undefined> {
   // validate language string
   const isValidIso = ISO6391.validate(languageIso);
 
   // ensure language string is valid
   if (!isValidIso) {
-    return inconsistentState(`Invalid language ISO-639-1 provided`, languageIso)
+    inconsistentState(`Invalid language ISO-639-1 provided`, languageIso)
+    return undefined
   }
 
   // load language
@@ -517,13 +538,14 @@ async function prepareVideoMetadata(videoProtobuf: VideoMetadata.AsObject, video
   return videoMeta
 }
 
-async function prepareVideoCategory(categoryId: number, db: DatabaseManager): Promise<VideoCategory> {
+async function prepareVideoCategory(categoryId: number, db: DatabaseManager): Promise<VideoCategory | undefined> {
   // load video category
   const category = await db.get(VideoCategory, { where: { id: categoryId.toString() } as FindConditions<VideoCategory> })
 
   // ensure video category exists
   if (!category) {
-    return inconsistentState('Non-existing video category association with video requested', categoryId)
+    inconsistentState('Non-existing video category association with video requested', categoryId)
+    return undefined
   }
 
   return category

+ 2 - 2
query-node/mappings/src/content/video.ts

@@ -179,7 +179,7 @@ export async function content_VideoCreated(
 
   // ensure channel exists
   if (!channel) {
-    return inconsistentState('Trying to add video to non-existing channel', channelId)
+    inconsistentState('Trying to add video to non-existing channel', channelId)
   }
 
   // create new video
@@ -375,7 +375,7 @@ export async function content_FeaturedVideosSet(
   } as FindConditions<Video> })
 
   if (videosToAdd.length != toAdd.length) {
-    return inconsistentState('At least one non-existing video featuring requested', toAdd)
+    inconsistentState('At least one non-existing video featuring requested', toAdd)
   }
 
   // mark previously not-featured videos as featured

+ 31 - 19
query-node/mappings/src/membership.ts

@@ -50,7 +50,12 @@ export async function members_MemberUpdatedAboutText(db: DatabaseManager, event:
   const { text, memberId } = new Members.ChangeMemberAboutTextCall(event).args
 
   // load member
-  const member = await getMemberById(db, memberId)
+  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)
@@ -71,7 +76,12 @@ export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: Su
   const { uri, memberId } = new Members.ChangeMemberAvatarCall(event).args
 
   // load member
-  const member = await getMemberById(db, memberId)
+  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)
@@ -92,7 +102,12 @@ export async function members_MemberUpdatedHandle(db: DatabaseManager, event: Su
   const { handle, memberId } = new Members.ChangeMemberHandleCall(event).args
 
   // load member
-  const member = await getMemberById(db, memberId)
+  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)
@@ -112,7 +127,13 @@ export async function members_MemberSetRootAccount(db: DatabaseManager, event: S
   // read event data
   const { newRootAccount, memberId } = new Members.SetRootAccountCall(event).args
 
-  const member = await getMemberById(db, memberId)
+  // 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()
@@ -133,7 +154,12 @@ export async function members_MemberSetControllerAccount(db: DatabaseManager, ev
   const { newControllerAccount, memberId } = new Members.SetControllerAccountCall(event).args
 
   // load member
-  const member = await getMemberById(db, memberId)
+  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()
@@ -150,20 +176,6 @@ export async function members_MemberSetControllerAccount(db: DatabaseManager, ev
 
 /////////////////// Helpers ////////////////////////////////////////////////////
 
-/*
-  Retrive membership from the database
-*/
-async function getMemberById(db: DatabaseManager, id: MemberId): Promise<Membership> {
-  // load member
-  const member = await db.get(Membership, { where: { id: id.toString() } as FindConditions<Membership> })
-
-  // ensure member exists
-  if (!member) {
-    return inconsistentState(`Operation on non-existing member requested`, id)
-  }
-  return member
-}
-
 /*
   Helper for converting Bytes type to string
 */

+ 1 - 1
query-node/schema.graphql

@@ -257,7 +257,7 @@ type Video @entity {
   id: ID!
 
   "Reference to member's channel"
-  channel: Channel!
+  channel: Channel
 
   "Reference to a video category"
   category: VideoCategory