Skip to content

Instantly share code, notes, and snippets.

@squamuglia
Created February 14, 2022 16:33
Show Gist options
  • Save squamuglia/771be284c7f6ce6c5bb92a1f01489979 to your computer and use it in GitHub Desktop.
Save squamuglia/771be284c7f6ce6c5bb92a1f01489979 to your computer and use it in GitHub Desktop.
import fetch from "node-fetch"
import sanityClient from "@sanity/client"
import * as fs from "fs"
import { fetchAPI } from "./fetchApi"
import gql from "graphql-tag"
const API_URL = "[add yours here]"
export async function fetchAPI(query, { variables = null } = {}) {
const QUERY = typeof query === "string" ? query : query?.loc.source.body
try {
const res = await fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: QUERY,
variables,
}),
})
const json = await res.json()
if (json.errors) {
console.error(json.errors)
throw new Error("Failed to fetch API")
}
return json.data
} catch (err) {
console.error(err)
}
}
/**
* To run these scripts, use sanity exec bin/migrate.ts --with-user-token
*/
const client = sanityClient({
projectId: "[Add yours here]",
dataset: "production",
apiVersion: "2021-06-07",
useCdn: false,
token:
"[Add yours here]"
})
const migratePosts = async () => {
const query = gql`
query {
posts(first: 1000) {
edges {
node {
postId
title
title_spanish
excerpt
slug
date
featuredImage {
node {
mediaItemUrl
altText
}
}
categories {
edges {
node {
name
}
}
}
tags {
edges {
node {
name
}
}
}
content
content_spanish
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.posts.edges
for (const edge of edges) {
try {
const { node } = edge
const filename = node?.featuredImage?.node.mediaItemUrl.split("/").pop()
let imageDocument
if (filename) {
const file = `bin/fne-site-uploads/${filename}`
// @ts-ignore
imageDocument = await client.assets.upload(
"image",
fs.createReadStream(file),
{ filename }
)
}
const doc = {
_id: node.slug,
_type: "post",
mainImage: imageDocument
? {
_type: "image",
asset: {
_ref: imageDocument._id,
_type: "reference",
},
}
: undefined,
slug: {
_type: "slug",
current: node.slug,
},
publishedAt: node.date,
title: {
_type: "localizedString",
en: node.title,
es: node.title_spanish ?? node.title,
},
legacyContent: {
_type: "localizedString",
en: node.content,
es: node.content_spanish ?? node.content,
},
}
await client.createOrReplace(doc)
// Sanity has a limit of 25 reqs/s
await new Promise((res) => setTimeout(() => res(null), 1000 / 25))
console.log(`created post: ${doc._id}`)
} catch (e) {
console.error("Error creating doc: ", e)
}
}
console.log("Upload complete")
}
const migratePages = async () => {
const query = gql`
query {
pages(first: 1000) {
edges {
node {
pageId
title
slug
date
featuredImage {
node {
mediaItemUrl
altText
}
}
content
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.pages.edges
for (const edge of edges) {
try {
const { node } = edge
const filename = node?.featuredImage?.node.mediaItemUrl.split("/").pop()
let imageDocument
if (filename) {
const file = `bin/fne-site-uploads/${filename}`
// @ts-ignore
imageDocument = await client.assets.upload(
"image",
fs.createReadStream(file),
{ filename }
)
}
const doc = {
_id: node.slug,
_type: "page",
_createdAt: node.date,
mainImage: imageDocument
? {
_type: "image",
asset: {
_ref: imageDocument._id,
_type: "reference",
},
}
: undefined,
slug: {
_type: "slug",
current: node.slug,
},
publishedAt: node.date,
title: {
_type: "localizedString",
en: node.title,
es: node.title,
},
legacyContent: {
_type: "localizedString",
en: node.content,
es: node.content,
},
}
await client.createOrReplace(doc)
// Sanity has a limit of 25 reqs/s
await new Promise((res) => setTimeout(() => res(null), 1000 / 25))
console.log(`created page: ${doc._id}`)
} catch (e) {
console.error("Error creating doc: ", e)
}
}
console.log("Upload complete")
}
const migrateMembers = async () => {
const query = gql`
query {
members(first: 100) {
nodes {
slug
memberDetails {
order
name
position
project
team
email
image {
mediaItemUrl
altText
title
}
}
}
}
}
`
const data = await fetchAPI(query)
const nodes = data.members.nodes
for (const node of nodes) {
try {
const { memberDetails } = node
const filename = memberDetails?.image?.mediaItemUrl.split("/").pop()
let image
if (filename) {
const file = `bin/fne-site-uploads/${filename}`
// @ts-ignore
const imageDocument = await client.assets.upload(
"image",
fs.createReadStream(file),
{ filename }
)
image = imageDocument
? {
mainImage: {
_type: "image",
asset: {
_ref: imageDocument._id,
_type: "reference",
},
},
}
: {}
}
const doc = {
_id: node.slug,
_type: "member",
email: memberDetails.email,
name: memberDetails.name,
position: memberDetails.position,
team: memberDetails.team,
...image,
}
await client.createOrReplace(doc)
// Sanity has a limit of 25 reqs/s
await new Promise((res) => setTimeout(() => res(null), 1000 / 25))
console.log(`created doc: ${doc._id}`)
} catch (e) {
console.error("Error creating doc: ", e)
}
}
console.log("Upload complete")
}
const patchProjectDates = async () => {
const query = gql`
query {
posts(first: 1000, where: { categoryName: "projects" }) {
edges {
node {
slug
date
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.posts.edges
for (const edge of edges) {
try {
const { node } = edge
const date = new Date(node.date).toISOString()
await client
.patch(`project_${node.slug}`) // Document ID to patch
.set({ _createdAt: date, publishedAt: date }) // Shallow merge
.commit() // Perform the patch and return a promise
console.log(`created posts: ${node.slug}`)
} catch (e) {
console.error("Error creating patch: ", e)
}
}
console.log("Upload complete")
}
const migrateProjects = async () => {
const query = gql`
query {
posts(first: 1000, where: { categoryName: "projects" }) {
edges {
node {
title
title_spanish
slug
date
content
content_spanish
featuredImage {
node {
mediaItemUrl
altText
}
}
location {
location {
latitude
longitude
}
}
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.posts.edges
for (const edge of edges) {
try {
const { node } = edge
const filename = node?.featuredImage?.node.mediaItemUrl.split("/").pop()
const date = new Date(node.date).toISOString()
let imageDocument
if (filename) {
const file = `bin/fne-site-uploads/${filename}`
// @ts-ignore
imageDocument = await client.assets.upload(
"image",
fs.createReadStream(file),
{ filename }
)
}
const doc = {
_id: `project_${node.slug}`,
_type: "project",
mainImage: imageDocument
? {
_type: "image",
asset: {
_ref: imageDocument._id,
_type: "reference",
},
}
: undefined,
slug: {
_type: "slug",
current: `project/${node.slug}`,
},
publishedAt: date,
location: node.location?.location?.latitude
? {
_type: "geopoint",
lat: node.location.location.latitude,
lng: node.location.location.longitude,
}
: undefined,
title: {
_type: "localizedString",
en: node.title,
es: node.title,
},
legacyContent: {
_type: "localizedString",
en: node.content,
es: node.content,
},
}
await client.createOrReplace(doc)
console.log(`created project: ${doc._id}`)
} catch (e) {
console.error("Error creating doc: ", e.message)
}
}
console.log("Upload complete")
}
const deleteProjectPosts = async () => {
const query = gql`
query {
posts(first: 1000, where: { categoryName: "projects" }) {
edges {
node {
slug
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.posts.edges
for (const edge of edges) {
try {
const { node } = edge
await client.delete(node.slug)
console.log(`delete project post: ${node.slug}`)
} catch (e) {
console.error("Error creating doc: ", e.message)
}
}
console.log("Upload complete")
}
const patchProjectSlugs = async () => {
const query = gql`
query {
posts(first: 1000, where: { categoryName: "projects" }) {
edges {
node {
slug
}
}
}
}
`
const data = await fetchAPI(query)
const edges = data.posts.edges
for (const edge of edges) {
try {
const { node } = edge
await client
.patch(`project_${node.slug}`) // Document ID to patch
.set({ slug: { current: node.slug } }) // Shallow merge
.commit() // Perform the patch and return a promise
console.log(`patched posts: ${node.slug}`)
} catch (e) {
console.error("Error creating patch: ", e)
}
}
console.log("Upload complete")
}
const run = (fn: () => Promise<any>) => {
console.log(`Starting ${fn.name}`)
fn().catch((err) => {
console.error(err)
process.exit(1)
})
}
const runAll = (...fns: (() => Promise<any>)[]) => {
for (const fn of fns) {
console.log(`Starting ${fn.name}`)
fn().catch((err) => {
console.error(err)
process.exit(1)
})
}
}
// run these in the below order
runAll(patchProjectSlugs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment