Skip to content

Commit

Permalink
select operator by string
Browse files Browse the repository at this point in the history
  • Loading branch information
lostfields committed Feb 6, 2020
1 parent 51c75f6 commit c6e0bd8
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jspm_packages
# Optional npm cache directory
.npm

.package-lock.json

# Optional REPL history
.node_repl_history

Expand Down
8 changes: 5 additions & 3 deletions src/linq/enumerable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,13 @@ export class Enumerable<TEntity> implements IEnumerable<TEntity>
* returns a new IEnumerable of TResult
* @param selector
*/
public select<TResult>(selector: (it: TEntity) => TResult): IEnumerable<TResult> {
public select<TResult>(selector: (it: TEntity) => TResult): IEnumerable<TResult>
public select<TResult extends Partial<TEntity>>(selector: string): IEnumerable<TResult>
public select(selector: string | ((it: TEntity) => Record<string, any>)): IEnumerable<Record<string, any>> {
if (typeof this.items == 'object' && typeof this.items[Symbol.asyncIterator] == 'function') {
return new Enumerable<TResult>(new SelectOperator<TEntity>(selector).evaluateAsync(this));
return new Enumerable(new SelectOperator(selector).evaluateAsync(this));
} else {
return new Enumerable<TResult>(new SelectOperator<TEntity>(selector).evaluate(this));
return new Enumerable(new SelectOperator(selector).evaluate(this));
}
}

Expand Down
41 changes: 40 additions & 1 deletion src/linq/operators/selectoperator.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { Operator, OperatorType } from './operator';

export class SelectOperator<TEntity> extends Operator<TEntity> {
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<TEntity>): IterableIterator<any> {
Expand All @@ -20,4 +31,32 @@ export class SelectOperator<TEntity> extends Operator<TEntity> {
yield this.selector(item)
}
}
}

function remapper(keys: string[], object: Record<string, any>): Record<string, any> {
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
}
10 changes: 10 additions & 0 deletions src/test/enumerable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ICar> = new Enumerable<ICar>();

Expand Down

0 comments on commit c6e0bd8

Please sign in to comment.