Skip to content

Commit

Permalink
refactor: simplify add media api to accept fewerparams for embedded t…
Browse files Browse the repository at this point in the history
…ag (#339)

- refactor: seed-db script should only download db file once
- refactor: simplify embedded tag params when adding new media objects
  • Loading branch information
vnugent committed Jul 12, 2023
1 parent 4ff66da commit 110b0c2
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 26 deletions.
15 changes: 11 additions & 4 deletions seed-db.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# This script rebuilds your local database with
# a copy of OpenBeta staging database.
# Rebuild your local database with a copy of OpenBeta staging database.
#
# To keep running time short, the script only downloads the remote
# database dump file once. Specify 'download' argument to force download.
#
# Syntax:
# ./seed-db.sh [download]
#
#!/bin/bash

FILE_NAME="openbeta-stg-db.tar.gz"
REMOTE_FILE="https://storage.googleapis.com/openbeta-dev-dbs/$FILE_NAME"

echo "Downloading db file(s)..."
wget --content-disposition $REMOTE_FILE
if [[ ! -f ${FILE_NAME} || ${1} == "download" ]]; then
echo "Downloading db file(s)..."
wget --content-disposition $REMOTE_FILE
fi

rm -rf ./db-dumps/staging/openbeta

Expand Down
9 changes: 7 additions & 2 deletions src/db/MediaObjectTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface MediaObject {
format: ImageFormatType
createdAt: Date
size: number
entityTags: EntityTag[]
entityTags?: EntityTag[]
}

export interface EntityTag {
Expand Down Expand Up @@ -52,6 +52,11 @@ export interface TagsLeaderboardType {
allTime: AllTimeTagStats
}

/**
* For creating a new Media object doc
*/
export type NewMediaObjectDoc = Omit<MediaObject, '_id' | 'createdAt'>

export interface UserMediaGQLQueryInput {
userUuid: string
maxFiles?: number
Expand Down Expand Up @@ -84,7 +89,7 @@ export interface EntityTagDeleteInput {
*/
export type MediaObjectGQLInput = Pick<MediaObject, 'mediaUrl' | 'width' | 'height' | 'format' | 'size'> & {
userUuid: string
entityTags?: Array<Omit<AddEntityTagGQLInput, 'mediaId'>>
entityTag?: Omit<AddEntityTagGQLInput, 'mediaId'>
}

/**
Expand Down
14 changes: 7 additions & 7 deletions src/graphql/schema/Media.gql
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
type Mutation {
"""
Add one or more media objects
Add one or more media objects. Each media object may contain one tag.
"""
addMediaObjects(input: [NewMediaObjectInput]): [MediaWithTags]

"""
Add sone media object
Delete one media object.
"""
deleteMediaObject(input: MediaDeleteInput!): Boolean!


"""
Add an entity tag to a media
Add an entity tag to a media.
"""
addEntityTag(input: MediaEntityTagInput): EntityTag!

"""
Remove an entity tag from a media
Remove an entity tag from a media.
"""
removeEntityTag(input: EntityTagDeleteInput!): Boolean!
}

type Query {
"""
Get single media object
Get single media object.
"""
media(input: MediaInput): MediaWithTags

Expand All @@ -46,7 +46,7 @@ type Query {
getUserMediaPagination(input: UserMediaInput): UserMedia

"""
Get a list of users and their tagged photo count
Get a list of users and their tagged photo count.
"""
getTagsLeaderboard(limit: Int): TagsLeaderboard
}
Expand Down Expand Up @@ -172,7 +172,7 @@ input NewMediaObjectInput {
format: String!
size: Int!
mediaUrl: String!
entityTags: [EmbeddedEntityInput]
entityTag: EmbeddedEntityInput
}

input EmbeddedEntityInput {
Expand Down
45 changes: 33 additions & 12 deletions src/model/MutableMediaDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@ import mongoose from 'mongoose'
import muuid from 'uuid-mongodb'

import MediaDataSource from './MediaDataSource.js'
import { EntityTag, EntityTagDeleteInput, MediaObject, MediaObjectGQLInput, AddTagEntityInput } from '../db/MediaObjectTypes.js'
import { EntityTag, EntityTagDeleteInput, MediaObject, MediaObjectGQLInput, AddTagEntityInput, NewMediaObjectDoc } from '../db/MediaObjectTypes.js'
import MutableAreaDataSource from './MutableAreaDataSource.js'

export default class MutableMediaDataSource extends MediaDataSource {
areaDS = MutableAreaDataSource.getInstance()

/**
* Add a new entity tag (a climb or area) to a media object.
* @returns new EntityTag . 'null' if the entity already exists.
*/
async addEntityTag ({ mediaId, entityUuid, entityType }: AddTagEntityInput): Promise<EntityTag> {
async getEntityDoc ({ entityUuid, entityType }: Omit<AddTagEntityInput, 'mediaId'>): Promise<EntityTag> {
let newEntityTagDoc: EntityTag
switch (entityType) {
case 0: {
Expand Down Expand Up @@ -61,6 +57,16 @@ export default class MutableMediaDataSource extends MediaDataSource {

default: throw new UserInputError(`Entity type ${entityType} not supported.`)
}
return newEntityTagDoc
}

/**
* Add a new entity tag (a climb or area) to a media object.
* @returns new EntityTag . 'null' if the entity already exists.
*/
async addEntityTag ({ mediaId, entityUuid, entityType }: AddTagEntityInput): Promise<EntityTag> {
// Find the entity we want to tag
const newEntityTagDoc = await this.getEntityDoc({ entityUuid, entityType })

// We treat 'entityTags' like a Set - can't tag the same climb/area id twice.
// See https://stackoverflow.com/questions/33576223/using-mongoose-mongodb-addtoset-functionality-on-array-of-objects
Expand Down Expand Up @@ -106,16 +112,31 @@ export default class MutableMediaDataSource extends MediaDataSource {
}

/**
* Add one or more media objects.
* Add one or more media objects. The embedded entityTag may have one tag.
*/
async addMediaObjects (input: MediaObjectGQLInput[]): Promise<MediaObject[]> {
const docs = input.map(entry => ({
...entry,
userUuid: muuid.from(entry.userUuid)
const docs: NewMediaObjectDoc[] = await Promise.all(input.map(async entry => {
const { userUuid: userUuidStr, mediaUrl, width, height, format, size, entityTag } = entry
let newTag: EntityTag | undefined
if (entityTag != null) {
newTag = await this.getEntityDoc({
entityType: entityTag.entityType,
entityUuid: muuid.from(entityTag.entityId)
})
}

return ({
mediaUrl,
width,
height,
format,
size,
userUuid: muuid.from(userUuidStr),
...newTag != null && { entityTags: [newTag] }
})
}))

const rs = await this.mediaObjectModel.insertMany(docs, { lean: true })
// @ts-expect-error
return rs != null ? rs : []
}

Expand All @@ -126,7 +147,7 @@ export default class MutableMediaDataSource extends MediaDataSource {
const filter = { _id: mediaId }
const rs = await this.mediaObjectModel.find(filter).orFail(new UserInputError(`Media Id not found ${mediaId.toString()}`))

if (rs[0].entityTags.length > 0) {
if ((rs[0].entityTags?.length ?? 0) > 0) {
throw new UserInputError('Cannot delete media object with non-empty tags. Delete tags first.')
}

Expand Down
2 changes: 1 addition & 1 deletion src/model/__tests__/MediaDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe('MediaDataSource', () => {
const rs = await media.addMediaObjects([{
...TEST_MEDIA,
mediaUrl: 'photo101.jpg',
entityTags: [{ entityType: 0, entityId: muuid.v4().toUUID().toString() }]
entityTag: { entityType: 0, entityId: climbIdForTagging.toUUID().toString() }
}
])

Expand Down

0 comments on commit 110b0c2

Please sign in to comment.