Skip to content

Commit

Permalink
feat: support creating documents from an existing Prismic repo
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed Sep 13, 2024
1 parent b3e9a82 commit aff265b
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 20 deletions.
119 changes: 100 additions & 19 deletions src/createMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import type {
FilledContentRelationshipField,
} from "./types/value/contentRelationship"
import type { PrismicDocument } from "./types/value/document"
import type { LinkField } from "./types/value/link"
import type { EmptyLinkField, LinkField } from "./types/value/link"

type PendingPrismicDocument<TDocument extends PrismicDocument> =
InjectMigrationSpecificTypes<
Pick<TDocument, "type" | "uid" | "lang" | "tags" | "data">
>

type ExistingPrismicDocument<TDocument extends PrismicDocument> =
PendingPrismicDocument<TDocument> & Pick<TDocument, "id">
InjectMigrationSpecificTypes<TDocument>

type MigrationDocument<TDocument extends PrismicDocument> =
| PendingPrismicDocument<TDocument>
Expand All @@ -24,21 +24,20 @@ type MigrationContentRelationship =
| (() => PrismicDocument | PrismicMigrationDocument | undefined)
| (() => Promise<PrismicDocument | PrismicMigrationDocument | undefined>)

type MigrationFilledContentRelationshipField = Pick<
FilledContentRelationshipField,
"link_type" | "id"
>

type InjectMigrationSpecificTypes<T> = T extends null
? undefined
: T extends LinkField | ContentRelationshipField
? T | MigrationContentRelationship
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends Record<any, any>
? { [P in keyof T]: InjectMigrationSpecificTypes<T[P]> }
: T extends Array<infer U>
? Array<InjectMigrationSpecificTypes<U>>
: T
type MigrationContentRelationshipField =
| Pick<FilledContentRelationshipField, "link_type" | "id">
| EmptyLinkField<"Document">

type InjectMigrationSpecificTypes<T> = T extends
| LinkField
| ContentRelationshipField
? T | MigrationContentRelationship
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends Record<any, any>
? { [P in keyof T]: InjectMigrationSpecificTypes<T[P]> }
: T extends Array<infer U>
? Array<InjectMigrationSpecificTypes<U>>
: T

export const createMigration = <
TDocument extends PrismicDocument,
Expand Down Expand Up @@ -83,6 +82,27 @@ export class Migration<TDocument extends PrismicDocument> {
return migrationDocument
}

createDocumentFromPrismic(
document: TDocument,
title: string,
): PrismicMigrationDocument<TDocument> {
const migrationDocument = new PrismicMigrationDocument(
this.#migratePrismicDocumentData({
type: document.type,
lang: document.lang,
uid: document.uid,
tags: document.tags,
data: document.data,
} as PendingPrismicDocument<TDocument>),
title,
{ originalPrismicID: document.id },
)

this.documents.push(migrationDocument)

return migrationDocument
}

getByUID<TType extends TDocument["type"]>(
type: TType,
uid: string,
Expand All @@ -105,6 +125,45 @@ export class Migration<TDocument extends PrismicDocument> {
doc.document.type === type,
)
}

getByOriginalID(id: string): PrismicMigrationDocument | undefined {
return this.documents.find((doc) => doc.originalPrismicID === id)
}

#migratePrismicDocumentData(
input: PendingPrismicDocument<TDocument>,
): PendingPrismicDocument<TDocument>
#migratePrismicDocumentData(input: unknown): unknown {
if (isFilledContentRelationshipField(input)) {
if (input.isBroken) {
return { link_type: "Document", id: "_____broken_____", isBroken: true }
}

return () => this.getByOriginalID(input.id)
}

if (input === null) {
return undefined
}

if (Array.isArray(input)) {
return input.map((element) => this.#migratePrismicDocumentData(element))
}

if (typeof input === "object") {
const res: Record<PropertyKey, unknown> = {}

for (const key in input) {
res[key] = this.#migratePrismicDocumentData(
input[key as keyof typeof input],
)
}

return res
}

return input
}
}

export class PrismicMigrationDocument<
Expand All @@ -114,22 +173,31 @@ export class PrismicMigrationDocument<
title?: string
masterLanguageDocument?: MigrationContentRelationship

// Only used when the document originally came from Prismic.
originalPrismicID?: string

constructor(
document: MigrationDocument<TDocument>,
title?: string,
options?: {
masterLanguageDocument?: MigrationContentRelationship
originalPrismicID?: string
},
) {
this.document = document
this.title = title
this.masterLanguageDocument = options?.masterLanguageDocument
this.originalPrismicID = options?.originalPrismicID
}
}

export async function resolveMigrationDocumentData(
input: unknown,
): Promise<unknown> {
if (input === null) {
return undefined
}

if (input instanceof PrismicMigrationDocument || isPrismicDocument(input)) {
return resolveMigrationContentRelationship(input)
}
Expand Down Expand Up @@ -161,20 +229,22 @@ export async function resolveMigrationDocumentData(

export async function resolveMigrationContentRelationship(
relation: MigrationContentRelationship,
): Promise<MigrationFilledContentRelationshipField | undefined> {
): Promise<MigrationContentRelationshipField> {
if (typeof relation === "function") {
return resolveMigrationContentRelationship(await relation())
}

if (relation instanceof PrismicMigrationDocument) {
return relation.document.id
? { link_type: "Document", id: relation.document.id }
: undefined
: { link_type: "Document" }
}

if (relation) {
return { link_type: "Document", id: relation.id }
}

return { link_type: "Document" }
}

function isPrismicDocument(input: unknown): input is PrismicDocument {
Expand All @@ -191,3 +261,14 @@ function isPrismicDocument(input: unknown): input is PrismicDocument {
return false
}
}

function isFilledContentRelationshipField(
input: unknown,
): input is FilledContentRelationshipField {
return (
typeof input === "object" &&
input !== null &&
"link_type" in input &&
input.link_type === "Document"
)
}
5 changes: 4 additions & 1 deletion src/createWriteClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ export class WriteClient<
...doc.document,
data: documentData,
title: doc.title,
alternate_language_id: alternateLanguageDocument?.id,
alternate_language_id:
"id" in alternateLanguageDocument
? alternateLanguageDocument.id
: undefined,
}

const response = await this.#fetch(
Expand Down

0 comments on commit aff265b

Please sign in to comment.