| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import * as z from 'zod'
- import { WRAPPER_HANDLERS, WRAPPERS } from './Wrappers.constants'
- import type { Table, WrapperMeta } from './Wrappers.types'
- import { FDW, FDWTable } from '@/data/fdw/fdws-query'
- const tableSchema = z
- .object({
- index: z.number(),
- columns: z.array(z.object({ name: z.string(), type: z.string() })),
- is_new_schema: z.boolean(),
- schema: z.string(),
- schema_name: z.string(),
- table_name: z.string(),
- object: z.any().optional(),
- })
- .passthrough() // passthrough is needed for table options
- export const getWrapperCreationFormSchema = (wrapperMeta: WrapperMeta) => {
- let wrapperSchema = {
- // Common validation for all wrappers
- wrapper_name: z.string().min(1, 'Please provide a name for your wrapper'),
- } as Record<string, any>
- // Add wrapper specific options
- wrapperMeta.server.options.forEach((option) => {
- if (option.required) {
- wrapperSchema[option.name] = z.string().min(1, 'Required')
- return
- }
- wrapperSchema[option.name] = z.string().optional()
- })
- return z.discriminatedUnion('mode', [
- z
- .object({
- mode: z.literal('tables'),
- tables: z
- .array(tableSchema, { required_error: 'Please provide at least one table' })
- .min(1, 'Please provide at least one table'),
- })
- .merge(z.object(wrapperSchema)),
- z
- .object({
- mode: z.literal('schema'),
- source_schema: z.string().min(1, 'Please provide a source schema'),
- target_schema: z.string().min(1, 'Please provide an unique target schema'),
- })
- .merge(z.object(wrapperSchema)),
- ])
- }
- export const getEditionFormSchema = (wrapperMeta: WrapperMeta) => {
- let wrapperSchema = {
- // Common validation for all wrappers
- wrapper_name: z.string().min(1, 'Please provide a name for your wrapper'),
- tables: z
- .array(tableSchema, { required_error: 'Please provide at least one table' })
- .min(1, 'Please provide at least one table'),
- } as Record<string, any>
- // Add wrapper specific options
- wrapperMeta.server.options.forEach((option) => {
- if (option.required) {
- wrapperSchema[option.name] = z.string().min(1, 'Required')
- return
- }
- wrapperSchema[option.name] = z.string().optional()
- })
- return z.object(wrapperSchema)
- }
- export const getTableFormSchema = (table: Table) => {
- let tableSchema = {
- table_name: z.string().min(1, 'Required'),
- schema: z.string().min(1, 'Required'),
- schema_name: z.string().optional(),
- columns: z.array(
- z.object({
- name: z.string().min(1, 'Required'),
- type: z.string().min(1, 'Required'),
- })
- ),
- } as Record<string, any>
- table.options.forEach((option) => {
- if (option.required) {
- tableSchema[option.name] = z.string().min(1, 'Required')
- return
- }
- tableSchema[option.name] = z.string().optional()
- })
- return (
- z
- .object(tableSchema)
- // passthrough is needed for table options
- .passthrough()
- .superRefine((values, ctx) => {
- if (values.schema === 'custom' && !values.schema_name) {
- ctx.addIssue({
- code: 'custom',
- path: ['schema_name'],
- message: 'Required',
- })
- }
- })
- )
- }
- export const makeValidateRequired = (options: { name: string; required: boolean }[]) => {
- const requiredOptionsSet = new Set(
- options.filter((option) => option.required).map((option) => option.name)
- )
- const requiredArrayOptionsSet = new Set(
- Array.from(requiredOptionsSet).filter((option) => option.includes('.'))
- )
- const requiredArrayOptions = Array.from(requiredArrayOptionsSet)
- return (values: Record<string, any>) => {
- const errors = Object.fromEntries(
- Object.entries(values)
- .flatMap(([key, value]) =>
- Array.isArray(value)
- ? [[key, value], ...value.map((v, i) => [`${key}.${i}`, v])]
- : [[key, value]]
- )
- .filter(([_key, value]) => {
- const [key, idx] = _key.split('.')
- if (
- idx !== undefined &&
- requiredOptionsSet.has(key) &&
- Object.keys(value).some((subKey) => requiredArrayOptionsSet.has(`${key}.${subKey}`))
- ) {
- const arrayOption = requiredArrayOptions.find((option) => option.startsWith(`${key}.`))
- if (arrayOption) {
- const subKey = arrayOption.split('.')[1]
- return !value[subKey]
- }
- return false
- }
- return requiredOptionsSet.has(key) && (Array.isArray(value) ? value.length < 1 : !value)
- })
- .map(([key]) => {
- if (key === 'table_name') return [key, 'Please provide a name for your table']
- else if (key === 'columns') return [key, 'Please select at least one column']
- else return [key, 'This field is required']
- })
- )
- return errors
- }
- }
- export const NewTable = {} as FormattedWrapperTable
- export interface FormattedWrapperTable {
- index: number
- columns: { name: string }[]
- is_new_schema: boolean
- schema: string
- schema_name: string
- table_name: string
- object?: string // From options object for Firebase/Stripe
- [key: string]: any // For other dynamic options from table.options
- }
- export const formatWrapperTables = (
- wrapper: { handler: string; tables?: FDWTable[] },
- wrapperMeta?: WrapperMeta
- ): FormattedWrapperTable[] => {
- const tables = wrapper?.tables ?? []
- return tables.map((table) => {
- let index: number = 0
- const options = Object.fromEntries(table.options.map((option: string) => option.split('=')))
- switch (wrapper.handler) {
- case WRAPPER_HANDLERS.STRIPE:
- index =
- wrapperMeta?.tables.findIndex(
- (x) => x.options.find((x) => x.name === 'object')?.defaultValue === options.object
- ) ?? 0
- break
- case WRAPPER_HANDLERS.FIREBASE:
- if (options.object === 'auth/users') {
- index =
- wrapperMeta?.tables.findIndex((x) =>
- x.options.find((x) => x.defaultValue === 'auth/users')
- ) ?? 0
- } else {
- index = wrapperMeta?.tables.findIndex((x) => x.label === 'Firestore Collection') ?? 0
- }
- break
- case WRAPPER_HANDLERS.S3:
- case WRAPPER_HANDLERS.AIRTABLE:
- case WRAPPER_HANDLERS.LOGFLARE:
- case WRAPPER_HANDLERS.BIG_QUERY:
- case WRAPPER_HANDLERS.CLICK_HOUSE:
- break
- }
- return {
- ...options,
- index,
- id: table.id,
- columns: table.columns ?? [],
- is_new_schema: false,
- schema: table.schema,
- schema_name: table.schema,
- table_name: table.name,
- }
- })
- }
- export const convertKVStringArrayToJson = (values: string[]): Record<string, string> => {
- return Object.fromEntries(values.map((value) => value.split('=')))
- }
- export function wrapperMetaComparator(
- wrapperMeta: Pick<WrapperMeta, 'handlerName' | 'server'>,
- wrapper: FDW | undefined
- ) {
- if (wrapperMeta.handlerName === 'wasm_fdw_handler') {
- const serverOptions = convertKVStringArrayToJson(wrapper?.server_options ?? [])
- return (
- wrapperMeta.server.options.find((option) => option.name === 'fdw_package_name')
- ?.defaultValue === serverOptions['fdw_package_name']
- )
- }
- return wrapperMeta.handlerName === wrapper?.handler
- }
- export function getWrapperMetaForWrapper(wrapper: FDW | undefined) {
- return WRAPPERS.find((w) => wrapperMetaComparator(w, wrapper))
- }
|