Skip to content
This repository has been archived by the owner on Jun 22, 2023. It is now read-only.

Commit

Permalink
Merge branch 'staging' into snyk-upgrade-ef4f00cb9889a6d9220051854613…
Browse files Browse the repository at this point in the history
…ce11
  • Loading branch information
ChristiaanScheermeijer authored Mar 22, 2021
2 parents 3483048 + 9560ec1 commit 7ea57cf
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 79 deletions.
24 changes: 14 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
"express": "4.17.1",
"graphql": "^15.5.0",
"graphql-auth-directives": "^2.2.2",
"graphql-tag": "^2.11.0",
"graphql-tag": "^2.12.1",
"graphql-tools": "^4.0.8",
"js-green-licenses": "^3.0.0",
"jsonwebtoken": "^8.5.1",
"micromatch": "^4.0.2",
"neo4j-driver": "4.2.1",
"neo4j-driver": "4.2.2",
"neo4j-graphql-js": "^2.19.2",
"validator": "12.2.0",
"walk-sync": "2.0.2"
"walk-sync": "2.2.0"
},
"devDependencies": {
"@babel/cli": "^7.13.10",
Expand Down
107 changes: 56 additions & 51 deletions src/commands/RequestControlActionCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class RequestControlActionCommand {
* @returns {Promise<StatementResult | never>}
*/
get create () {
const requestInput = this._retrieveRequestInput()
const requestInput = this.params.controlAction
const entryPointQuery = this._generateTemplateQuery(requestInput)
info(entryPointQuery)
return this.session.run(entryPointQuery)
Expand All @@ -46,37 +46,20 @@ class RequestControlActionCommand {
}

/**
* @returns {Object}
* Get aliases for the given property identifier
* @param template
* @param propertyIdentifier
* @return {{templatePropertyAlias: string, nodeAlias: string, propertyAlias: string}}
* @private
*/
_retrieveRequestInput () {
const requestInput = this.params.controlAction
if (typeof requestInput !== 'object' || typeof requestInput.entryPointIdentifier !== 'string' || typeof requestInput.potentialActionIdentifier !== 'string') {
throw new UserInputError('Request Input error: either empty or missing `entryPointIdentifier` or `potentialActionIdentifier` parameter')
}

let nodeCounter = 1
// hydrate propertyObject aliases
if (Array.isArray(requestInput.propertyObject)) {
requestInput.propertyObject = requestInput.propertyObject.map(node => {
node.alias = `node_${nodeCounter}`
node.propertyValueAlias = `propertyValue_${nodeCounter}`
nodeCounter++
_getAliasesForProperty (template, propertyIdentifier) {
const count = template.potentialAction.object.findIndex(({ identifier }) => identifier === propertyIdentifier) + 1

return node
})
return {
templatePropertyAlias: `templateProperty_${count}`,
propertyAlias: `property_${count}`,
nodeAlias: `node_${count}`
}
// hydrate propertyValueObject aliases
if (Array.isArray(requestInput.propertyValueObject)) {
requestInput.propertyValueObject = requestInput.propertyValueObject.map(node => {
node.propertyValueAlias = `propertyValue_${nodeCounter}`
nodeCounter++

return node
})
}

return requestInput
}

/**
Expand All @@ -103,22 +86,17 @@ class RequestControlActionCommand {
* @private
*/
_generateCreateQuery (template, requestInput) {
const nodeAliasesClause = (Array.isArray(requestInput.propertyObject) && requestInput.propertyObject.length > 0)
? `, ${requestInput.propertyObject.map(object => {
return `\`${object.alias}\``
}).join(', ')}`
: ''
const propertySelections = this._generateMatchPropertyNodes(requestInput)
const { selections, aliases } = this._generatePropertyMatchClauses(requestInput, template)

return [
`MATCH (\`entryPoint\`:\`EntryPoint\` {\`identifier\`:"${requestInput.entryPointIdentifier}"})${this.queryHelper.generateRelationClause('EntryPoint', 'potentialAction')}(\`potentialControlAction\`:\`ControlAction\` {\`identifier\`:"${requestInput.potentialActionIdentifier}"})`,
propertySelections ? `, ${propertySelections}` : '',
`WITH \`entryPoint\`, \`potentialControlAction\`${nodeAliasesClause}`,
selections ? `, ${selections}` : '',
`WITH \`entryPoint\`, \`potentialControlAction\`${aliases ? `, ${aliases}` : ''}`,
'LIMIT 1',
`CREATE (\`entryPoint\`)${this.queryHelper.generateRelationClause('ControlAction', 'target', null, true)}(\`controlAction\`:\`ControlAction\`:\`ActionInterface\`:\`ProvenanceActivityInterface\`:\`ProvenanceEntityInterface\`:\`ThingInterface\` {${this._generateControlActionPropertyClause(template.potentialAction)}})${this.queryHelper.generateRelationClause('ControlAction', 'wasDerivedFrom')}(\`potentialControlAction\`)`,
`WITH \`entryPoint\`, \`potentialControlAction\`, \`controlAction\`${nodeAliasesClause}`,
`WITH \`entryPoint\`, \`potentialControlAction\`, \`controlAction\`${aliases ? `, ${aliases}` : ''}`,
this._generateCreatePropertyValuesClause(template, requestInput),
this._generateNodeValueRelationsClause(requestInput.propertyObject),
this._generateNodeValueRelationsClause(requestInput.propertyObject, template),
this._generateReturnClause(template, requestInput)
].filter(line => typeof line === 'string' && line.length > 0).join(' ')
}
Expand Down Expand Up @@ -256,17 +234,31 @@ class RequestControlActionCommand {

/**
* @param requestInput
* @returns {string}
* @param template
* @returns {Object}
* @private
*/
_generateMatchPropertyNodes (requestInput) {
if (!Array.isArray(requestInput.propertyObject) || !requestInput.propertyObject.length > 0) {
return ''
}
_generatePropertyMatchClauses (requestInput, template) {
// create match clauses for all template property
const propertyMatchClauses = template.potentialAction.object.map(object => {
const { templatePropertyAlias } = this._getAliasesForProperty(template, object.identifier)

return [templatePropertyAlias, `(\`${templatePropertyAlias}\`:\`${object._schemaType}\` {\`identifier\`:"${object.identifier}"})`]
})

// create match clauses for each Property node
const nodeMatchClauses = (requestInput.propertyObject || []).map(node => {
const { nodeAlias } = this._getAliasesForProperty(template, node.potentialActionPropertyIdentifier)

return [nodeAlias, `(\`${nodeAlias}\`:\`${node.nodeType}\` {\`identifier\`:"${node.nodeIdentifier}"})`]
})

const allPairs = [...propertyMatchClauses, ...nodeMatchClauses]

return requestInput.propertyObject.map(node => {
return `(\`${node.alias}\`:\`${node.nodeType}\` {\`identifier\`:"${node.nodeIdentifier}"})`
}).join(', ')
return {
selections: allPairs.map(([, query]) => query).join(', '),
aliases: allPairs.map(([alias]) => `\`${alias}\``).join(', ')
}
}

/**
Expand Down Expand Up @@ -294,20 +286,31 @@ class RequestControlActionCommand {
if (!matchingRequestProperty) {
throw new UserInputError('Required node property is missing from input: ' + templateProperty.identifier + ' ' + templateProperty.title)
}

const { templatePropertyAlias, propertyAlias } = this._getAliasesForProperty(template, templateProperty.identifier)

const wasDerivedFromRelationClause = this.queryHelper.generateRelationClause('PropertyValue', 'wasDerivedFrom')
const wasDerivedFromClause = `${wasDerivedFromRelationClause}(\`${templatePropertyAlias}\`)`

// compose PropertyValue clause
return `(\`controlAction\`)${objectRelationClause}(\`${matchingRequestProperty.propertyValueAlias}\`:\`PropertyValue\`:\`ThingInterface\` {${this._composeControlActionPropertyClause(templateProperty, matchingRequestProperty)}})`
return `(\`controlAction\`)${objectRelationClause}(\`${propertyAlias}\`:\`PropertyValue\`:\`ThingInterface\` {${this._composeControlActionPropertyClause(templateProperty, matchingRequestProperty)}})${wasDerivedFromClause}`
}
case 'PropertyValueSpecification': {
const matchingRequestPropertyValue = requestInput.propertyValueObject.find(requestPropertyValue => {
return requestPropertyValue.potentialActionPropertyValueSpecificationIdentifier === templateProperty.identifier
})

const { templatePropertyAlias, propertyAlias } = this._getAliasesForProperty(template, templateProperty.identifier)

const wasDerivedFromRelationClause = this.queryHelper.generateRelationClause('PropertyValue', 'wasDerivedFrom')
const wasDerivedFromClause = `${wasDerivedFromRelationClause}(\`${templatePropertyAlias}\`)`

// compose PropertyValue clause
if (typeof matchingRequestPropertyValue === 'object') {
const valuesClause = this._composeControlActionPropertyValueClause(templateProperty, matchingRequestPropertyValue)

// compose PropertyValue clause
return `(\`controlAction\`)${objectRelationClause}(\`${matchingRequestPropertyValue.propertyValueAlias}\`:\`PropertyValue\`:\`ThingInterface\` {${valuesClause}})`
return `(\`controlAction\`)${objectRelationClause}(\`${propertyAlias}\`:\`PropertyValue\`:\`ThingInterface\` {${valuesClause}})${wasDerivedFromClause}`
}

// use the default value if given in the template PropertyValue
Expand All @@ -318,7 +321,7 @@ class RequestControlActionCommand {
})

// use a random PropertyValue alias, we are not referring to it
return `(\`controlAction\`)${objectRelationClause}(\`propertyValue_${Math.round(Math.random() * 100)}\`:\`PropertyValue\`:\`ThingInterface\` {${valuesClause}})`
return `(\`controlAction\`)${objectRelationClause}(\`propertyValue_${Math.round(Math.random() * 100)}\`:\`PropertyValue\`:\`ThingInterface\` {${valuesClause}})${wasDerivedFromClause}`
}

// throw error if this property is required
Expand All @@ -342,16 +345,18 @@ class RequestControlActionCommand {

/**
* @param requestProperties
* @param template
* @returns {string}
* @private
*/
_generateNodeValueRelationsClause (requestProperties) {
_generateNodeValueRelationsClause (requestProperties, template) {
if (!Array.isArray(requestProperties) || requestProperties.length <= 0) {
return ''
}

const segments = requestProperties.map(requestProperty => {
return `(\`${requestProperty.propertyValueAlias}\`)${this.queryHelper.generateRelationClause('PropertyValue', 'nodeValue')}(\`${requestProperty.alias}\`)`
const { propertyAlias, nodeAlias } = this._getAliasesForProperty(template, requestProperty.potentialActionPropertyIdentifier)
return `(\`${propertyAlias}\`)${this.queryHelper.generateRelationClause('PropertyValue', 'nodeValue')}(\`${nodeAlias}\`)`
})

return `CREATE ${segments.join(', ')}`
Expand Down
21 changes: 11 additions & 10 deletions src/helpers/SchemaHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { info, warning } from '../utils/logger'
class SchemaHelper {
constructor (schema) {
this.schema = (typeof schema === 'object') ? schema : defaultSchema
this.schemaTypeMap = this.schema._typeMap
}

/**
Expand All @@ -13,12 +12,12 @@ class SchemaHelper {
* @returns {GraphQLField<*, *>|GraphQLInputField}
*/
findPropertyType (parentType, propertyName) {
const typeMap = this.schema._typeMap[parentType]
const typeMap = this.schema.getType(parentType)
if (typeof typeMap === 'undefined') {
throw Error('Type could not be retrieved from schema')
}

const propertyType = typeMap._fields[propertyName]
const propertyType = typeMap.getFields()[propertyName]
if (typeof propertyType === 'undefined') {
throw Error('Property type could not be retrieved from schema')
}
Expand All @@ -32,7 +31,7 @@ class SchemaHelper {
*/
findInterfaceImplementingTypes (interfaceName) {
const implementations = this.findInterface(interfaceName)
if (implementations instanceof Array === false || !implementations.length) {
if (!Array.isArray(implementations) || !implementations.length) {
return null
}

Expand All @@ -44,15 +43,16 @@ class SchemaHelper {
* @returns {*|Array<GraphQLObjectType>}
*/
findInterface (interfaceName) {
return this.schema._implementationsMap[interfaceName]
return this.schema.getImplementations(interfaceName)
}

/**
* @param unionName
* @returns {*}
*/
findPossibleTypes (unionName) {
const possibleTypes = this.schema._possibleTypeMap[unionName]
const possibleTypes = this.schema.getImplementations(unionName)

if (typeof possibleTypes !== 'object') {
return null
}
Expand All @@ -79,7 +79,7 @@ class SchemaHelper {
*/
getTypeNames () {
return Object
.values(this.schemaTypeMap)
.values(this.schema.getTypeMap())
.filter(type => type.astNode && type.astNode.kind === 'ObjectTypeDefinition' && !!type.astNode.interfaces.length)
.map(type => type.name)
}
Expand All @@ -90,7 +90,8 @@ class SchemaHelper {
*/
getTypeFields (typeName) {
const schemaType = this.getSchemaType(typeName)
const typeFields = schemaType._fields
const typeFields = schemaType && schemaType.getFields()

if (typeof typeFields === 'undefined') {
info('No typeFields (type could be scalar)')
return null
Expand Down Expand Up @@ -130,7 +131,7 @@ class SchemaHelper {
* @returns {*}
*/
getSchemaType (typeName) {
const schemaType = this.schemaTypeMap[typeName]
const schemaType = this.schema.getType(typeName)
if (typeof schemaType === 'undefined') {
throw Error('Type could not be retrieved from schema')
}
Expand All @@ -145,7 +146,7 @@ class SchemaHelper {
const relationDetails = {}

const directives = propertyType.astNode.directives
if (directives instanceof Array === false) {
if (!Array.isArray(directives)) {
throw Error('Type property directives could not be retrieved from schema')
}

Expand Down
13 changes: 9 additions & 4 deletions src/queries/SearchQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ class SearchQuery {
this.params = params
this.resolveInfo = resolveInfo

this.doEvaluateTypeSubset = !(!(this.params.onTypes instanceof Array) || this.params.onTypes.length === 0 || this.params.onTypes.length === this.resolveInfo.schema._typeMap.SearchableInterfaceType._values.length)
this.doEvaluateFieldSubset = !(!(this.params.onFields instanceof Array) || this.params.onFields.length === 0 || this.params.onFields.length === this.resolveInfo.schema._typeMap.SearchableMetadataFields._values.length)
this.searchableInterfaceType = this.resolveInfo.schema.getType('SearchableInterfaceType')
this.searchableMetadataFields = this.resolveInfo.schema.getType('SearchableMetadataFields')

const { onTypes, onFields } = this.params

this.doEvaluateTypeSubset = Array.isArray(onTypes) && onTypes.length && onTypes.length !== this.searchableInterfaceType.getValues().length
this.doEvaluateFieldSubset = Array.isArray(onFields) && onFields.length && onFields.length !== this.searchableMetadataFields.getValues().length
}

/**
Expand Down Expand Up @@ -66,7 +71,7 @@ class SearchQuery {
_generateQueryClause () {
// if only a subset of fields need to be evaluated: build query clause for [substring]~ on all eligible fields
if (this.doEvaluateFieldSubset) {
const fieldNames = this.doEvaluateFieldSubset ? this.params.onFields : this.resolveInfo.schema._typeMap.SearchableMetadataFields._values.map(field => { return field.name })
const fieldNames = this.doEvaluateFieldSubset ? this.params.onFields : this.searchableMetadataFields.getValues().map(field => { return field.name })

return fieldNames
.map(field => this._generateFieldSubStringClause(field))
Expand All @@ -84,7 +89,7 @@ class SearchQuery {
// if only a subset of types need to be evaluated: build type clause for [substring]~ on all eligible fields
let typeClause = ''
if (this.doEvaluateTypeSubset) {
const typeNames = this.doEvaluateTypeSubset ? this.params.onTypes : this.resolveInfo.schema._typeMap.SearchableInterfaceType._values.map(type => { return `'${type.name}'` })
const typeNames = this.doEvaluateTypeSubset ? this.params.onTypes : this.searchableInterfaceType.getValues().map(type => { return `'${type.name}'` })
typeClause = `WHERE HEAD(labels(\`node\`)) IN ['${typeNames.join('\', \'')}']`
}

Expand Down
Loading

0 comments on commit 7ea57cf

Please sign in to comment.