Skip to content

Commit efee40a

Browse files
committed
Move the Result Transformers to their own file
1 parent 06a8b90 commit efee40a

File tree

15 files changed

+340
-157
lines changed

15 files changed

+340
-157
lines changed

packages/core/src/driver.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ import {
4242
} from './types'
4343
import { ServerAddress } from './internal/server-address'
4444
import BookmarkManager, { bookmarkManager } from './bookmark-manager'
45-
import EagerResult, { createEagerResultFromResult } from './result-eager'
46-
import Result from './result'
45+
import EagerResult from './result-eager'
46+
import resultTransformers, { ResultTransformer } from './result-transformers'
4747
import QueryExecutor from './internal/query-executor'
4848
import { newError } from './error'
4949

@@ -257,8 +257,6 @@ const routing = {
257257

258258
Object.freeze(routing)
259259

260-
type ResultTransformer<T> = (result: Result) => Promise<T>
261-
262260
/**
263261
* The query configuration
264262
* @interface
@@ -412,11 +410,11 @@ class Driver {
412410
* const transformedResult = await driver.executeQuery(
413411
* "<QUERY>",
414412
* <PARAMETERS>,
415-
* QueryConfig {
416-
* routing: neo4j.routing.WRITERS,
417-
* resultTransformer: transformer,
418-
* database: "<DATABASE>",
419-
* impersonatedUser: "<USER>",
413+
* {
414+
* routing: neo4j.routing.WRITERS,
415+
* resultTransformer: transformer,
416+
* database: "<DATABASE>",
417+
* impersonatedUser: "<USER>",
420418
* bookmarkManager: bookmarkManager
421419
* })
422420
* // are equivalent to those
@@ -436,14 +434,15 @@ class Driver {
436434
* }
437435
*
438436
* @public
437+
* @experimental
439438
* @param {string | {text: string, parameters?: object}} query - Cypher query to execute
440439
* @param {Object} parameters - Map with parameters to use in the query
441440
* @param {QueryConfig<T>} config - The query configuration
442441
* @returns {Promise<T>}
443442
*/
444443
async executeQuery<T> (query: Query, parameters?: any, config: QueryConfig<T> = {}): Promise<T> {
445444
const bookmarkManager = config.bookmarkManager === null ? undefined : (config.bookmarkManager ?? this.queryBookmarkManager)
446-
const resultTransformer = (config.resultTransformer ?? createEagerResultFromResult) as ResultTransformer<T>
445+
const resultTransformer = (config.resultTransformer ?? resultTransformers.eagerResultTransformer()) as ResultTransformer<T>
447446
const routingConfig: string = config.routing ?? routing.WRITERS
448447

449448
if (routingConfig !== routing.READERS && routingConfig !== routing.WRITERS) {
@@ -799,6 +798,6 @@ function createHostNameResolver (config: any): ConfiguredCustomResolver {
799798
return new ConfiguredCustomResolver(config.resolver)
800799
}
801800

802-
export { Driver, READ, WRITE, routing, SessionConfig}
801+
export { Driver, READ, WRITE, routing, SessionConfig }
803802
export type { QueryConfig, RoutingControl }
804803
export default Driver

packages/core/src/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import BookmarkManager, { BookmarkManagerConfig, bookmarkManager } from './bookm
8080
import { SessionConfig, QueryConfig, RoutingControl, routing } from './driver'
8181
import * as types from './types'
8282
import * as json from './json'
83+
import resultTransformers, { ResultTransformer } from './result-transformers'
8384
import * as internal from './internal' // todo: removed afterwards
8485

8586
/**
@@ -152,7 +153,8 @@ const forExport = {
152153
json,
153154
auth,
154155
bookmarkManager,
155-
routing
156+
routing,
157+
resultTransformers
156158
}
157159

158160
export {
@@ -214,7 +216,8 @@ export {
214216
json,
215217
auth,
216218
bookmarkManager,
217-
routing
219+
routing,
220+
resultTransformers
218221
}
219222

220223
export type {
@@ -228,7 +231,8 @@ export type {
228231
BookmarkManagerConfig,
229232
SessionConfig,
230233
QueryConfig,
231-
RoutingControl
234+
RoutingControl,
235+
ResultTransformer
232236
}
233237

234238
export default forExport

packages/core/src/result-eager.ts

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

2020
import Record, { Dict } from './record'
2121
import ResultSummary from './result-summary'
22-
import Result from './result'
2322

2423
/**
2524
* Represents the fully streamed result
@@ -58,17 +57,3 @@ export default class EagerResult<Entries extends Dict = Dict> {
5857
this.summary = summary
5958
}
6059
}
61-
62-
/**
63-
* Creates an {@link EagerResult} from a given {@link Result} by
64-
* consuming the whole stream.
65-
*
66-
* @private
67-
* @param {Result} result The result to be consumed
68-
* @returns A promise of an EagerResult
69-
*/
70-
export async function createEagerResultFromResult<Entries extends Dict = Dict> (result: Result): Promise<EagerResult<Entries>> {
71-
const { summary, records } = await result
72-
const keys = await result.keys()
73-
return new EagerResult<Entries>(keys, records, summary)
74-
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import { Dict } from './record'
21+
import Result from './result'
22+
import EagerResult from './result-eager'
23+
24+
async function createEagerResultFromResult<Entries extends Dict> (result: Result): Promise<EagerResult<Entries>> {
25+
const { summary, records } = await result
26+
const keys = await result.keys()
27+
return new EagerResult<Entries>(keys, records, summary)
28+
}
29+
30+
type ResultTransformer<T> = (result: Result) => Promise<T>
31+
/**
32+
* Protocol for transforming {@link Result}.
33+
*
34+
* @typedef {function<T>(result:Result):Promise<T>} ResultTransformer
35+
* @interface
36+
* @experimental
37+
*
38+
* @see {@link resultTransformers} for provided implementations.
39+
* @see {@link Driver#executeQuery} for usage.
40+
*
41+
*/
42+
/**
43+
* Defines the object which holds the common {@link ResultTransformer} used with {@link Driver#executeQuery}.
44+
*
45+
* @experimental
46+
*/
47+
class ResultTransformers {
48+
/**
49+
* Creates a {@link ResultTransformer} which transforms {@link Result} to {@link EagerResult}
50+
* by consuming the whole stream.
51+
*
52+
* This is the default implementation used in {@link Driver#executeQuery}
53+
*
54+
* @example
55+
* // This:
56+
* const { keys, records, summary } = await driver.executeQuery('CREATE (p:Person{ name: $name }) RETURN p', { name: 'Person1'}, {
57+
* resultTransformer: neo4j.resultTransformers.eagerResultTransformer()
58+
* })
59+
* // equivalent to:
60+
* const { keys, records, summary } = await driver.executeQuery('CREATE (p:Person{ name: $name }) RETURN p', { name: 'Person1'})
61+
*
62+
*
63+
* @experimental
64+
* @returns {ResultTransformer<EagerResult<Entries>>} The result transformer
65+
*/
66+
eagerResultTransformer<Entries extends Dict = Dict>(): ResultTransformer<EagerResult<Entries>> {
67+
return createEagerResultFromResult
68+
}
69+
}
70+
71+
/**
72+
* Holds the common {@link ResultTransformer} used with {@link Driver#executeQuery}.
73+
*
74+
* @experimental
75+
*/
76+
const resultTransformers = new ResultTransformers()
77+
78+
Object.freeze(resultTransformers)
79+
80+
export default resultTransformers
81+
82+
export type {
83+
ResultTransformer
84+
}

packages/core/test/driver.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Logger } from '../src/internal/logger'
2424
import QueryExecutor from '../src/internal/query-executor'
2525
import { ConfiguredCustomResolver } from '../src/internal/resolver'
2626
import { LogLevel } from '../src/types'
27-
import { createEagerResultFromResult } from '../src/result-eager'
27+
import resultTransformers from '../src/result-transformers'
2828
import Record, { Dict } from '../src/record'
2929

3030
describe('Driver', () => {
@@ -334,7 +334,7 @@ describe('Driver', () => {
334334

335335
expect(eagerResult).toEqual(expected)
336336
expect(spiedExecute).toBeCalledWith({
337-
resultTransformer: createEagerResultFromResult,
337+
resultTransformer: resultTransformers.eagerResultTransformer(),
338338
bookmarkManager: driver?.queryBookmarkManager,
339339
routing: routing.WRITERS,
340340
database: undefined,
@@ -458,7 +458,7 @@ describe('Driver', () => {
458458
function extendsDefaultWith<T = EagerResult<Dict>> (config: QueryConfig<T>) {
459459
return () => {
460460
const defaultConfig = {
461-
resultTransformer: createEagerResultFromResult,
461+
resultTransformer: resultTransformers.eagerResultTransformer(),
462462
bookmarkManager: driver?.queryBookmarkManager,
463463
routing: routing.WRITERS,
464464
database: undefined,

packages/core/test/result-eager.test.ts

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
* limitations under the License.
1818
*/
1919

20-
import { EagerResult, newError, Record, Result, ResultSummary } from '../src'
21-
import { createEagerResultFromResult } from '../src/result-eager'
22-
import ResultStreamObserverMock from './utils/result-stream-observer.mock'
20+
import { EagerResult, Record, ResultSummary } from '../src'
2321

2422
describe('EagerResult', () => {
2523
it('should construct with keys, records and summary', () => {
@@ -34,81 +32,3 @@ describe('EagerResult', () => {
3432
expect(eagerResult.summary).toBe(summary)
3533
})
3634
})
37-
38-
describe('createEagerResultFromResult', () => {
39-
describe('with a valid result', () => {
40-
it('it should return an EagerResult', async () => {
41-
const resultStreamObserverMock = new ResultStreamObserverMock()
42-
const query = 'Query'
43-
const params = { a: 1 }
44-
const meta = { db: 'adb' }
45-
const result = new Result(Promise.resolve(resultStreamObserverMock), query, params)
46-
const keys = ['a', 'b']
47-
const rawRecord1 = [1, 2]
48-
const rawRecord2 = [3, 4]
49-
resultStreamObserverMock.onKeys(keys)
50-
resultStreamObserverMock.onNext(rawRecord1)
51-
resultStreamObserverMock.onNext(rawRecord2)
52-
resultStreamObserverMock.onCompleted(meta)
53-
54-
const eagerResult: EagerResult = await createEagerResultFromResult(result)
55-
56-
expect(eagerResult.keys).toEqual(keys)
57-
expect(eagerResult.records).toEqual([
58-
new Record(keys, rawRecord1),
59-
new Record(keys, rawRecord2)
60-
])
61-
expect(eagerResult.summary).toEqual(
62-
new ResultSummary(query, params, meta)
63-
)
64-
})
65-
66-
it('it should return a type-safe EagerResult', async () => {
67-
interface Car {
68-
model: string
69-
year: number
70-
}
71-
const resultStreamObserverMock = new ResultStreamObserverMock()
72-
const query = 'Query'
73-
const params = { a: 1 }
74-
const meta = { db: 'adb' }
75-
const result = new Result(Promise.resolve(resultStreamObserverMock), query, params)
76-
const keys = ['model', 'year']
77-
const rawRecord1 = ['Beautiful Sedan', 1987]
78-
const rawRecord2 = ['Hot Hatch', 1995]
79-
80-
resultStreamObserverMock.onKeys(keys)
81-
resultStreamObserverMock.onNext(rawRecord1)
82-
resultStreamObserverMock.onNext(rawRecord2)
83-
resultStreamObserverMock.onCompleted(meta)
84-
85-
const eagerResult: EagerResult<Car> = await createEagerResultFromResult(result)
86-
87-
expect(eagerResult.keys).toEqual(keys)
88-
expect(eagerResult.records).toEqual([
89-
new Record(keys, rawRecord1),
90-
new Record(keys, rawRecord2)
91-
])
92-
expect(eagerResult.summary).toEqual(
93-
new ResultSummary(query, params, meta)
94-
)
95-
96-
const [car1, car2] = eagerResult.records.map(record => record.toObject())
97-
98-
expect(car1.model).toEqual(rawRecord1[0])
99-
expect(car1.year).toEqual(rawRecord1[1])
100-
101-
expect(car2.model).toEqual(rawRecord2[0])
102-
expect(car2.year).toEqual(rawRecord2[1])
103-
})
104-
})
105-
106-
describe('when results fail', () => {
107-
it('should propagate the exception', async () => {
108-
const expectedError = newError('expected error')
109-
const result = new Result(Promise.reject(expectedError), 'query')
110-
111-
await expect(createEagerResultFromResult(result)).rejects.toThrow(expectedError)
112-
})
113-
})
114-
})

0 commit comments

Comments
 (0)