Skip to content

Instantly share code, notes, and snippets.

@hos
Last active March 17, 2023 15:20
Show Gist options
  • Save hos/4cbea782f52bbcfe6db9cc3f8b974412 to your computer and use it in GitHub Desktop.
Save hos/4cbea782f52bbcfe6db9cc3f8b974412 to your computer and use it in GitHub Desktop.
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