Skip to content

Commit

Permalink
Auto incremental key: use Math.max to calculate next value; do not ke…
Browse files Browse the repository at this point in the history
…ep default values when converting node def; (#3568)

* autoincremental key using max (WIP)

* use max to calculate autoincremental key

* do not copy default values in convert if auto incremental key

* re-create default values when changing node def name

* keep auto incremental key always visible if set

---------

Co-authored-by: Stefano Ricci <[email protected]>
  • Loading branch information
SteRiccio and SteRiccio authored Sep 12, 2024
1 parent 0fee070 commit 8e54509
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 33 deletions.
3 changes: 2 additions & 1 deletion core/stringUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export const nullToEmpty = (value) => (value === null ? '' : value)
export const appendIfMissing = (suffix) => (text) => (text.endsWith(suffix) ? text : `${text}${suffix}`)
export const prependIfMissing = (prefix) => (text) => (text.startsWith(prefix) ? text : `${prefix}${text}`)
export const removePrefix = (prefix) => (text) => (text.startsWith(prefix) ? text.substring(prefix.length) : text)
export const removeSuffix = (suffix) => (text) => text.substring(0, text.length - suffix.length)
export const removeSuffix = (suffix) => (text) =>
text.endsWith(suffix) ? text.substring(0, text.length - suffix.length) : text

export const quote = (text) => (isBlank(text) ? '' : `'${text}'`)

Expand Down
38 changes: 22 additions & 16 deletions core/survey/nodeDef.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,16 @@ export const visibleFieldsDefaultByType = {
[nodeDefType.taxon]: [valuePropsTaxon.code, valuePropsTaxon.scientificName, valuePropsTaxon.vernacularName],
}

export const autoIncrementalKeyExpression = 'index($context) + 1'
export const createAutoIncrementalKeyDefaultValues = ({ nodeDef, nodeDefParent }) => {
const nodeDefName = getName(nodeDef)
const nodeDefParentName = getName(nodeDefParent)
return [
NodeDefExpression.createExpression({ expression: '1', applyIf: 'index($context) == 0' }),
NodeDefExpression.createExpression({
expression: `Math.max(parent($context).${nodeDefParentName}.${nodeDefName}) + 1`,
}),
]
}

// ==== READ

Expand Down Expand Up @@ -506,7 +515,10 @@ export const convertToType =
({ toType }) =>
(nodeDef) => {
const propsUpdated = R.pick(commonAttributePropsKeys)(getProps(nodeDef))
const propsAdvancedUpdated = R.pick(commonAttributePropsAdvancedKeys)(getPropsAdvanced(nodeDef))
const propsAdvancedToKeep = isAutoIncrementalKey(nodeDef)
? commonAttributePropsAdvancedKeys.filter((prop) => prop !== keysPropsAdvanced.defaultValues)
: commonAttributePropsAdvancedKeys
const propsAdvancedUpdated = R.pick(propsAdvancedToKeep)(getPropsAdvanced(nodeDef))

const layout = getLayout(nodeDef)
const layoutUpdated = Object.entries(layout).reduce((acc, [cycleKey, cycleLayout]) => {
Expand Down Expand Up @@ -662,23 +674,17 @@ export const clearNotApplicableProps = (cycle) => (nodeDef) => {
export const canHaveMobileProps = (cycle) => (nodeDef) =>
canBeHiddenInMobile(nodeDef) || canIncludeInMultipleEntitySummary(cycle)(nodeDef)

const isDefaultValueAutoIncrementExpression = (defaultValue) => {
const expression = NodeDefExpression.getExpression(defaultValue)
return (
(expression === autoIncrementalKeyExpression ||
StringUtils.removeSuffix('\n')(expression).replaceAll(' ', '') ===
autoIncrementalKeyExpression.replaceAll(' ', '')) &&
Objects.isEmpty(NodeDefExpression.getApplyIf(defaultValue))
)
}

export const canHaveAutoIncrementalKey = (nodeDef) => {
export const canHaveAutoIncrementalKey = ({ nodeDef, nodeDefParent }) => {
if (!isKey(nodeDef) || !isInteger(nodeDef)) return false

const defaultValues = getDefaultValues(nodeDef)
if (defaultValues.length === 0) return true
if (defaultValues.length > 1) return false

const defaultValue = defaultValues[0]
return NodeDefExpression.isEmpty(defaultValue) || isDefaultValueAutoIncrementExpression(defaultValue)
const autoIncrementalDefaultValues = createAutoIncrementalKeyDefaultValues({ nodeDef, nodeDefParent })
return (
defaultValues.length === autoIncrementalDefaultValues.length &&
autoIncrementalDefaultValues.every((defaultValue, index) =>
NodeDefExpression.isSimilarTo(defaultValue)(defaultValues[index])
)
)
}
10 changes: 10 additions & 0 deletions core/survey/nodeDefExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ export const isPlaceholder = R.propEq(keys.placeholder, true)
export const isEmpty = (expression = {}) =>
StringUtils.isBlank(getExpression(expression)) && StringUtils.isBlank(getApplyIf(expression))

export const isSimilarTo = (expressionA) => (expressionB) => {
if (isEmpty(expressionA) && isEmpty(expressionB)) return true
if (isEmpty(expressionA) || isEmpty(expressionB)) return false
const prepareExpr = (expr) => StringUtils.removeSuffix('\n')(expr.replaceAll(' ', ''))
return (
prepareExpr(getExpression(expressionA)) === prepareExpr(getExpression(expressionB)) &&
prepareExpr(getApplyIf(expressionA)) === prepareExpr(getApplyIf(expressionB))
)
}

// ====== UPDATE

const assocProp = (propName, value) => R.pipe(R.assoc(propName, value), R.dissoc(keys.placeholder))
Expand Down
1 change: 0 additions & 1 deletion webapp/components/survey/NodeDefDetails/AdvancedProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ const AdvancedProps = (props) => {
</FormItem>

<NodeDefExpressionsProp
applyIf={!autoIncrementalKey}
qualifier={TestId.nodeDefDetails.defaultValues}
state={state}
Actions={Actions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ export const useBasicProps = (props) => {
const nodeDefParentLabel = NodeDef.getLabel(nodeDefParent, lang)
const ancestorMultipleEntityDef = Survey.getNodeDefAncestorMultipleEntity(nodeDef)(survey)
const canHaveAutoIncrementalKey =
NodeDef.canHaveAutoIncrementalKey(nodeDef) &&
ancestorMultipleEntityDef &&
!NodeDef.isRoot(ancestorMultipleEntityDef)
NodeDef.isAutoIncrementalKey(nodeDef) ||
(NodeDef.canHaveAutoIncrementalKey({ nodeDef, nodeDefParent }) &&
ancestorMultipleEntityDef &&
!NodeDef.isRoot(ancestorMultipleEntityDef))

return {
nodeDef,
Expand Down
23 changes: 11 additions & 12 deletions webapp/components/survey/NodeDefDetails/store/actions/useSetProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import * as A from '@core/arena'
import * as StringUtils from '@core/stringUtils'
import * as Survey from '@core/survey/survey'
import * as NodeDef from '@core/survey/nodeDef'
import * as NodeDefExpression from '@core/survey/nodeDefExpression'
import * as NodeDefLayout from '@core/survey/nodeDefLayout'
import * as NodeDefValidations from '@core/survey/nodeDefValidations'

Expand Down Expand Up @@ -75,24 +74,24 @@ const _generateLabelFromName = (name) => {
return parts.join(' ')
}

const _onUpdateName = ({ nodeDef, nodeDefPrev, value: name, lang }) => {
const _onUpdateName = ({ survey, nodeDef, nodeDefPrev, value: name, lang }) => {
let nodeDefUpdated = nodeDef
const prevNameCapitalized = _generateLabelFromName(NodeDef.getName(nodeDefPrev))
const prevLabel = NodeDef.getLabel(nodeDef, lang, NodeDef.NodeDefLabelTypes.label, false)
if (StringUtils.isBlank(prevLabel) || prevNameCapitalized === prevLabel) {
const nameCapitalized = _generateLabelFromName(name)
return NodeDef.assocLabel({ label: nameCapitalized, lang })(nodeDef)
nodeDefUpdated = NodeDef.assocLabel({ label: nameCapitalized, lang })(nodeDefUpdated)
}
return nodeDef
if (NodeDef.isAutoIncrementalKey(nodeDefUpdated)) {
// re-generate default values; they depend on current node def name
nodeDefUpdated = _onUpdateAutoIncrementalKey({ survey, nodeDef, value: true })
}
return nodeDefUpdated
}

const _onUpdateAutoIncrementalKey = ({ nodeDef, value }) => {
const defaultValues = []
if (value) {
const defaultValueExpression = NodeDefExpression.createExpression({
expression: NodeDef.autoIncrementalKeyExpression,
})
defaultValues.push(defaultValueExpression)
}
const _onUpdateAutoIncrementalKey = ({ survey, nodeDef, value }) => {
const nodeDefParent = Survey.getNodeDefParent(nodeDef)(survey)
const defaultValues = value ? NodeDef.createAutoIncrementalKeyDefaultValues({ nodeDef, nodeDefParent }) : []
return A.pipe(
NodeDef.assocDefaultValues(defaultValues),
NodeDef.assocDefaultValueEvaluatedOnlyOneTime(value)
Expand Down

0 comments on commit 8e54509

Please sign in to comment.