Skip to content

Commit 89dc64f

Browse files
authored
bug: Accommodated for special characters in edge labels to ensure correct Cypher translation (aws#127)
Queries would fail if an edge label contained a special character such as a colon, period, or space as it is invalid formatting for Cypher. Thus, back ticks were added to ensure that special characters could be included as label names without crashing from incorrect Cypher translations. Added a unit test for the resolver to ensure backticks are added correctly in cypher translations from queries with special characters in edge labels. Also changed existing resolver unit tests to accommodate for this change.
1 parent 90215c2 commit 89dc64f

File tree

4 files changed

+184
-106
lines changed

4 files changed

+184
-106
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,12 @@ permissions and limitations under the License.
112112
* Fixed Apollo template to reference `graphql` `parse` instead of `graphql-tag`
113113
`gql` ([#116](https://github.com/aws/amazon-neptune-for-graphql/pull/116))
114114
* Fixed deployment of AWS resources if a pipeline name is not provided as an
115-
input
116-
option ([#117](https://github.com/aws/amazon-neptune-for-graphql/pull/117))
115+
input option ([#117](https://github.com/aws/amazon-neptune-for-graphql/pull/117))
117116
* Fixed invalid schema generation when AWS AppSync scalar types are used in
118-
an input
119-
schema ([#118](https://github.com/aws/amazon-neptune-for-graphql/pull/118))
117+
an input schema ([#118](https://github.com/aws/amazon-neptune-for-graphql/pull/118))
120118
* Fixed duplicated nodes and edges from nodes with
121119
multi-labels ([#125](https://github.com/aws/amazon-neptune-for-graphql/pull/125))
122120
* Updated Apollo subgraph to allow use of Federation 2 features.
123121
([#126](https://github.com/aws/amazon-neptune-for-graphql/pull/126))
122+
* Accommodated for special characters in edge labels to ensure proper Cypher
123+
translation ([#127](https://github.com/aws/amazon-neptune-for-graphql/pull/127))

src/test/airports.customized.graphql

Lines changed: 136 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ type Continent @alias(property: "continent") {
88
type: String
99
code: String
1010
desc: String
11-
airportContainssOut(filter: AirportInput, options: Options): [Airport] @relationship(edgeType: "contains", direction: OUT)
11+
airportContainssOut(filter: AirportInput, options: Options, sort: [AirportSort!]): [Airport] @relationship(edgeType: "contains", direction: OUT)
1212
contains: Contains
1313
}
1414

1515
input ContinentInput {
16-
_id: ID @id
17-
type: StringScalarFilters
18-
code: StringScalarFilters
19-
desc: StringScalarFilters
16+
_id: ID @id
17+
type: StringScalarFilters
18+
code: StringScalarFilters
19+
desc: StringScalarFilters
2020
}
2121

2222
input ContinentCreateInput {
@@ -54,24 +54,24 @@ type Country @alias(property: "country") {
5454
governmentSite: AWSURL
5555
emergencyLine: AWSPhone
5656
gatewayIp: AWSIPAddress
57-
airportContainssOut(filter: AirportInput, options: Options): [Airport] @relationship(edgeType: "contains", direction: OUT)
57+
airportContainssOut(filter: AirportInput, options: Options, sort: [AirportSort!]): [Airport] @relationship(edgeType: "contains", direction: OUT)
5858
contains: Contains
5959
}
6060

6161
input CountryInput {
62-
_id: ID @id
63-
type: StringScalarFilters
64-
code: StringScalarFilters
65-
desc: StringScalarFilters
66-
foundingDate: AWSDate
67-
localOfficeTime: AWSTime
68-
updatedAt: AWSDateTime
69-
createdTimestamp: AWSTimestamp
70-
officialEmail: AWSEmail
71-
metadataJson: AWSJSON
72-
governmentSite: AWSURL
73-
emergencyLine: AWSPhone
74-
gatewayIp: AWSIPAddress
62+
_id: ID @id
63+
type: StringScalarFilters
64+
code: StringScalarFilters
65+
desc: StringScalarFilters
66+
foundingDate: AWSDate
67+
localOfficeTime: AWSTime
68+
updatedAt: AWSDateTime
69+
createdTimestamp: AWSTimestamp
70+
officialEmail: AWSEmail
71+
metadataJson: AWSJSON
72+
governmentSite: AWSURL
73+
emergencyLine: AWSPhone
74+
gatewayIp: AWSIPAddress
7575
}
7676

7777
input CountryCreateInput {
@@ -129,15 +129,17 @@ type Version @alias(property: "version") {
129129
author: String
130130
type: String
131131
code: String
132+
dataSourcePulled_cn_fromOut(filter: DataSourceInput, options: Options): [DataSource] @relationship(edgeType: "pulled:From", direction: OUT)
133+
pulled_cn_From: Pulled_cn_from
132134
}
133135

134136
input VersionInput {
135-
_id: ID @id
136-
date: StringScalarFilters
137-
desc: StringScalarFilters
138-
author: StringScalarFilters
139-
type: StringScalarFilters
140-
code: StringScalarFilters
137+
_id: ID @id
138+
date: StringScalarFilters
139+
desc: StringScalarFilters
140+
author: StringScalarFilters
141+
type: StringScalarFilters
142+
code: StringScalarFilters
141143
}
142144

143145
input VersionCreateInput {
@@ -191,19 +193,19 @@ type Airport @alias(property: "airport") {
191193
}
192194

193195
input AirportInput {
194-
_id: ID @id
195-
type: StringScalarFilters
196-
city: StringScalarFilters
197-
icao: StringScalarFilters
198-
code: StringScalarFilters
199-
country: StringScalarFilters
200-
lat: Float
201-
longest: Int
202-
runways: Int
203-
desc: StringScalarFilters
204-
lon: Float
205-
region: StringScalarFilters
206-
elev: Int
196+
_id: ID @id
197+
type: StringScalarFilters
198+
city: StringScalarFilters
199+
icao: StringScalarFilters
200+
code: StringScalarFilters
201+
country: StringScalarFilters
202+
lat: Float
203+
longest: Int
204+
runways: Int
205+
desc: StringScalarFilters
206+
lon: Float
207+
region: StringScalarFilters
208+
elev: Int
207209
}
208210

209211
input AirportCreateInput {
@@ -254,61 +256,119 @@ input AirportSort {
254256
elev: SortingDirection
255257
}
256258

257-
type Contains @alias(property:"contains") {
258-
_id: ID! @id
259+
type DataSource @alias(property: "dataSource") {
260+
_id: ID! @id
261+
name: String
262+
type: String
263+
url: String
264+
description: String
265+
lastUpdated: String
266+
isActive: Boolean
267+
versionPulled_cn_fromsIn(filter: VersionInput, options: Options, sort: [VersionSort!]): [Version] @relationship(edgeType: "pulled:From", direction: IN)
268+
pulled_cn_From: Pulled_cn_from
269+
}
270+
271+
input DataSourceInput {
272+
_id: ID @id
273+
name: StringScalarFilters
274+
type: StringScalarFilters
275+
url: StringScalarFilters
276+
description: StringScalarFilters
277+
lastUpdated: StringScalarFilters
278+
isActive: Boolean
259279
}
260280

261-
type Route @alias(property:"route") {
262-
_id: ID! @id
263-
dist: Int
281+
input DataSourceCreateInput {
282+
_id: ID @id
283+
name: String
284+
type: String
285+
url: String
286+
description: String
287+
lastUpdated: String
288+
isActive: Boolean
289+
}
290+
291+
input DataSourceUpdateInput {
292+
_id: ID! @id
293+
name: String
294+
type: String
295+
url: String
296+
description: String
297+
lastUpdated: String
298+
isActive: Boolean
299+
}
300+
301+
input DataSourceSort {
302+
_id: SortingDirection
303+
name: SortingDirection
304+
type: SortingDirection
305+
url: SortingDirection
306+
description: SortingDirection
307+
lastUpdated: SortingDirection
308+
isActive: SortingDirection
309+
}
310+
311+
type Contains @alias(property: "contains") {
312+
_id: ID! @id
313+
}
314+
315+
type Route @alias(property: "route") {
316+
_id: ID! @id
317+
dist: Int
264318
}
265319

266320
input RouteInput {
267-
dist: Int
321+
dist: Int
322+
}
323+
324+
type Pulled_cn_from @alias(property: "pulled:From") {
325+
_id: ID! @id
268326
}
269327

270328
input Options {
271-
limit:Int
272-
offset:Int
329+
limit: Int
330+
offset: Int
273331
}
274332

275333
input StringScalarFilters {
276-
eq: String
277-
contains: String
278-
endsWith: String
279-
startsWith: String
334+
eq: String
335+
contains: String
336+
endsWith: String
337+
startsWith: String
280338
}
281339

282340
type Query {
283-
getAirportByCode(code: String): Airport
284-
getAirportConnection(fromCode: String!, toCode: String!): Airport @cypher(statement: "MATCH (:airport{code: '$fromCode'})-[:route]->(this:airport)-[:route]->(:airport{code:'$toCode'})")
285-
getContinentsWithGremlin: [Continent] @graphQuery(statement: "g.V().hasLabel('continent').elementMap().fold()")
286-
getCountriesCountGremlin: Int @graphQuery(statement: "g.V().hasLabel('country').count()")
287-
getContinent(filter: ContinentInput): Continent
288-
getContinents(filter: ContinentInput, options: Options, sort: [ContinentSort!]): [Continent]
289-
getCountry(filter: CountryInput): Country
290-
getCountrys(filter: CountryInput, options: Options, sort: [CountrySort!]): [Country]
291-
getVersion(filter: VersionInput): Version
292-
getVersions(filter: VersionInput, options: Options, sort: [VersionSort!]): [Version]
293-
getAirport(filter: AirportInput): Airport
294-
airportQuery_getAirport(filter: AirportInput): Airport
295-
getAirports(filter: AirportInput, options: Options, sort: [AirportSort!]): [Airport]
296-
getAirportWithGremlin(code: String): Airport @graphQuery(statement: "g.V().has('airport', 'code', '$code').elementMap()")
297-
getCountriesCount: Int @graphQuery(statement: "g.V().hasLabel('country').count()")
341+
getAirportByCode(code: String): Airport
342+
getAirportConnection(fromCode: String!, toCode: String!): Airport @cypher(statement: "MATCH (:airport{code: '$fromCode'})-[:route]->(this:airport)-[:route]->(:airport{code:'$toCode'})")
343+
getContinentsWithGremlin: [Continent] @graphQuery(statement: "g.V().hasLabel('continent').elementMap().fold()")
344+
getCountriesCountGremlin: Int @graphQuery(statement: "g.V().hasLabel('country').count()")
345+
getContinent(filter: ContinentInput): Continent
346+
getContinents(filter: ContinentInput, options: Options, sort: [ContinentSort!]): [Continent]
347+
getCountry(filter: CountryInput): Country
348+
getCountrys(filter: CountryInput, options: Options, sort: [CountrySort!]): [Country]
349+
getVersion(filter: VersionInput): Version
350+
getVersions(filter: VersionInput, options: Options, sort: [VersionSort!]): [Version]
351+
getAirport(filter: AirportInput): Airport
352+
airportQuery_getAirport(filter: AirportInput): Airport
353+
getAirports(filter: AirportInput, options: Options, sort: [AirportSort!]): [Airport]
354+
getAirportWithGremlin(code: String): Airport @graphQuery(statement: "g.V().has('airport', 'code', '$code').elementMap()")
355+
getCountriesCount: Int @graphQuery(statement: "g.V().hasLabel('country').count()")
298356
}
299357

300358
type Mutation {
301-
createAirport(input: AirportCreateInput!): Airport
302-
airportMutation_createAirport(input: AirportCreateInput!): Airport
303-
updateAirport(input: AirportUpdateInput!): Airport
304-
airportMutation_updateAirport(input: AirportUpdateInput!): Airport
305-
connectCountryToAirportThroughContains(from_id: ID!, to_id: ID!): Contains
306-
airportMutation_connectCountryToAirportThroughContains(from_id: ID!, to_id: ID!): Contains
307-
deleteContainsConnectionFromCountryToAirport(from_id: ID!, to_id: ID!): Boolean
308-
airportMutation_deleteContainsConnectionFromCountryToAirport(from_id: ID!, to_id: ID!): Boolean
309-
updateRouteConnectionFromAirportToAirport(from_id: ID!, to_id: ID!, edge: RouteInput!): Route
310-
airportMutation_updateRouteConnectionFromAirportToAirport(from_id: ID!, to_id: ID!, edge: RouteInput!): Route
311-
createAirportCustom(input: AirportCreateInput!): Airport @graphQuery(statement: "CREATE (this:airport {$input}) RETURN this")
359+
createAirport(input: AirportCreateInput!): Airport
360+
airportMutation_createAirport(input: AirportCreateInput!): Airport
361+
updateAirport(input: AirportUpdateInput!): Airport
362+
airportMutation_updateAirport(input: AirportUpdateInput!): Airport
363+
connectCountryToAirportThroughContains(from_id: ID!, to_id: ID!): Contains
364+
airportMutation_connectCountryToAirportThroughContains(from_id: ID!, to_id: ID!): Contains
365+
deleteContainsConnectionFromCountryToAirport(from_id: ID!, to_id: ID!): Boolean
366+
airportMutation_deleteContainsConnectionFromCountryToAirport(from_id: ID!, to_id: ID!): Boolean
367+
updateRouteConnectionFromAirportToAirport(from_id: ID!, to_id: ID!, edge: RouteInput!): Route
368+
airportMutation_updateRouteConnectionFromAirportToAirport(from_id: ID!, to_id: ID!, edge: RouteInput!): Route
369+
connectVersionToDataSourceThroughPulled_cn_from(from_id: ID!, to_id: ID!): Pulled_cn_from
370+
deletePulled_cn_fromConnectionFromVersionToDataSource(from_id: ID!, to_id: ID!): Boolean
371+
createAirportCustom(input: AirportCreateInput!): Airport @graphQuery(statement: "CREATE (this:airport {$input}) RETURN this")
312372
}
313373

314374
schema {

0 commit comments

Comments
 (0)