|
17 | 17 | * limitations under the License. |
18 | 18 | */ |
19 | 19 |
|
20 | | -import { Dict } from './record.ts' |
| 20 | +import Record, { Dict } from './record.ts' |
21 | 21 | import Result from './result.ts' |
22 | 22 | import EagerResult from './result-eager.ts' |
| 23 | +import ResultSummary from './result-summary.ts' |
| 24 | +import { newError } from './error.ts' |
23 | 25 |
|
24 | 26 | async function createEagerResultFromResult<Entries extends Dict> (result: Result): Promise<EagerResult<Entries>> { |
25 | 27 | const { summary, records } = await result |
@@ -66,6 +68,106 @@ class ResultTransformers { |
66 | 68 | eagerResultTransformer<Entries extends Dict = Dict>(): ResultTransformer<EagerResult<Entries>> { |
67 | 69 | return createEagerResultFromResult |
68 | 70 | } |
| 71 | + |
| 72 | + /** |
| 73 | + * Creates a {@link ResultTransformer} which maps the {@link Record} in the result and collects it |
| 74 | + * along with the {@link ResultSummary} and {@link Result#keys}. |
| 75 | + * |
| 76 | + * NOTE: The config object requires map or/and collect to be valid. |
| 77 | + * |
| 78 | + * @example |
| 79 | + * // Mapping the records |
| 80 | + * const { keys, records, summary } = await driver.executeQuery('MATCH (p:Person{ age: $age }) RETURN p.name as name', { age: 25 }, { |
| 81 | + * resultTransformer: neo4j.resultTransformers.mappedResultTransformer({ |
| 82 | + * map(record) { |
| 83 | + * return record.get('name') |
| 84 | + * } |
| 85 | + * }) |
| 86 | + * }) |
| 87 | + * |
| 88 | + * records.forEach(name => console.log(`${name} has 25`)) |
| 89 | + * |
| 90 | + * @example |
| 91 | + * // Mapping records and collect result |
| 92 | + * const names = await driver.executeQuery('MATCH (p:Person{ age: $age }) RETURN p.name as name', { age: 25 }, { |
| 93 | + * resultTransformer: neo4j.resultTransformers.mappedResultTransformer({ |
| 94 | + * map(record) { |
| 95 | + * return record.get('name') |
| 96 | + * }, |
| 97 | + * collect(records, summary, keys) { |
| 98 | + * return records |
| 99 | + * } |
| 100 | + * }) |
| 101 | + * }) |
| 102 | + * |
| 103 | + * names.forEach(name => console.log(`${name} has 25`)) |
| 104 | + * |
| 105 | + * @example |
| 106 | + * // The transformer can be defined one and used everywhere |
| 107 | + * const getRecordsAsObjects = neo4j.resultTransformers.mappedResultTransformer({ |
| 108 | + * map(record) { |
| 109 | + * return record.toObject() |
| 110 | + * }, |
| 111 | + * collect(objects) { |
| 112 | + * return objects |
| 113 | + * } |
| 114 | + * }) |
| 115 | + * |
| 116 | + * // The usage in a driver.executeQuery |
| 117 | + * const objects = await driver.executeQuery('MATCH (p:Person{ age: $age }) RETURN p.name as name', { age: 25 }, { |
| 118 | + * resultTransformer: getRecordsAsObjects |
| 119 | + * }) |
| 120 | + * objects.forEach(object => console.log(`${object.name} has 25`)) |
| 121 | + * |
| 122 | + * |
| 123 | + * // The usage in session.executeRead |
| 124 | + * const objects = await session.executeRead(tx => getRecordsAsObjects(tx.run('MATCH (p:Person{ age: $age }) RETURN p.name as name'))) |
| 125 | + * objects.forEach(object => console.log(`${object.name} has 25`)) |
| 126 | + * |
| 127 | + * @experimental |
| 128 | + * @param {object} config The result transformer configuration |
| 129 | + * @param {function(record:Record):R} [config.map=function(record) { return record }] Method called for mapping each record |
| 130 | + * @param {function(records:R[], summary:ResultSummary, keys:string[]):T} [config.collect=function(records, summary, keys) { return { records, summary, keys }}] Method called for mapping |
| 131 | + * the result data to the transformer output. |
| 132 | + * @returns {ResultTransformer<T>} The result transformer |
| 133 | + * @see {@link Driver#executeQuery} |
| 134 | + */ |
| 135 | + mappedResultTransformer < |
| 136 | + R = Record, T = { records: R[], keys: string[], summary: ResultSummary } |
| 137 | + >(config: { map?: (rec: Record) => R, collect?: (records: R[], summary: ResultSummary, keys: string[]) => T }): ResultTransformer<T> { |
| 138 | + if (config == null || (config.collect == null && config.map == null)) { |
| 139 | + throw newError('Requires a map or/and a collect functions.') |
| 140 | + } |
| 141 | + return async (result: Result) => { |
| 142 | + return await new Promise((resolve, reject) => { |
| 143 | + const state: { keys: string[], records: R[] } = { records: [], keys: [] } |
| 144 | + |
| 145 | + result.subscribe({ |
| 146 | + onKeys (keys: string[]) { |
| 147 | + state.keys = keys |
| 148 | + }, |
| 149 | + onNext (record: Record) { |
| 150 | + if (config.map != null) { |
| 151 | + state.records.push(config.map(record)) |
| 152 | + } else { |
| 153 | + state.records.push(record as unknown as R) |
| 154 | + } |
| 155 | + }, |
| 156 | + onCompleted (summary: ResultSummary) { |
| 157 | + if (config.collect != null) { |
| 158 | + resolve(config.collect(state.records, summary, state.keys)) |
| 159 | + } else { |
| 160 | + const obj = { records: state.records, summary, keys: state.keys } |
| 161 | + resolve(obj as unknown as T) |
| 162 | + } |
| 163 | + }, |
| 164 | + onError (error: Error) { |
| 165 | + reject(error) |
| 166 | + } |
| 167 | + }) |
| 168 | + }) |
| 169 | + } |
| 170 | + } |
69 | 171 | } |
70 | 172 |
|
71 | 173 | /** |
|
0 commit comments