Skip to content

Commit 0365f07

Browse files
authored
Merge pull request #494 from martin-neotech/recordmapfunction
Implemented map function for Record.
2 parents a17eee1 + fa5ee39 commit 0365f07

File tree

8 files changed

+179
-12
lines changed

8 files changed

+179
-12
lines changed

src/graph-types.js

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@
1717
* limitations under the License.
1818
*/
1919

20+
const IDENTIFIER_PROPERTY_ATTRIBUTES = {
21+
value: true,
22+
enumerable: false,
23+
configurable: false,
24+
writable: false
25+
}
26+
27+
const NODE_IDENTIFIER_PROPERTY = '__isNode__'
28+
const RELATIONSHIP_IDENTIFIER_PROPERTY = '__isRelationship__'
29+
const UNBOUND_RELATIONSHIP_IDENTIFIER_PROPERTY = '__isUnboundRelationship__'
30+
const PATH_IDENTIFIER_PROPERTY = '__isPath__'
31+
const PATH_SEGMENT_IDENTIFIER_PROPERTY = '__isPathSegment__'
32+
33+
function hasIdentifierProperty (obj, property) {
34+
return (obj && obj[property]) === true
35+
}
36+
2037
/**
2138
* Class for Node Type.
2239
*/
@@ -54,7 +71,7 @@ class Node {
5471
for (let i = 0; i < this.labels.length; i++) {
5572
s += ':' + this.labels[i]
5673
}
57-
let keys = Object.keys(this.properties)
74+
const keys = Object.keys(this.properties)
5875
if (keys.length > 0) {
5976
s += ' {'
6077
for (let i = 0; i < keys.length; i++) {
@@ -68,6 +85,21 @@ class Node {
6885
}
6986
}
7087

88+
Object.defineProperty(
89+
Node.prototype,
90+
NODE_IDENTIFIER_PROPERTY,
91+
IDENTIFIER_PROPERTY_ATTRIBUTES
92+
)
93+
94+
/**
95+
* Test if given object is an instance of {@link Node} class.
96+
* @param {Object} obj the object to test.
97+
* @return {boolean} `true` if given object is a {@link Node}, `false` otherwise.
98+
*/
99+
function isNode (obj) {
100+
return hasIdentifierProperty(obj, NODE_IDENTIFIER_PROPERTY)
101+
}
102+
71103
/**
72104
* Class for Relationship Type.
73105
*/
@@ -114,7 +146,7 @@ class Relationship {
114146
*/
115147
toString () {
116148
let s = '(' + this.start + ')-[:' + this.type
117-
let keys = Object.keys(this.properties)
149+
const keys = Object.keys(this.properties)
118150
if (keys.length > 0) {
119151
s += ' {'
120152
for (let i = 0; i < keys.length; i++) {
@@ -128,6 +160,21 @@ class Relationship {
128160
}
129161
}
130162

163+
Object.defineProperty(
164+
Relationship.prototype,
165+
RELATIONSHIP_IDENTIFIER_PROPERTY,
166+
IDENTIFIER_PROPERTY_ATTRIBUTES
167+
)
168+
169+
/**
170+
* Test if given object is an instance of {@link Relationship} class.
171+
* @param {Object} obj the object to test.
172+
* @return {boolean} `true` if given object is a {@link Relationship}, `false` otherwise.
173+
*/
174+
function isRelationship (obj) {
175+
return hasIdentifierProperty(obj, RELATIONSHIP_IDENTIFIER_PROPERTY)
176+
}
177+
131178
/**
132179
* Class for UnboundRelationship Type.
133180
* @access private
@@ -181,7 +228,7 @@ class UnboundRelationship {
181228
*/
182229
toString () {
183230
let s = '-[:' + this.type
184-
let keys = Object.keys(this.properties)
231+
const keys = Object.keys(this.properties)
185232
if (keys.length > 0) {
186233
s += ' {'
187234
for (let i = 0; i < keys.length; i++) {
@@ -195,6 +242,21 @@ class UnboundRelationship {
195242
}
196243
}
197244

245+
Object.defineProperty(
246+
UnboundRelationship.prototype,
247+
UNBOUND_RELATIONSHIP_IDENTIFIER_PROPERTY,
248+
IDENTIFIER_PROPERTY_ATTRIBUTES
249+
)
250+
251+
/**
252+
* Test if given object is an instance of {@link UnboundRelationship} class.
253+
* @param {Object} obj the object to test.
254+
* @return {boolean} `true` if given object is a {@link UnboundRelationship}, `false` otherwise.
255+
*/
256+
function isUnboundRelationship (obj) {
257+
return hasIdentifierProperty(obj, UNBOUNT_RELATIONSHIP_IDENTIFIER_PROPERTY)
258+
}
259+
198260
/**
199261
* Class for PathSegment Type.
200262
*/
@@ -225,6 +287,21 @@ class PathSegment {
225287
}
226288
}
227289

290+
Object.defineProperty(
291+
PathSegment.prototype,
292+
PATH_SEGMENT_IDENTIFIER_PROPERTY,
293+
IDENTIFIER_PROPERTY_ATTRIBUTES
294+
)
295+
296+
/**
297+
* Test if given object is an instance of {@link PathSegment} class.
298+
* @param {Object} obj the object to test.
299+
* @return {boolean} `true` if given object is a {@link PathSegment}, `false` otherwise.
300+
*/
301+
function isPathSegment (obj) {
302+
return hasIdentifierProperty(obj, PATH_SEGMENT_IDENTIFIER_PROPERTY)
303+
}
304+
228305
/**
229306
* Class for Path Type.
230307
*/
@@ -260,4 +337,30 @@ class Path {
260337
}
261338
}
262339

263-
export { Node, Relationship, UnboundRelationship, Path, PathSegment }
340+
Object.defineProperty(
341+
Path.prototype,
342+
PATH_IDENTIFIER_PROPERTY,
343+
IDENTIFIER_PROPERTY_ATTRIBUTES
344+
)
345+
346+
/**
347+
* Test if given object is an instance of {@link Path} class.
348+
* @param {Object} obj the object to test.
349+
* @return {boolean} `true` if given object is a {@link Path}, `false` otherwise.
350+
*/
351+
function isPath (obj) {
352+
return hasIdentifierProperty(obj, PATH_IDENTIFIER_PROPERTY)
353+
}
354+
355+
export {
356+
Node,
357+
isNode,
358+
Relationship,
359+
isRelationship,
360+
UnboundRelationship,
361+
isUnboundRelationship,
362+
Path,
363+
isPath,
364+
PathSegment,
365+
isPathSegment
366+
}

src/record.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import { newError } from './error'
2121

2222
function generateFieldLookup (keys) {
23-
let lookup = {}
23+
const lookup = {}
2424
keys.forEach((name, idx) => {
2525
lookup[name] = idx
2626
})
@@ -85,6 +85,26 @@ class Record {
8585
}
8686
}
8787

88+
/**
89+
* Run the given function for each field in this record. The function
90+
* will get three arguments - the value, the key and this record, in that
91+
* order.
92+
*
93+
* @param {function(value: Object, key: string, record: Record)} visitor the function to apply on each field
94+
* and return a value that is saved to the returned Array.
95+
*
96+
* @returns {Array}
97+
*/
98+
map (visitor) {
99+
const resultArray = []
100+
101+
for (let i = 0; i < this.keys.length; i++) {
102+
resultArray.push(visitor(this._fields[i], this.keys[i], this))
103+
}
104+
105+
return resultArray
106+
}
107+
88108
/**
89109
* Generates an object out of the current Record
90110
*

src/spatial-types.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ export class Point {
6262
toString () {
6363
return this.z || this.z === 0
6464
? `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat(
65-
this.x
66-
)}, y=${formatAsFloat(this.y)}, z=${formatAsFloat(this.z)}}`
65+
this.x
66+
)}, y=${formatAsFloat(this.y)}, z=${formatAsFloat(this.z)}}`
6767
: `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat(
68-
this.x
69-
)}, y=${formatAsFloat(this.y)}}`
68+
this.x
69+
)}, y=${formatAsFloat(this.y)}}`
7070
}
7171
}
7272

@@ -77,7 +77,8 @@ function formatAsFloat (number) {
7777
Object.defineProperty(Point.prototype, POINT_IDENTIFIER_PROPERTY, {
7878
value: true,
7979
enumerable: false,
80-
configurable: false
80+
configurable: false,
81+
writable: false
8182
})
8283

8384
/**

src/temporal-types.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import { newError } from './error'
2828
const IDENTIFIER_PROPERTY_ATTRIBUTES = {
2929
value: true,
3030
enumerable: false,
31-
configurable: false
31+
configurable: false,
32+
writable: false
3233
}
3334

3435
const DURATION_IDENTIFIER_PROPERTY = '__isDuration__'

test/record.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,17 @@ describe('#unit Record', () => {
113113
// Then
114114
expect(result).toEqual([['Bob', 'name', record], [45, 'age', record]])
115115
})
116+
117+
it('should allow map function for the record', () => {
118+
// Given
119+
const record = new Record(['name', 'age'], ['Bob', 45])
120+
121+
// When
122+
const result = record.map((value, key, rec) => {
123+
return [value, key, rec]
124+
})
125+
126+
// Then
127+
expect(result).toEqual([['Bob', 'name', record], [45, 'age', record]])
128+
})
116129
})

test/types/graph-types.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ import {
2222
Path,
2323
PathSegment,
2424
Relationship,
25-
UnboundRelationship
25+
UnboundRelationship,
26+
isNode,
27+
isPath,
28+
isPathSegment,
29+
isRelationship,
30+
isUnboundRelationship
2631
} from '../../types/graph-types'
2732
import Integer, { int } from '../../types/integer'
2833

@@ -32,6 +37,7 @@ const node1Id: Integer = node1.identity
3237
const node1Labels: string[] = node1.labels
3338
const node1Props: object = node1.properties
3439
const isNode1: boolean = node1 instanceof Node
40+
const isNode1B: boolean = isNode(node1)
3541

3642
const node2: Node<number> = new Node(2, ['Person', 'Employee'], {
3743
name: 'Alice'
@@ -48,6 +54,7 @@ const rel1End: Integer = rel1.end
4854
const rel1Type: string = rel1.type
4955
const rel1Props: object = rel1.properties
5056
const isRel1: boolean = rel1 instanceof Relationship
57+
const isRel1B: boolean = isRelationship(rel1)
5158

5259
const rel2: UnboundRelationship = new UnboundRelationship(int(1), 'KNOWS', {
5360
since: 12345
@@ -58,6 +65,7 @@ const rel2Id: Integer = rel2.identity
5865
const rel2Type: string = rel2.type
5966
const rel2Props: object = rel2.properties
6067
const isRel2: boolean = rel2 instanceof UnboundRelationship
68+
const isRel2B: boolean = isUnboundRelationship(rel2)
6169

6270
const rel4: Relationship<number> = new Relationship(2, 3, 4, 'KNOWS', {
6371
since: 12345
@@ -82,6 +90,7 @@ const pathSegment1Start: Node = pathSegment1.start
8290
const pathSegment1Rel: Relationship = pathSegment1.relationship
8391
const pathSegment1End: Node = pathSegment1.end
8492
const isPathSegment1: boolean = pathSegment1 instanceof PathSegment
93+
const isPathSegment1B: boolean = isPathSegment(pathSegment1)
8594

8695
const pathSegment2: PathSegment<number> = new PathSegment(node2, rel4, node2)
8796
const pathSegment2Start: Node<number> = pathSegment2.start
@@ -94,6 +103,7 @@ const path1End: Node = path1.end
94103
const path1Segments: PathSegment[] = path1.segments
95104
const path1Length: number = path1.length
96105
const isPath1: boolean = path1 instanceof Path
106+
const isPath1B: boolean = isPath(path1)
97107

98108
const path2: Path<number> = new Path(node2, node2, [pathSegment2])
99109
const path2Start: Node<number> = path2.start

types/graph-types.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,27 @@ declare class Path<T extends NumberOrInteger = Integer> {
7373
constructor(start: Node<T>, end: Node<T>, segments: PathSegment<T>[])
7474
}
7575

76+
declare function isNode(obj: object): boolean
77+
78+
declare function isRelationship(obj: object): boolean
79+
80+
declare function isUnboundRelationship(obj: object): boolean
81+
82+
declare function isPath(obj: object): boolean
83+
84+
declare function isPathSegment(obj: object): boolean
85+
7686
export {
7787
Node,
7888
Relationship,
7989
UnboundRelationship,
8090
Path,
8191
PathSegment,
92+
isNode,
93+
isRelationship,
94+
isUnboundRelationship,
95+
isPath,
96+
isPathSegment,
8297
NumberOrInteger,
8398
StandardDate
8499
}

types/record.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
declare type Visitor = (value: any, key: string, record: Record) => void
2121

22+
declare type MapVisitor<T> = (value: any, key: string, record: Record) => T
23+
2224
declare class Record {
2325
keys: string[]
2426
length: number
@@ -31,6 +33,8 @@ declare class Record {
3133

3234
forEach(visitor: Visitor): void
3335

36+
map<T>(visitor: MapVisitor<T>): T[]
37+
3438
toObject(): object
3539

3640
get(key: string | number): any

0 commit comments

Comments
 (0)