Skip to content

Commit de5a465

Browse files
committed
fix #1216 - missing pattern-matched outputs
1 parent 3f932f6 commit de5a465

File tree

2 files changed

+302
-62
lines changed

2 files changed

+302
-62
lines changed

dash-renderer/src/actions/dependencies.js

Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
dissoc,
1111
equals,
1212
evolve,
13+
findIndex,
1314
flatten,
1415
forEachObjIndexed,
1516
includes,
@@ -785,9 +786,10 @@ export function computeGraphs(dependencies, dispatchError) {
785786
// Also collect MATCH keys in the output (all outputs must share these)
786787
// and ALL keys in the first output (need not be shared but we'll use
787788
// the first output for calculations) for later convenience.
788-
const {anyKeys, hasALL} = findWildcardKeys(outputs[0].id);
789+
const {anyKeys} = findWildcardKeys(outputs[0].id);
790+
const firstSingleOutput = findIndex(o => !isMultiValued(o.id), outputs);
789791
const finalDependency = mergeRight(
790-
{hasALL, anyKeys, outputs},
792+
{anyKeys, firstSingleOutput, outputs},
791793
dependency
792794
);
793795

@@ -822,21 +824,18 @@ export function computeGraphs(dependencies, dispatchError) {
822824
function findWildcardKeys(id) {
823825
const anyKeys = [];
824826
const allsmallerKeys = [];
825-
let hasALL = false;
826827
if (typeof id === 'object') {
827828
forEachObjIndexed((val, key) => {
828829
if (val === MATCH) {
829830
anyKeys.push(key);
830831
} else if (val === ALLSMALLER) {
831832
allsmallerKeys.push(key);
832-
} else if (val === ALL) {
833-
hasALL = true;
834833
}
835834
}, id);
836835
anyKeys.sort();
837836
allsmallerKeys.sort();
838837
}
839-
return {anyKeys, allsmallerKeys, hasALL};
838+
return {anyKeys, allsmallerKeys};
840839
}
841840

842841
/*
@@ -1048,31 +1047,6 @@ function getCallbackByOutput(graphs, paths, id, prop) {
10481047
return makeResolvedCallback(callback, resolve, anyVals);
10491048
}
10501049

1051-
/*
1052-
* If there are ALL keys we need to reduce a set of outputs resolved
1053-
* from an input to one item per combination of MATCH values.
1054-
* That will give one result per callback invocation.
1055-
*/
1056-
function reduceALLOuts(outs, anyKeys, hasALL) {
1057-
if (!hasALL) {
1058-
return outs;
1059-
}
1060-
if (!anyKeys.length) {
1061-
// If there's ALL but no MATCH, there's only one invocation
1062-
// of the callback, so just base it off the first output.
1063-
return [outs[0]];
1064-
}
1065-
const anySeen = {};
1066-
return outs.filter(i => {
1067-
const matchKeys = JSON.stringify(props(anyKeys, i.id));
1068-
if (!anySeen[matchKeys]) {
1069-
anySeen[matchKeys] = 1;
1070-
return true;
1071-
}
1072-
return false;
1073-
});
1074-
}
1075-
10761050
function addResolvedFromOutputs(callback, outPattern, outs, matches) {
10771051
const out0Keys = Object.keys(outPattern.id).sort();
10781052
const out0PatternVals = props(out0Keys, outPattern.id);
@@ -1088,6 +1062,51 @@ function addResolvedFromOutputs(callback, outPattern, outs, matches) {
10881062
});
10891063
}
10901064

1065+
function addAllResolvedFromOutputs(resolve, paths, matches) {
1066+
return callback => {
1067+
const {anyKeys, firstSingleOutput, outputs} = callback;
1068+
if (anyKeys.length) {
1069+
const singleOutPattern = outputs[firstSingleOutput];
1070+
if (singleOutPattern) {
1071+
addResolvedFromOutputs(
1072+
callback,
1073+
singleOutPattern,
1074+
resolve(paths)(singleOutPattern),
1075+
matches
1076+
);
1077+
} else {
1078+
/*
1079+
* If every output has ALL we need to reduce resolved set
1080+
* to one item per combination of MATCH values.
1081+
* That will give one result per callback invocation.
1082+
*/
1083+
const anySeen = {};
1084+
outputs.forEach(outPattern => {
1085+
const outSet = resolve(paths)(outPattern).filter(i => {
1086+
const matchKeys = JSON.stringify(props(anyKeys, i.id));
1087+
if (!anySeen[matchKeys]) {
1088+
anySeen[matchKeys] = 1;
1089+
return true;
1090+
}
1091+
return false;
1092+
});
1093+
addResolvedFromOutputs(
1094+
callback,
1095+
outPattern,
1096+
outSet,
1097+
matches
1098+
);
1099+
});
1100+
}
1101+
} else {
1102+
const cb = makeResolvedCallback(callback, resolve, '');
1103+
if (flatten(cb.getOutputs(paths)).length) {
1104+
matches.push(cb);
1105+
}
1106+
}
1107+
};
1108+
}
1109+
10911110
/*
10921111
* For a given id and prop find all callbacks it's an input of.
10931112
*
@@ -1111,21 +1130,9 @@ export function getCallbacksByInput(graphs, paths, id, prop, changeType) {
11111130
return [];
11121131
}
11131132

1114-
const baseResolve = resolveDeps();
1115-
callbacks.forEach(callback => {
1116-
const {anyKeys, hasALL} = callback;
1117-
if (anyKeys) {
1118-
const out0Pattern = callback.outputs[0];
1119-
const out0Set = reduceALLOuts(
1120-
baseResolve(paths)(out0Pattern),
1121-
anyKeys,
1122-
hasALL
1123-
);
1124-
addResolvedFromOutputs(callback, out0Pattern, out0Set, matches);
1125-
} else {
1126-
matches.push(makeResolvedCallback(callback, baseResolve, ''));
1127-
}
1128-
});
1133+
callbacks.forEach(
1134+
addAllResolvedFromOutputs(resolveDeps(), paths, matches)
1135+
);
11291136
} else {
11301137
// wildcard version
11311138
const keys = Object.keys(id).sort();
@@ -1137,23 +1144,13 @@ export function getCallbacksByInput(graphs, paths, id, prop, changeType) {
11371144
}
11381145
patterns.forEach(pattern => {
11391146
if (idMatch(keys, vals, pattern.values)) {
1140-
const resolve = resolveDeps(keys, vals, pattern.values);
1141-
pattern.callbacks.forEach(callback => {
1142-
const out0Pattern = callback.outputs[0];
1143-
const {anyKeys, hasALL} = callback;
1144-
const out0Set = reduceALLOuts(
1145-
resolve(paths)(out0Pattern),
1146-
anyKeys,
1147-
hasALL
1148-
);
1149-
1150-
addResolvedFromOutputs(
1151-
callback,
1152-
out0Pattern,
1153-
out0Set,
1147+
pattern.callbacks.forEach(
1148+
addAllResolvedFromOutputs(
1149+
resolveDeps(keys, vals, pattern.values),
1150+
paths,
11541151
matches
1155-
);
1156-
});
1152+
)
1153+
);
11571154
}
11581155
});
11591156
}

0 commit comments

Comments
 (0)