From 51fdf4df97d167fcb1d2a6fe3846d0a3211ba62e Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 1 Mar 2021 16:54:39 -0500 Subject: [PATCH 1/2] Try type gurads --- client/dive-common/use/useSave.ts | 57 ++++++++++++++++--------------- client/src/track.ts | 11 ++++++ client/src/use/useAttributes.ts | 11 ++++++ 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/client/dive-common/use/useSave.ts b/client/dive-common/use/useSave.ts index d81357388..7fb4051e8 100644 --- a/client/dive-common/use/useSave.ts +++ b/client/dive-common/use/useSave.ts @@ -1,10 +1,25 @@ import { ref, Ref } from '@vue/composition-api'; -import Track, { TrackId } from 'vue-media-annotator/track'; -import { Attribute } from 'vue-media-annotator/use/useAttributes'; +import Track, { TrackId, isTrack } from 'vue-media-annotator/track'; +import { Attribute, isAttribute } from 'vue-media-annotator/use/useAttributes'; import { useApi, DatasetMetaMutable } from 'dive-common/apispec'; +function _updatePendingChangeMap( + key: K, value: V, + action: 'upsert' | 'delete', + upsert: Map, + del: Set, +) { + if (action === 'delete') { + del.add(key); + upsert.delete(key); + } else if (action === 'upsert') { + del.delete(key); + upsert.set(key, value); + } +} + export default function useSave(datasetId: Ref>) { const pendingSaveCount = ref(0); const pendingChangeMap = { @@ -49,37 +64,25 @@ export default function useSave(datasetId: Ref>) { function markChangesPending( { - type, action, data, }: { - type: 'track' | 'attribute' | 'meta'; - action?: 'upsert' | 'delete'; - data?: Track | Attribute; - } = { type: 'meta' }, + action: 'upsert' | 'delete' | 'meta'; + data?: Track | Attribute; + } = { action: 'meta' }, ) { - if (type === 'meta') { + if (action === 'meta') { pendingChangeMap.meta += 1; - } else if (type === 'track' && data !== undefined && (data as Track).trackId !== undefined) { - const track = data as Track; - if (action === 'delete') { - pendingChangeMap.delete.add(track.trackId); - pendingChangeMap.upsert.delete(track.trackId); - } else if (action === 'upsert') { - pendingChangeMap.delete.delete(track.trackId); - pendingChangeMap.upsert.set(track.trackId, track); - } - } else if (type === 'attribute' && data !== undefined && (data as Attribute)._id !== undefined) { - const attribute = data as Attribute; - if (action === 'delete') { - pendingChangeMap.attributeDelete.add(attribute._id); - pendingChangeMap.attributeUpsert.delete(attribute._id); - } else if (action === 'upsert') { - pendingChangeMap.attributeDelete.delete(attribute._id); - pendingChangeMap.attributeUpsert.set(attribute._id, attribute); - } + } else if (isTrack(data)) { + _updatePendingChangeMap( + data.trackId, data, action, pendingChangeMap.upsert, pendingChangeMap.delete, + ); + } else if (isAttribute(data)) { + _updatePendingChangeMap( + data._id, data, action, pendingChangeMap.attributeUpsert, pendingChangeMap.attributeDelete, + ); } else { - throw new Error('Arguments inconsistent with pending change type'); + throw new Error(`Arguments inconsistent with pending change type: ${action} cannot be performed on ${data}`); } pendingSaveCount.value += 1; } diff --git a/client/src/track.ts b/client/src/track.ts index a805c660a..05a3b24ef 100644 --- a/client/src/track.ts +++ b/client/src/track.ts @@ -51,6 +51,17 @@ interface TrackParams { attributes?: StringKeyObject; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isTrack(obj: any): obj is Track { + return ( + (typeof obj === 'object') + && (obj.trackId !== undefined) + && (typeof obj.features === 'object') + && (typeof obj.begin === 'number') + && (typeof obj.end === 'number') + ); +} + /** * Track manages the state of a track, its * frame data, and all metadata. diff --git a/client/src/use/useAttributes.ts b/client/src/use/useAttributes.ts index b2ebcb5ae..300a502ff 100644 --- a/client/src/use/useAttributes.ts +++ b/client/src/use/useAttributes.ts @@ -11,6 +11,17 @@ export interface Attribute { _id: string; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isAttribute(obj: any): obj is Attribute { + return ( + (typeof obj === 'object') + && (typeof obj.belongs === 'string') + && (typeof obj.datatype === 'string') + && (typeof obj._id === 'string') + && (typeof obj.name === 'string') + ); +} + export type Attributes = Record; /** From f84f241165e70c470ff6bbdbb37626bfa52c8132 Mon Sep 17 00:00:00 2001 From: BryonLewis <61746913+BryonLewis@users.noreply.github.com> Date: Tue, 2 Mar 2021 08:24:52 -0500 Subject: [PATCH 2/2] markChangesPending update (#609) --- client/src/use/useAttributes.ts | 8 +++----- client/src/use/useTrackStore.ts | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/client/src/use/useAttributes.ts b/client/src/use/useAttributes.ts index 300a502ff..b6272fe75 100644 --- a/client/src/use/useAttributes.ts +++ b/client/src/use/useAttributes.ts @@ -30,11 +30,9 @@ export type Attributes = Record; interface UseAttributesParams { markChangesPending: ( { - type, action, data, }: { - type: 'attribute'; action: 'upsert' | 'delete'; data: Attribute; } @@ -62,7 +60,7 @@ export default function UseAttributes({ markChangesPending }: UseAttributesParam oldAttribute = attributes.value[data._id]; // Name change should delete the old attribute and create a new one with the updated id VueDel(attributes.value, data._id); - markChangesPending({ type: 'attribute', action: 'delete', data: { ...attributes.value[data._id] } }); + markChangesPending({ action: 'delete', data: { ...attributes.value[data._id] } }); // Create a new attribute to replace it // eslint-disable-next-line no-param-reassign data._id = `${data.belongs}_${data.name}`; @@ -72,13 +70,13 @@ export default function UseAttributes({ markChangesPending }: UseAttributesParam // TODO: Lengthy track/detection attribute updating function } VueSet(attributes.value, data._id, data); - markChangesPending({ type: 'attribute', action: 'upsert', data: attributes.value[data._id] }); + markChangesPending({ action: 'upsert', data: attributes.value[data._id] }); } function deleteAttribute(attributeId: string, removeFromTracks = false) { if (attributes.value[attributeId] !== undefined) { - markChangesPending({ type: 'attribute', action: 'delete', data: { ...attributes.value[attributeId] } }); + markChangesPending({ action: 'delete', data: { ...attributes.value[attributeId] } }); VueDel(attributes.value, attributeId); } if (removeFromTracks) { diff --git a/client/src/use/useTrackStore.ts b/client/src/use/useTrackStore.ts index 6b5837e3f..bcb88aa71 100644 --- a/client/src/use/useTrackStore.ts +++ b/client/src/use/useTrackStore.ts @@ -5,12 +5,10 @@ import Track, { TrackId } from '../track'; interface UseTrackStoreParams { markChangesPending: ( { - type, action, data, }: { - type: 'track'; action: 'upsert' | 'delete'; data: Track; }) => void; @@ -74,7 +72,7 @@ export default function useTrackStore({ markChangesPending }: UseTrackStoreParam intervalTree.insert([track.begin, track.end], track.trackId.toString()); } canary.value += 1; - markChangesPending({ type: 'track', action: 'upsert', data: track }); + markChangesPending({ action: 'upsert', data: track }); } function insertTrack(track: Track, afterId?: TrackId) { @@ -97,7 +95,7 @@ export default function useTrackStore({ markChangesPending }: UseTrackStoreParam confidencePairs: [[defaultType, 1]], }); insertTrack(track, afterId); - markChangesPending({ type: 'track', action: 'upsert', data: track }); + markChangesPending({ action: 'upsert', data: track }); return track; } @@ -117,7 +115,7 @@ export default function useTrackStore({ markChangesPending }: UseTrackStoreParam throw new Error(`TrackId ${trackId} not found in trackIds.`); } trackIds.value.splice(listIndex, 1); - markChangesPending({ type: 'track', action: 'delete', data: track }); + markChangesPending({ action: 'delete', data: track }); } /*