UNPKG

lean4-code-actions

Version:

Refactorings and snippets for Lean 4

131 lines (118 loc) 6.33 kB
import { difference, isDefined } from 'remeda' import { ZodIssueCode } from 'zod' import { SuperRefinement } from 'zod/lib/types' import { getId, Id, WithId } from '../../../generic/models/Id' import { Mapper } from '../../Mapper' import { parallelMap } from '../../promise' import { ToString } from '../../string' export const oneToMany = <Database, Parent, Child, ParentId, ChildId>($parent: string, $child: string, getParents: Mapper<Database, Parent[]>, getChildren: Mapper<Database, Child[]>, getParentId: Mapper<Parent, ParentId>, getChildId: Mapper<Child, ChildId>, getChildParentId: Mapper<Child, ParentId>): SuperRefinement<Database> => (database, ctx) => { const parents = getParents(database) const children = getChildren(database) // const getParentById = (database: Database, parentId: ParentId) => parents.find(p => getParentId(p) === parentId) // const getChildren = todo() // const childrenWithoutParents = getChildrenWithoutParents({ iDatabase: { getChildren, getParentById } }) for (const child of children) { const parentId = getChildParentId(child) const parent = parents.find(p => getParentId(p) === parentId) if (!parent) { ctx.addIssue({ code: ZodIssueCode.custom, message: `${$child} #${getChildId(child)} is linked to ${$parent} #${parentId}, but ${$parent} #${parentId} does not exist`, params: { child, }, }) } } } export const oneToManyArray = <Database, Parent, Child, ParentId, ChildId>($parent: string, $child: string, getParents: Mapper<Database, Parent[]>, getChildren: Mapper<Database, Child[]>, getParentId: Mapper<Parent, ParentId>, getChildId: Mapper<Child, ChildId>, getChildParentIds: Mapper<Child, ParentId[]>): SuperRefinement<Database> => (database, ctx) => { const parents = getParents(database) const children = getChildren(database) for (const child of children) { const parentIdsAll = getChildParentIds(child) const parentIdsWithoutParent = parentIdsAll.filter(parentId => !parents.find(p => getParentId(p) === parentId)) if (parentIdsWithoutParent.length) { ctx.addIssue({ code: ZodIssueCode.custom, message: `${$child} #${getChildId(child)} is linked to ${$parent} ${parentIdsWithoutParent.map(parentId => `#${parentId}`)}, but these parents do not exist`, params: { child, parentIdsWithoutParent, }, }) } } } export const oneToManyWithId = <Database, Parent extends { id: Id }, Child extends { id: Id }>($parent: string, $child: string, getParents: Mapper<Database, Parent[]>, getChildren: Mapper<Database, Child[]>, getChildParentId: Mapper<Child, Id>): SuperRefinement<Database> => { return oneToMany($parent, $child, getParents, getChildren, getId, getId, getChildParentId) } export const oneToManyArrayWithId = <Database, Parent extends { id: Id }, Child extends { id: Id }>($parent: string, $child: string, getParents: Mapper<Database, Parent[]>, getChildren: Mapper<Database, Child[]>, getChildParentIds: Mapper<Child, Id[]>): SuperRefinement<Database> => { return oneToManyArray($parent, $child, getParents, getChildren, getId, getId, getChildParentIds) } export const oneToManySimple = <Val, Id>($source: string, $target: string, getSourceIds: (value: Val) => Id[], getTargetIds: (value: Val) => Id[]): SuperRefinement<Val> => (value, ctx) => { const diff = getOneToManyDiff(getSourceIds, getTargetIds)(value) if (diff.length) { ctx.addIssue({ code: ZodIssueCode.custom, message: 'Some values are present in target but not present in source', params: { diff, }, }) } } export const getOneToManyDiff = <Val, Id>(getSourceIds: (value: Val) => Id[], getTargetIds: (value: Val) => Id[]) => (value: Val) => { const sourceIds = getSourceIds(value) const targetIds = getTargetIds(value) return difference(targetIds, sourceIds) } export const getChildrenWithoutParents = <Database, Parent, Child, ParentId>( getChildren: (database: Database) => Promise<Child[]>, getParentById: (database: Database, parentId: ParentId) => Promise<Parent | undefined>, getChildParentId: (child: Child) => ParentId, ) => async (database: Database) => { const children = await getChildren(database) const results = await parallelMap(children, async (child) => { const parentId = getChildParentId(child) const parent = await getParentById(database, parentId) return parent ? undefined : child }) return results.filter(isDefined) } export interface OneToManyError<ParentId, ChildId> { $parent: string $child: string parentId: ParentId childId: ChildId } export const getOneToManyErrors = <Database, Parent, Child, ParentId, ChildId>( $parent: string, $child: string, getChildren: (database: Database) => Promise<Child[]>, getParentById: (database: Database, parentId: ParentId) => Promise<Parent | undefined>, getChildParentId: (child: Child) => ParentId, getChildId: (child: Child) => ChildId ) => async (database: Database): Promise<OneToManyError<ParentId, ChildId>[]> => { const children = await getChildrenWithoutParents(getChildren, getParentById, getChildParentId)(database) return children.map(child => ({ $parent, $child, parentId: getChildParentId(child), childId: getChildId(child), })) } export const getOneToManyErrorsWithId = <Database, Parent extends WithId, Child extends WithId>( $parent: string, $child: string, getParents: (database: Database) => Promise<Parent[]>, getChildren: (database: Database) => Promise<Child[]>, ) => async (database: Database) => { const parents = await getParents(database) const getParentById = async (database: Database, parentId: Id) => parents.find(parent => parent.id === parentId) return getOneToManyErrors($parent, $child, getChildren, getParentById, getId, getId) } const toStringOneToManyError = <ParentId, ChildId>(toStringChildId: ToString<ChildId>, toStringParentId: ToString<ParentId>) => ({ $child, $parent, childId, parentId }: OneToManyError<ParentId, ChildId>) => { const $parentId = toStringParentId(parentId) const $childId = toStringChildId(childId) return `${$child} #${$childId} is linked to ${$parent} #${$parentId}, but ${$parent} #${$parentId} does not exist` }