haystack-react
Version:
Project Haystack utilities for building React applications
92 lines (83 loc) • 3.42 kB
text/typescript
/*
* Copyright (c) 2021, J2 Innovations. All Rights Reserved
*/
import { HDict, HVal } from 'haystack-core'
import { second } from 'haystack-units'
import {
HaystackPointWriteOptions,
PointWriteFunc,
useHaystackPoint,
} from './useHaystackPoint'
import { useHaystackRecordTag } from './useHaystackRecordTag'
import {
isResolvableDict,
isResolvablePoint,
isResolvableTag,
Resolvable,
ResolvableDict,
} from './Resolvable'
/**
* A hook to use a value from an haystack-server as react state.
*
* This hook should be used when input flexibility is required.
* It is meant to abstract how data is actually retrieved/polled/written, enabling at the same time a data driven approach.
*
* It takes a ResolvableDict that contains the record data and a meta tag that indicates how to interact with that record to poll and write an HVal.
* @see ResolvableDict for the options available.
*
* IMPORTANT: this hook requires a ClientContext to work. @see https://github.com/j2inn/haystack-nclient
*
* @example <caption>Here’s a usage example:</caption>
* const [point] = useReadByFilter('point and temp and zone and sp').grid // One-shot reading the first point that matches the filter
*
* //Adding meta data to the dict (this could be done server side)
* const resolvableDict1 = point?.newCopy().set('meta', {resolveType: 'point'}) as Resolvable<HNum>
* const resolvableDict2 = point?.newCopy().set('meta', {resolveType: 'tag', readTag: 'precision'}) as Resolvable<HNum>
*
* // The actual state used depends on the metadata in the dict:
* const [pointValue, setPointValue, point] = useResolveHaystackValue<HNum>(resolvableDict1)
* const [pointPrecision, setPointPrecision, point] = useResolveHaystackValue<HNum>(resolvableDict2)
*
* @param resolvable Resolvable containing a record and metadata on how to resolve the value or the value itself.
* @param pollRate poll rate for the value subscription. Expressed in seconds. Default is 5.
* @returns a resolved value and a function to update it on the server, if the value is not resolved it is passed through.
*/
export function useResolveHaystackValue<Value extends HVal>(
resolvable?: Resolvable<Value>
): [Optional<Value>, PointWriteFunc<Value> | undefined, Optional<HDict>] {
const pollTime = resolvePollTime(resolvable)
const isPoint = isResolvablePoint(resolvable)
const isTag = isResolvableTag(resolvable)
const [pointValue, writePoint, point] = useHaystackPoint<Value>(
isPoint ? resolvable : undefined,
pollTime,
isPoint ? resolveDefaultPointWriteOpt(resolvable) : undefined
)
const [tag, writeTag, record] = useHaystackRecordTag<Value>(
isTag ? resolvable : undefined,
isTag ? resolvable.meta.readTag.value : undefined,
pollTime
)
return isPoint
? [pointValue, writePoint, point]
: isTag
? [tag, writeTag, record]
: [resolvable, undefined, undefined]
}
const resolveDefaultPointWriteOpt: (
resolvableDict: ResolvableDict
) => HaystackPointWriteOptions = (resolvableDict) => {
return {
who: resolvableDict.meta?.writeWho?.value,
duration: resolvableDict.meta?.writeDuration,
level: resolvableDict.meta?.writeLevel?.value,
}
}
const resolvePollTime: (resolvable?: Resolvable<HVal>) => number | undefined = (
resolvable
) => {
return isResolvableDict(resolvable)
? resolvable?.meta?.subscriptionPollTime?.convertTo(second).value
: undefined
}
type Optional<Value> = Value | undefined | null