packages/core/src/models/Query.ts (105 lines of code) (raw):

import { FormPath, isFn, each, FormPathPattern } from '@formily/shared' import { buildDataPath } from '../shared/internals' import { GeneralField, IGeneralFieldState, IQueryProps } from '../types' import { Form } from './Form' const output = ( field: GeneralField, taker: (field: GeneralField, address: FormPath) => any ) => { if (!field) return if (isFn(taker)) { return taker(field, field.address) } return field } const takeMatchPattern = (form: Form, pattern: FormPath) => { const identifier = pattern.toString() const indexIdentifier = form.indexes[identifier] const absoluteField = form.fields[identifier] const indexField = form.fields[indexIdentifier] if (absoluteField) { return identifier } else if (indexField) { return indexIdentifier } } export class Query { private pattern: FormPath private addresses: string[] = [] private form: Form constructor(props: IQueryProps) { this.pattern = FormPath.parse(props.pattern, props.base) this.form = props.form if (!this.pattern.isMatchPattern) { const matched = takeMatchPattern( this.form, this.pattern.haveRelativePattern ? buildDataPath(props.form.fields, this.pattern) : this.pattern ) if (matched) { this.addresses = [matched] } } else { each(this.form.fields, (field, address) => { if (!field) { delete this.form.fields[address] return } if (field.match(this.pattern)) { this.addresses.push(address) } }) } } take(): GeneralField | undefined take<Result>( getter: (field: GeneralField, address: FormPath) => Result ): Result take(taker?: any): any { return output(this.form.fields[this.addresses[0]], taker) } map(): GeneralField[] map<Result>( iterator?: (field: GeneralField, address: FormPath) => Result ): Result[] map(iterator?: any): any { return this.addresses.map((address) => output(this.form.fields[address], iterator) ) } forEach<Result>( iterator: (field: GeneralField, address: FormPath) => Result ) { return this.addresses.forEach((address) => output(this.form.fields[address], iterator) ) } reduce<Result>( reducer: (value: Result, field: GeneralField, address: FormPath) => Result, initial?: Result ): Result { return this.addresses.reduce( (value, address) => output(this.form.fields[address], (field, address) => reducer(value, field, address) ), initial ) } get<K extends keyof IGeneralFieldState>(key: K): IGeneralFieldState[K] { const results: any = this.take() if (results) { return results[key] } } getIn(pattern?: FormPathPattern) { return FormPath.getIn(this.take(), pattern) } value() { return this.get('value') } initialValue() { return this.get('initialValue') } }