private void ScanEverythingBelongingToNodes(NodeMappings nodeMappings) { using (NodeCursor nodeCursor = _cursors.allocateNodeCursor(), PropertyCursor propertyCursor = _cursors.allocatePropertyCursor()) { _dataRead.allNodesScan(nodeCursor); while (nodeCursor.Next()) { // each node SortedLabels labels = SortedLabels.From(nodeCursor.Labels()); nodeCursor.Properties(propertyCursor); MutableIntSet propertyIds = IntSets.mutable.empty(); while (propertyCursor.Next()) { Value currentValue = propertyCursor.PropertyValue(); int propertyKeyId = propertyCursor.PropertyKey(); Pair <SortedLabels, int> key = Pair.of(labels, propertyKeyId); UpdateValueTypeInMapping(currentValue, key, nodeMappings.LabelSetANDNodePropertyKeyIdToValueType); propertyIds.add(propertyKeyId); } propertyCursor.Close(); MutableIntSet oldPropertyKeySet = nodeMappings.LabelSetToPropertyKeys.getOrDefault(labels, _emptyPropertyIdSet); // find out which old properties we did not visited and mark them as nullable if (oldPropertyKeySet == _emptyPropertyIdSet) { if (propertyIds.size() == 0) { // Even if we find property key on other nodes with those labels, set all of them nullable nodeMappings.NullableLabelSets.Add(labels); } propertyIds.addAll(oldPropertyKeySet); } else { MutableIntSet currentPropertyIdsHelperSet = new IntHashSet(propertyIds.size()); currentPropertyIdsHelperSet.addAll(propertyIds); propertyIds.removeAll(oldPropertyKeySet); // only the brand new ones in propIds now oldPropertyKeySet.removeAll(currentPropertyIdsHelperSet); // only the old ones that are not on the new node propertyIds.addAll(oldPropertyKeySet); propertyIds.forEach(id => { Pair <SortedLabels, int> key = Pair.of(labels, id); nodeMappings.LabelSetANDNodePropertyKeyIdToValueType[key].setNullable(); }); propertyIds.addAll(currentPropertyIdsHelperSet); } nodeMappings.LabelSetToPropertyKeys[labels] = propertyIds; } nodeCursor.Close(); } }
// If we would have this schema information in the count store (or somewhere), this could be super fast public virtual Stream <NodePropertySchemaInfoResult> CalculateTabularResultStreamForNodes() { NodeMappings nodeMappings = InitializeMappingsForNodes(); ScanEverythingBelongingToNodes(nodeMappings); // go through all labels to get actual names AddNamesToCollection(_tokenRead.labelsGetAllTokens(), nodeMappings.LabelIdToLabelName); return(ProduceResultsForNodes(nodeMappings).stream()); }
private IList <NodePropertySchemaInfoResult> ProduceResultsForNodes(NodeMappings nodeMappings) { IList <NodePropertySchemaInfoResult> results = new List <NodePropertySchemaInfoResult>(); foreach (SortedLabels labelSet in nodeMappings.LabelSetToPropertyKeys.Keys) { // lookup label names and produce list of names and produce String out of them IList <string> labelNames = new List <string>(); for (int i = 0; i < labelSet.NumberOfLabels(); i++) { string name = nodeMappings.LabelIdToLabelName[labelSet.Label(i)]; labelNames.Add(name); } labelNames.Sort(); // this is optional but waaaaay nicer StringBuilder labelsConcatenator = new StringBuilder(); foreach (string item in labelNames) { labelsConcatenator.Append(":`").Append(item).Append("`"); } string labels = labelsConcatenator.ToString(); // lookup property value types MutableIntSet propertyIds = nodeMappings.LabelSetToPropertyKeys[labelSet]; if (propertyIds.size() == 0) { results.Add(new NodePropertySchemaInfoResult(labels, labelNames, null, null, false)); } else { propertyIds.forEach(propId => { string propName = _propertyIdToPropertyNameMapping[propId]; ValueTypeListHelper valueTypeListHelper = nodeMappings.LabelSetANDNodePropertyKeyIdToValueType[Pair.of(labelSet, propId)]; if (nodeMappings.NullableLabelSets.Contains(labelSet)) { results.Add(new NodePropertySchemaInfoResult(labels, labelNames, propName, valueTypeListHelper.CypherTypesList, false)); } else { results.Add(new NodePropertySchemaInfoResult(labels, labelNames, propName, valueTypeListHelper.CypherTypesList, valueTypeListHelper.Mandatory)); } }); } } return(results); }