refactor: update collection type using zod

This commit is contained in:
nivedin
2023-12-11 17:33:06 +05:30
committed by Andrew Bastin
parent b6f3b24b9e
commit 79a8bc669e
4 changed files with 127 additions and 33 deletions

View File

@@ -1,37 +1,47 @@
import { import { InferredEntity, createVersionedEntity } from "verzod"
GQL_REQ_SCHEMA_VERSION,
HoppGQLRequest,
translateToGQLRequest,
} from "../graphql"
import { HoppRESTRequest, translateToNewRequest } from "../rest"
const CURRENT_COLL_SCHEMA_VER = 1 import V1_VERSION from "./v/1"
import V2_VERSION from "./v/2"
type SupportedReqTypes = HoppRESTRequest | HoppGQLRequest import { z } from "zod"
import { translateToNewRequest } from "../rest"
import { translateToGQLRequest } from "../graphql"
export type HoppCollection<T extends SupportedReqTypes> = { const versionedObject = z.object({
v: number // v is a stringified number
name: string v: z.string().regex(/^\d+$/).transform(Number),
folders: HoppCollection<T>[] })
requests: T[]
auth: T["auth"] export const HoppCollection = createVersionedEntity({
headers: T["headers"] latestVersion: 2,
versionMap: {
1: V1_VERSION,
2: V2_VERSION,
},
getVersion(data) {
const versionCheck = versionedObject.safeParse(data)
id?: string // For Firestore ID data if (versionCheck.success) return versionCheck.data.v
}
// For V1 we have to check the schema
const result = V1_VERSION.schema.safeParse(data)
return result.success ? 0 : null
},
})
export type HoppCollection = InferredEntity<typeof HoppCollection>
export const CollectionSchemaVersion = 2
/** /**
* Generates a Collection object. This ignores the version number object * Generates a Collection object. This ignores the version number object
* so it can be incremented independently without updating it everywhere
* @param x The Collection Data * @param x The Collection Data
* @returns The final collection * @returns The final collection
*/ */
export function makeCollection<T extends SupportedReqTypes>( export function makeCollection(x: Omit<HoppCollection, "v">): HoppCollection {
x: Omit<HoppCollection<T>, "v">
): HoppCollection<T> {
return { return {
v: CURRENT_COLL_SCHEMA_VER, v: CollectionSchemaVersion,
...x, ...x,
} }
} }
@@ -41,20 +51,18 @@ export function makeCollection<T extends SupportedReqTypes>(
* @param x The collection object to load * @param x The collection object to load
* @returns The proper new collection format * @returns The proper new collection format
*/ */
export function translateToNewRESTCollection( export function translateToNewRESTCollection(x: any): HoppCollection {
x: any if (x.v && x.v === CollectionSchemaVersion) return x
): HoppCollection<HoppRESTRequest> {
if (x.v && x.v === 1) return x
// Legacy // Legacy
const name = x.name ?? "Untitled" const name = x.name ?? "Untitled"
const folders = (x.folders ?? []).map(translateToNewRESTCollection) const folders = (x.folders ?? []).map(translateToNewRESTCollection)
const requests = (x.requests ?? []).map(translateToNewRequest) const requests = (x.requests ?? []).map(translateToNewRequest)
const auth = x.auth ?? "None" const auth = x.auth ?? { authType: "inherit", authActive: true }
const headers = x.headers ?? [] const headers = x.headers ?? []
const obj = makeCollection<HoppRESTRequest>({ const obj = makeCollection({
name, name,
folders, folders,
requests, requests,
@@ -72,10 +80,8 @@ export function translateToNewRESTCollection(
* @param x The collection object to load * @param x The collection object to load
* @returns The proper new collection format * @returns The proper new collection format
*/ */
export function translateToNewGQLCollection( export function translateToNewGQLCollection(x: any): HoppCollection {
x: any if (x.v && x.v === CollectionSchemaVersion) return x
): HoppCollection<HoppGQLRequest> {
if (x.v && x.v === GQL_REQ_SCHEMA_VERSION) return x
// Legacy // Legacy
const name = x.name ?? "Untitled" const name = x.name ?? "Untitled"
@@ -85,7 +91,7 @@ export function translateToNewGQLCollection(
const auth = x.auth ?? { authType: "inherit", authActive: true } const auth = x.auth ?? { authType: "inherit", authActive: true }
const headers = x.headers ?? [] const headers = x.headers ?? []
const obj = makeCollection<HoppGQLRequest>({ const obj = makeCollection({
name, name,
folders, folders,
requests, requests,

View File

@@ -0,0 +1,33 @@
import { defineVersion, entityReference } from "verzod"
import { z } from "zod"
import { HoppRESTRequest } from "../../rest"
import { HoppGQLRequest } from "../../graphql"
const baseCollectionSchema = z.object({
v: z.literal(1),
id: z.optional(z.string()), // For Firestore ID data
name: z.string(),
requests: z.array(
z.lazy(() =>
z.union([
entityReference(HoppRESTRequest),
entityReference(HoppGQLRequest),
])
)
),
})
type Collection = z.infer<typeof baseCollectionSchema> & {
folders: Collection[]
}
//@ts-expect-error ~ Recursive type
export const V1_SCHEMA: z.ZodType<Collection> = baseCollectionSchema.extend({
folders: z.lazy(() => z.array(V1_SCHEMA)),
})
export default defineVersion({
initial: true,
schema: V1_SCHEMA,
})

View File

@@ -0,0 +1,54 @@
import { defineVersion, entityReference } from "verzod"
import { z } from "zod"
import { HoppRESTRequest, HoppRESTAuth } from "../../rest"
import { HoppGQLRequest, HoppGQLAuth, GQLHeader } from "../../graphql"
import { V1_SCHEMA } from "./1"
import { HoppRESTHeaders } from "../../rest/v/1"
const baseCollectionSchema = z.object({
v: z.literal(2),
id: z.optional(z.string()), // For Firestore ID data
name: z.string(),
requests: z.array(
z.lazy(() =>
z.union([
entityReference(HoppRESTRequest),
entityReference(HoppGQLRequest),
])
)
),
auth: z.union([HoppRESTAuth, HoppGQLAuth]),
headers: z.array(z.union([HoppRESTHeaders, GQLHeader])),
})
type Collection = z.infer<typeof baseCollectionSchema> & {
folders: Collection[]
}
// @ts-expect-error ~ Recursive type
export const V2_SCHEMA: z.ZodType<Collection> = baseCollectionSchema.extend({
folders: z.lazy(() => z.array(V2_SCHEMA)),
})
export default defineVersion({
initial: false,
schema: V2_SCHEMA,
up(old: z.infer<typeof V1_SCHEMA>) {
// @ts-expect-error
const result: z.infer<typeof V2_SCHEMA> = {
...old,
v: 2,
auth: {
authActive: true,
authType: "inherit",
},
headers: [],
}
if (old.id) result.id = old.id
return result
},
})

View File

@@ -25,6 +25,7 @@ export {
HoppRESTAuthNone, HoppRESTAuthNone,
HoppRESTAuthOAuth2, HoppRESTAuthOAuth2,
HoppRESTReqBody, HoppRESTReqBody,
HoppRESTHeaders,
} from "./v/1" } from "./v/1"
const versionedObject = z.object({ const versionedObject = z.object({