Last active
March 17, 2023 15:20
-
-
Save hos/4cbea782f52bbcfe6db9cc3f8b974412 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { PgSelectSingleStep } from "@dataplan/pg"; | |
import { Episode } from "@mythrillfiction/types"; | |
import { context, lambda } from "grafast"; | |
import { gql, makeExtendSchemaPlugin, makeWrapPlansPlugin, PlanWrapperFn } from "graphile-utils"; | |
import { WorkerUtils } from "graphile-worker"; | |
import _ from "lodash"; | |
import * as yup from "yup"; | |
import { SCHEMA_NAME } from "../config.js"; | |
import { adminDb } from "../firebase.js"; | |
import { CreateEpisodeInput, Season } from "../gql/sdk.js"; | |
import { extractDocumentText } from "../utils/gcp.utils.js"; | |
import { getDriveDocumentLink } from "../utils/slack.utils.js"; | |
const EpisodeUpdateSchema = yup.object().shape({ | |
title: yup.string().max(100), | |
teaserText: yup.string().max(400), | |
}); | |
const EpisodeExportPlugin = makeWrapPlansPlugin((build) => { | |
const seasonSource = build.input.pgSources.find( | |
(s) => !s.parameters && s.extensions?.pg?.schemaName === SCHEMA_NAME && s.extensions.pg.name === "seasons" | |
); | |
if (!seasonSource) { | |
throw new Error("Couldn't find source for app_public.seasons"); | |
} | |
return { | |
Mutation: { | |
createEpisode: (plan, $source, args) => { | |
const $input = args.get(["input"]); | |
const $planResult = plan(); | |
const $workerUtils = context().get("workerUtils"); | |
const $validate = lambda([$input], async ([_input, _workerUtils]) => { | |
const input = _input as CreateEpisodeInput; | |
await EpisodeUpdateSchema.validate(input.episode); | |
}); | |
$validate.hasSideEffects = true; | |
const $seasonId = args.get(["input", "episode", "seasonId"]); | |
const $season = seasonSource.get({ id: $seasonId }) as PgSelectSingleStep<any, any, any, any>; | |
// We need to get price of the last episode from firestore | |
// and create the new episode with that same price. | |
const $price = lambda([$input, $season.record()], async ([_input, _season]) => { | |
const season = _season as any; | |
const storyId = season.story_id; | |
const snapshot = await adminDb.collectionGroup(`episodes`).where("storyId", "==", storyId).get(); | |
const episodes = _.orderBy( | |
snapshot.docs.map( | |
(doc) => | |
({ | |
...doc.data(), | |
episodeIndex: doc.get("seasonNumber") * 100 + doc.get("episodeNumber"), | |
} as Episode & { episodeIndex: number }) | |
), | |
["episodeIndex"], | |
["desc"] | |
); | |
const lastEpisode = episodes[0]; | |
const lastEpisodePrice = lastEpisode?.price || 3; | |
return lastEpisodePrice; | |
}); | |
const $insert = $planResult.get("result"); | |
$insert.set( | |
"price", | |
lambda([$input, $price], async ([_input, _price]) => { | |
const input = _input as CreateEpisodeInput; | |
const price = _price as number | undefined; | |
if (input.episode.price === undefined && price) { | |
return price; | |
} | |
return input.episode.price; | |
}) | |
); | |
// This may be also implemented with database triggers, | |
// but later we will need to add here javascript. | |
const $id = $planResult.get("result").get("id"); | |
const $exportToDrive = lambda([$id, $workerUtils], async ([episodeId, _workerUtils]) => { | |
const workerUtils = _workerUtils as WorkerUtils; | |
await workerUtils.addJob("exportEpisodeToDrive", { episodeId }, { maxAttempts: 1 }); | |
}); | |
$exportToDrive.hasSideEffects = true; | |
return $planResult; | |
}, | |
// updateEpisode: resolve(false), | |
}, | |
}; | |
}); | |
const EpisodeDriveDocumentPlugin = makeExtendSchemaPlugin(() => { | |
return { | |
typeDefs: gql` | |
extend type Episode { | |
driveDocumentLink: String | |
""" | |
Will get text from drive document, convert to HTML and sanitize it, | |
so it will be compatible with the mobile app HTML renderer. Take into account | |
this is an external API call and it will delay your response. | |
""" | |
driveDocumentText: String | |
} | |
`, | |
plans: { | |
Episode: { | |
driveDocumentLink($obj) { | |
const $driveDocumentId = $obj.get("drive_document_id"); | |
return lambda($driveDocumentId, getDriveDocumentLink); | |
}, | |
driveDocumentText($obj) { | |
const $driveDocumentId = $obj.get("drive_document_id"); | |
return lambda($driveDocumentId, extractDocumentText); | |
}, | |
}, | |
}, | |
}; | |
}); | |
const EpisodePlugin: GraphileConfig.Preset = { | |
plugins: [EpisodeExportPlugin, EpisodeDriveDocumentPlugin], | |
}; | |
export default EpisodePlugin; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment