diff --git a/.gitignore b/.gitignore index bd318e3..35c5866 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ jspm_packages # Optional npm cache directory .npm +.package-lock.json + # Optional REPL history .node_repl_history diff --git a/src/linq/enumerable.ts b/src/linq/enumerable.ts index c616dc4..9b19107 100644 --- a/src/linq/enumerable.ts +++ b/src/linq/enumerable.ts @@ -243,11 +243,13 @@ export class Enumerable implements IEnumerable * returns a new IEnumerable of TResult * @param selector */ - public select(selector: (it: TEntity) => TResult): IEnumerable { + public select(selector: (it: TEntity) => TResult): IEnumerable + public select>(selector: string): IEnumerable + public select(selector: string | ((it: TEntity) => Record)): IEnumerable> { if (typeof this.items == 'object' && typeof this.items[Symbol.asyncIterator] == 'function') { - return new Enumerable(new SelectOperator(selector).evaluateAsync(this)); + return new Enumerable(new SelectOperator(selector).evaluateAsync(this)); } else { - return new Enumerable(new SelectOperator(selector).evaluate(this)); + return new Enumerable(new SelectOperator(selector).evaluate(this)); } } diff --git a/src/linq/operators/selectoperator.ts b/src/linq/operators/selectoperator.ts index c2e4f38..4d02e1c 100644 --- a/src/linq/operators/selectoperator.ts +++ b/src/linq/operators/selectoperator.ts @@ -1,8 +1,19 @@ import { Operator, OperatorType } from './operator'; export class SelectOperator extends Operator { - constructor(public selector: (it: TEntity) => {}) { + private selector: (it: TEntity) => {} + + constructor(selector: string | ((it: TEntity) => {})) { super(OperatorType.Select); + + if(typeof selector == 'string') { + let keys = selector ? selector.split(',').map(sel => sel.trim()) : [] + + this.selector = (it) => remapper(keys, it) + } + else { + this.selector = selector + } } public* evaluate(items: Iterable): IterableIterator { @@ -20,4 +31,32 @@ export class SelectOperator extends Operator { yield this.selector(item) } } +} + +function remapper(keys: string[], object: Record): Record { + if(!keys || keys.length == 0) + return object + + let remapped = {}, + groups: { [key: string]: string[] } = {} + + for(let key of keys) { + let match = /([^/]+)\/(.*)/i.exec(key) + + if(match) { + if(!groups[match[1]]) + groups[match[1]] = [] + + groups[match[1]].push(match[2]) + } + else { + remapped[key] = object[key] + } + } + + for(let [prop, keys] of Object.entries(groups)) { + remapped[prop] = remapper(keys, object[prop]) + } + + return remapped } \ No newline at end of file diff --git a/src/test/enumerable.ts b/src/test/enumerable.ts index 045e7ad..612ebcb 100644 --- a/src/test/enumerable.ts +++ b/src/test/enumerable.ts @@ -461,6 +461,16 @@ describe("When using Enumerable", () => { assert.equal(car.model, 'QASHQAI'); }) + it("should be able to convert list by using select by string", () => { + let car = new Enumerable(cars) + .where(it => it.id == 2) + .select('id, type/make') + .first(); + + assert.equal(car.id, 2); + assert.equal(car.type.make, 'NISSAN') + }) + it("should be able to get first Operator by class", () => { let query: Enumerable = new Enumerable();