-
Notifications
You must be signed in to change notification settings - Fork 15
refactor(ensnode-sdk): public config data model #1642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dce8f5d
8beaaaa
60132e0
ca6b280
9843eaf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||
| import type { Unvalidated } from "../../../shared/types"; | ||||||
| import { deserializeEnsApiPublicConfig } from "../../config/deserialize"; | ||||||
| import type { EnsApiConfigResponse } from "./response"; | ||||||
| import type { SerializedEnsApiConfigResponse } from "./serialized-response"; | ||||||
|
|
@@ -6,9 +7,9 @@ import type { SerializedEnsApiConfigResponse } from "./serialized-response"; | |||||
| * Deserialize a {@link EnsApiConfigResponse} object. | ||||||
| */ | ||||||
| export function deserializeEnsApiConfigResponse( | ||||||
| serializedResponse: SerializedEnsApiConfigResponse, | ||||||
| maybeResponse: Unvalidated<SerializedEnsApiConfigResponse>, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Goal: "maybe response" sounds funny. It sounds like it's not sure if this was the response or not. But as I understand, we know it was the response, we just don't know if its a valid one or not yet.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it might sound funny, but also we convey information that the input is not guaranteed to be a response. Before, we'd have |
||||||
| ): EnsApiConfigResponse { | ||||||
| return deserializeEnsApiPublicConfig(serializedResponse); | ||||||
| return deserializeEnsApiPublicConfig(maybeResponse); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,49 @@ | ||
| import { prettifyError, ZodError } from "zod/v4"; | ||
| import { prettifyError } from "zod/v4"; | ||
|
|
||
| import { buildUnvalidatedEnsIndexerPublicConfig } from "../../ensindexer/config/deserialize"; | ||
| import type { Unvalidated } from "../../shared/types"; | ||
| import type { SerializedEnsApiPublicConfig } from "./serialized-types"; | ||
| import type { EnsApiPublicConfig } from "./types"; | ||
| import { makeEnsApiPublicConfigSchema } from "./zod-schemas"; | ||
| import { | ||
| makeEnsApiPublicConfigSchema, | ||
| makeSerializedEnsApiPublicConfigSchema, | ||
| } from "./zod-schemas"; | ||
|
|
||
| /** | ||
| * Deserialize a {@link EnsApiPublicConfig} object. | ||
| * Builds an unvalidated {@link EnsApiPublicConfig} object to be | ||
| * validated with {@link makeEnsApiPublicConfigSchema}. | ||
| * | ||
| * @param serializedPublicConfig - The serialized public config to build from. | ||
| * @return An unvalidated {@link EnsApiPublicConfig} object. | ||
| */ | ||
| function buildUnvalidatedEnsApiPublicConfig( | ||
| serializedPublicConfig: SerializedEnsApiPublicConfig, | ||
| ): Unvalidated<EnsApiPublicConfig> { | ||
| return { | ||
| ...serializedPublicConfig, | ||
| ensIndexerPublicConfig: buildUnvalidatedEnsIndexerPublicConfig( | ||
| serializedPublicConfig.ensIndexerPublicConfig, | ||
| ), | ||
| }; | ||
| } | ||
tk-o marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Deserialize value into {@link EnsApiPublicConfig} object. | ||
| */ | ||
| export function deserializeEnsApiPublicConfig( | ||
| maybeConfig: SerializedEnsApiPublicConfig, | ||
| maybePublicConfig: Unvalidated<SerializedEnsApiPublicConfig>, | ||
| valueLabel?: string, | ||
| ): EnsApiPublicConfig { | ||
| const schema = makeEnsApiPublicConfigSchema(valueLabel); | ||
| try { | ||
| return schema.parse(maybeConfig); | ||
| } catch (error) { | ||
| if (error instanceof ZodError) { | ||
| throw new Error(`Cannot deserialize EnsApiPublicConfig:\n${prettifyError(error)}\n`); | ||
| } | ||
| const parsed = makeSerializedEnsApiPublicConfigSchema(valueLabel) | ||
| .transform(buildUnvalidatedEnsApiPublicConfig) | ||
| .pipe(makeEnsApiPublicConfigSchema(valueLabel)) | ||
|
Comment on lines
+37
to
+39
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applying three-step deserialization protocol. |
||
| .safeParse(maybePublicConfig); | ||
|
|
||
| throw error; | ||
| if (parsed.error) { | ||
| throw new Error(`Cannot deserialize EnsApiPublicConfig:\n${prettifyError(parsed.error)}\n`); | ||
| } | ||
|
|
||
| return parsed.data; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,40 @@ | ||
| import { prettifyError } from "zod/v4"; | ||
|
|
||
| import type { Unvalidated } from "../../shared/types"; | ||
| import type { SerializedEnsIndexerPublicConfig } from "./serialized-types"; | ||
| import type { EnsIndexerPublicConfig } from "./types"; | ||
| import { makeEnsIndexerPublicConfigSchema } from "./zod-schemas"; | ||
| import { | ||
| makeEnsIndexerPublicConfigSchema, | ||
| makeSerializedEnsIndexerPublicConfigSchema, | ||
| } from "./zod-schemas"; | ||
|
|
||
| /** | ||
| * Deserialize object into a {@link EnsIndexerPublicConfig} object. | ||
| * Builds an unvalidated {@link EnsIndexerPublicConfig} object to be | ||
| * validated with {@link makeEnsIndexerPublicConfigSchema}. | ||
| * | ||
| * @param serializedPublicConfig - The serialized public config to build from. | ||
| * @return An unvalidated {@link EnsIndexerPublicConfig} object. | ||
| */ | ||
| export function buildUnvalidatedEnsIndexerPublicConfig( | ||
| serializedPublicConfig: SerializedEnsIndexerPublicConfig, | ||
| ): Unvalidated<EnsIndexerPublicConfig> { | ||
| return { | ||
| ...serializedPublicConfig, | ||
| indexedChainIds: new Set(serializedPublicConfig.indexedChainIds), | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Deserialize value into {@link EnsIndexerPublicConfig} object. | ||
| */ | ||
| export function deserializeEnsIndexerPublicConfig( | ||
| maybeConfig: SerializedEnsIndexerPublicConfig, | ||
| maybePublicConfig: Unvalidated<SerializedEnsIndexerPublicConfig>, | ||
| valueLabel?: string, | ||
| ): EnsIndexerPublicConfig { | ||
| const schema = makeEnsIndexerPublicConfigSchema(valueLabel); | ||
| const parsed = schema.safeParse(maybeConfig); | ||
| const parsed = makeSerializedEnsIndexerPublicConfigSchema(valueLabel) | ||
| .transform(buildUnvalidatedEnsIndexerPublicConfig) | ||
tk-o marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .pipe(makeEnsIndexerPublicConfigSchema(valueLabel)) | ||
|
Comment on lines
+34
to
+36
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applying the three-step deserialization protocol, where we use schema describing serialized data model, and then, we use validated serialized data model to build unvalidated business data model which gets validated in the last step by business-layer Zod schema. |
||
| .safeParse(maybePublicConfig); | ||
|
|
||
| if (parsed.error) { | ||
| throw new Error(`Cannot deserialize EnsIndexerPublicConfig:\n${prettifyError(parsed.error)}\n`); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,12 +25,18 @@ import { invariant_ensDbVersionIsSameAsEnsIndexerVersion } from "./validations"; | |
| * Makes a schema for parsing {@link IndexedChainIds}. | ||
| */ | ||
| export const makeIndexedChainIdsSchema = (valueLabel: string = "Indexed Chain IDs") => | ||
| z.set(makeChainIdSchema(valueLabel), { error: `${valueLabel} must be a set` }).min(1, { | ||
| error: `${valueLabel} must be a set with at least one chain ID.`, | ||
| }); | ||
|
|
||
| export const makeSerializedIndexedChainIdsSchema = (valueLabel: string = "Indexed Chain IDs") => | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
tk-o marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| z | ||
| .array(makeChainIdSchema(valueLabel), { | ||
| error: `${valueLabel} must be an array.`, | ||
| }) | ||
| .min(1, { error: `${valueLabel} list must include at least one element.` }) | ||
| .transform((v) => new Set(v)); | ||
| .min(1, { | ||
| error: `${valueLabel} must be an array with at least one chain ID.`, | ||
| }); | ||
|
|
||
| /** | ||
| * Makes a schema for parsing a list of strings that (for future-proofing) | ||
|
|
@@ -91,7 +97,7 @@ export const makeLabelSetIdSchema = (valueLabel: string) => { | |
| */ | ||
| export const makeLabelSetVersionSchema = (valueLabel: string) => { | ||
| return z.coerce | ||
| .number({ error: `${valueLabel} must be an integer.` }) | ||
| .number<number>({ error: `${valueLabel} must be an integer.` }) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Type convenience update — we know the only valid input is value representing a number, otherwise, the |
||
| .pipe(makeNonNegativeIntegerSchema(valueLabel)); | ||
| }; | ||
|
|
||
|
|
@@ -170,11 +176,13 @@ export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexe | |
| .object({ | ||
| labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`), | ||
| indexedChainIds: makeIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`), | ||
| isSubgraphCompatible: z.boolean({ error: `${valueLabel}.isSubgraphCompatible` }), | ||
| isSubgraphCompatible: z.boolean({ | ||
| error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`, | ||
| }), | ||
| namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`), | ||
| plugins: makePluginsListSchema(`${valueLabel}.plugins`), | ||
| databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`), | ||
| versionInfo: makeENSIndexerVersionInfoSchema(`${valueLabel}.versionInfo`), | ||
| versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`), | ||
| }) | ||
| /** | ||
| * Validations | ||
|
|
@@ -189,3 +197,18 @@ export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexe | |
| * @deprecated Use {@link makeEnsIndexerPublicConfigSchema} instead. | ||
| */ | ||
| export const makeENSIndexerPublicConfigSchema = makeEnsIndexerPublicConfigSchema; | ||
|
|
||
| export const makeSerializedEnsIndexerPublicConfigSchema = ( | ||
| valueLabel: string = "Serialized ENSIndexerPublicConfig", | ||
| ) => | ||
| z.object({ | ||
| labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`), | ||
| indexedChainIds: makeSerializedIndexedChainIdsSchema(`${valueLabel}.indexedChainIds`), | ||
| isSubgraphCompatible: z.boolean({ | ||
| error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`, | ||
| }), | ||
| namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`), | ||
| plugins: makePluginsListSchema(`${valueLabel}.plugins`), | ||
| databaseSchemaName: makeDatabaseSchemaNameSchema(`${valueLabel}.databaseSchemaName`), | ||
| versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`), | ||
| }); | ||
tk-o marked this conversation as resolved.
Show resolved
Hide resolved
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EnsApiConfigSchemais now purely business-layer Zod schema, so we don't need to serialize data to be able to use it.