Skip to content

Commit 85c0939

Browse files
authored
Add generic types for Node#labels, Relationship#type and UnboundRelationship#type (#1014)
This generic types enable defining a list string like values accepted for an specific node labels list or relationship type. Node example: ```typescript type PersonLabels = 'Person' | 'Actor' // get the person from a non-typed record. If the record is correctly type-mapped // the Node type can be omitted since it will be inferred. const person: Node<Integer, PersonProps, PersonLabels> = record.get('person') // get labels // the type inferred for the labels will be PersonLabels[] const labels = person.labels // @ts-exepct-error const wrongLabels: 'Car'|'Bicycle'[] = person.labels ``` Relationship/UnboundRelationship example: ```typescript type ActedInType = 'ACTED_IN' // get the relationship from a non-typed record. If the record is correctly type mapped // the Relationship type can be omitted since it will be inferred. const actedIn: Relationship<Integer, ActedInProps, ActedInType> = record.get('actedIn') // get type // the type inferred for the relType will be 'ACTED_IN' const relType = actedIn.type // @ts-expect-error const directed: 'DIRECTED' = actedIn.type ``` ⚠️ This type definitions are not asserted in runtime. Thus mismatched type records coming from the database will not trigger type errors.
1 parent 1720c97 commit 85c0939

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

packages/core/src/graph-types.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function hasIdentifierProperty (obj: any, property: string): boolean {
4747
/**
4848
* Class for Node Type.
4949
*/
50-
class Node<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
50+
class Node<T extends NumberOrInteger = Integer, P extends Properties = Properties, Label extends string = string> {
5151
identity: T
52-
labels: string[]
52+
labels: Label[]
5353
properties: P
5454
elementId: string
5555
/**
@@ -60,7 +60,7 @@ class Node<T extends NumberOrInteger = Integer, P extends Properties = Propertie
6060
* @param {Properties} properties - Map with node properties
6161
* @param {string} elementId - Node element identifier
6262
*/
63-
constructor (identity: T, labels: string[], properties: P, elementId?: string) {
63+
constructor (identity: T, labels: Label[], properties: P, elementId?: string) {
6464
/**
6565
* Identity of the node.
6666
* @type {NumberOrInteger}
@@ -124,11 +124,11 @@ function isNode (obj: object): obj is Node {
124124
/**
125125
* Class for Relationship Type.
126126
*/
127-
class Relationship<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
127+
class Relationship<T extends NumberOrInteger = Integer, P extends Properties = Properties, Type extends string = string> {
128128
identity: T
129129
start: T
130130
end: T
131-
type: string
131+
type: Type
132132
properties: P
133133
elementId: string
134134
startNodeElementId: string
@@ -147,7 +147,7 @@ class Relationship<T extends NumberOrInteger = Integer, P extends Properties = P
147147
* @param {string} endNodeElementId - End Node element identifier
148148
*/
149149
constructor (
150-
identity: T, start: T, end: T, type: string, properties: P,
150+
identity: T, start: T, end: T, type: Type, properties: P,
151151
elementId?: string, startNodeElementId?: string, endNodeElementId?: string
152152
) {
153153
/**
@@ -236,9 +236,9 @@ function isRelationship (obj: object): obj is Relationship {
236236
* Class for UnboundRelationship Type.
237237
* @access private
238238
*/
239-
class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
239+
class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Properties = Properties, Type extends string = string> {
240240
identity: T
241-
type: string
241+
type: Type
242242
properties: P
243243
elementId: string
244244

@@ -250,7 +250,7 @@ class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Propert
250250
* @param {Properties} properties - Map with relationship properties
251251
* @param {string} elementId - Relationship element identifier
252252
*/
253-
constructor (identity: T, type: string, properties: any, elementId?: string) {
253+
constructor (identity: T, type: Type, properties: any, elementId?: string) {
254254
/**
255255
* Identity of the relationship.
256256
* @type {NumberOrInteger}

packages/core/test/graph-types.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ describe('Node', () => {
7878
expect(isNode(nonNode)).toBe(false)
7979
})
8080

81+
test('should type mapping labels', () => {
82+
type PersonLabels = 'Person' | 'Actor'
83+
const labels: PersonLabels[] = ['Actor', 'Person']
84+
type Person = Node<number, {}, PersonLabels>
85+
86+
const p: Person = new Node(1, labels, {})
87+
88+
const receivedLabels: PersonLabels[] = p.labels
89+
90+
expect(receivedLabels).toEqual(labels)
91+
92+
// @ts-expect-error
93+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
94+
const _: 'Movie'|Array<'TvShow'> = p.labels
95+
})
96+
8197
function validNodes (): any[] {
8298
return [
8399
[new Node(1, ['label'], {}, 'elementId')],
@@ -191,6 +207,18 @@ describe('Relationship', () => {
191207
expect(isRelationship(nonRelationship)).toBe(false)
192208
})
193209

210+
test('should type mapping relationship type', () => {
211+
type ActedIn = Relationship<number, { [key in string]: any }, 'ACTED_IN'>
212+
const a: ActedIn = new Relationship(1, 1, 2, 'ACTED_IN', {})
213+
214+
const receivedType: 'ACTED_IN' = a.type
215+
expect(receivedType).toEqual('ACTED_IN')
216+
217+
// @ts-expect-error
218+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
219+
const _: 'DIRECTED' = a.type
220+
})
221+
194222
function validRelationships (): any[] {
195223
return [
196224
[new Relationship(1, 2, 3, 'Rel', {}, 'elementId', 'startNodeElementId', 'endNodeElementId')],
@@ -306,6 +334,18 @@ describe('UnboundRelationship', () => {
306334
)
307335
})
308336

337+
test('should type mapping relationship type', () => {
338+
type ActedIn = UnboundRelationship<number, { [key in string]: any }, 'ACTED_IN'>
339+
const a: ActedIn = new UnboundRelationship(1, 'ACTED_IN', {})
340+
341+
const receivedType: 'ACTED_IN' = a.type
342+
expect(receivedType).toEqual('ACTED_IN')
343+
344+
// @ts-expect-error
345+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
346+
const _: 'DIRECTED' = a.type
347+
})
348+
309349
function validUnboundRelationships (): any[] {
310350
return [
311351
[new UnboundRelationship(1, 'Rel', {}, 'elementId')],

packages/neo4j-driver-deno/lib/core/graph-types.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function hasIdentifierProperty (obj: any, property: string): boolean {
4747
/**
4848
* Class for Node Type.
4949
*/
50-
class Node<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
50+
class Node<T extends NumberOrInteger = Integer, P extends Properties = Properties, Label extends string = string> {
5151
identity: T
52-
labels: string[]
52+
labels: Label[]
5353
properties: P
5454
elementId: string
5555
/**
@@ -60,7 +60,7 @@ class Node<T extends NumberOrInteger = Integer, P extends Properties = Propertie
6060
* @param {Properties} properties - Map with node properties
6161
* @param {string} elementId - Node element identifier
6262
*/
63-
constructor (identity: T, labels: string[], properties: P, elementId?: string) {
63+
constructor (identity: T, labels: Label[], properties: P, elementId?: string) {
6464
/**
6565
* Identity of the node.
6666
* @type {NumberOrInteger}
@@ -124,11 +124,11 @@ function isNode (obj: object): obj is Node {
124124
/**
125125
* Class for Relationship Type.
126126
*/
127-
class Relationship<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
127+
class Relationship<T extends NumberOrInteger = Integer, P extends Properties = Properties, Type extends string = string> {
128128
identity: T
129129
start: T
130130
end: T
131-
type: string
131+
type: Type
132132
properties: P
133133
elementId: string
134134
startNodeElementId: string
@@ -147,7 +147,7 @@ class Relationship<T extends NumberOrInteger = Integer, P extends Properties = P
147147
* @param {string} endNodeElementId - End Node element identifier
148148
*/
149149
constructor (
150-
identity: T, start: T, end: T, type: string, properties: P,
150+
identity: T, start: T, end: T, type: Type, properties: P,
151151
elementId?: string, startNodeElementId?: string, endNodeElementId?: string
152152
) {
153153
/**
@@ -236,9 +236,9 @@ function isRelationship (obj: object): obj is Relationship {
236236
* Class for UnboundRelationship Type.
237237
* @access private
238238
*/
239-
class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Properties = Properties> {
239+
class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Properties = Properties, Type extends string = string> {
240240
identity: T
241-
type: string
241+
type: Type
242242
properties: P
243243
elementId: string
244244

@@ -250,7 +250,7 @@ class UnboundRelationship<T extends NumberOrInteger = Integer, P extends Propert
250250
* @param {Properties} properties - Map with relationship properties
251251
* @param {string} elementId - Relationship element identifier
252252
*/
253-
constructor (identity: T, type: string, properties: any, elementId?: string) {
253+
constructor (identity: T, type: Type, properties: any, elementId?: string) {
254254
/**
255255
* Identity of the relationship.
256256
* @type {NumberOrInteger}

0 commit comments

Comments
 (0)