Last active
March 30, 2020 15:36
-
-
Save robertpitt/335235ad1199e74e41a1790901c178ed to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { pipeline } from 'pipe-and-compose'; | |
import * as path from 'object-path'; | |
/** | |
* A deduction can been seen as synonymous with a transformation, except that | |
* a deduction also performs movement of the source value(s) via a sequence of reducers | |
* to the destination in the output object. | |
*/ | |
export type Deduction<I, O> = { | |
/** | |
* Source path is the location of the property in the source object, | |
* this can also be an array of paths in order to select multiple values | |
* from the source, this is useful for for separate time and date fields | |
* or calculating the total from separate price and tax rate. | |
* | |
* If the source object is an array, you can use integers or array of integers | |
* to select values, this is useful for selecting columns with leaderless csv files. | |
* | |
* If the source object is an object you can use string or array of strings | |
* to select values. | |
* | |
* @example { source: "_id", destination: "id" } | |
* @example { source: ["date", "time"], destination: "dateTime", reducers: [ makeDateTime ] } | |
* @example { source: 1, destination: "id" } | |
* @example { source: [2, 3], destination: "dateTime", reducers: [ madeDateTime ] } | |
*/ | |
source: keyof I | keyof I[] | (string | number)[]; | |
/** | |
* Destination is a string value containing the index you want to save the | |
* value to within the output. | |
* | |
* @example { source: "_id", destination: "id" } | |
* @example { source: ["date", "time"], destination: "dateTime", reducers: [ makeDateTime ] } | |
* @example { source: 1, destination: "id" } | |
* @example { source: [2, 3], destination: "dateTime", reducers: [ madeDateTime ] } | |
*/ | |
destination: keyof O | path.Path; | |
/** | |
* Reducers contain an array of functions that are executed using a pipe, | |
* pipe is the exact same as compose apart from ut uses reducerRight instead of reduce, | |
* effectively switching the execution from rtl to ltr. | |
* | |
* @example [ | |
* toString, | |
* toUpperCase, | |
* remove('-', '_', ''), | |
* ] | |
*/ | |
reducers?: Array<(a: unknown) => unknown>; | |
}; | |
/** | |
* deduce is a function that executes a set of deductions against an input source, | |
* each deduction will be responsible for selecting one or more values from the input source | |
* and specifying the destination key in the output object. | |
* | |
* Deductions are executed sequentially in array order, each deduction will fully | |
* complete before the next deduction is executed, during the execution of the deduction | |
* the reducer pipeline will be invoked with the initial source value, the final | |
* result of the reducer pipeline will be stored in the destination key of hte output object | |
* | |
* @param input Array or Object that is the input source. | |
* @param deductions An array of Deductions that will be executed sequentially. | |
*/ | |
export const deduce = <I extends object, O extends object>( | |
input: I, | |
deductions: Deduction<I, O>[], | |
): O => { | |
return deductions.reduce<O>((o, { source, destination, reducers = [] }) => { | |
// Create a new transform stack that will process the current value | |
const transform = pipeline( | |
Array.isArray(source) | |
? source.map(k => path.get(input, k)) | |
: path.get(input, source as path.Path), | |
v => v, | |
...reducers, | |
); | |
// Execute the pipeline and set the result to the target key on the output object | |
path.set(o, destination as string, transform); | |
return o; | |
}, Object.create({})); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { deduce, Deduction } from './deduce'; | |
const toUpperCase = v => typeof v === "string" ? v.toUpperCase() : v; | |
const parserFormattedDateTimeTupple = ([date, time]) => new Date(); // would normally be parsed. | |
const input = ["abc123", "Mr J Doe", "20200331", "1230", "20200407", "1230"] | |
const result = deduce(input, [ | |
{ | |
source: 0, | |
destination: "reference", | |
reducers: [ toUpperCase ] | |
}, | |
{ | |
source: 1, | |
destiantion: "customer.name" | |
}, | |
{ | |
source: [2, 3], | |
destiantion: "bookingStartDate", | |
reducers: [ parserFormattedDateTimeTupple ] | |
}, | |
{ | |
source: [4, 5], | |
destiantion: "bookingEndDate", | |
reducers: [ parserFormattedDateTimeTupple ] | |
} | |
]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment