Skip to content

Commit

Permalink
Merge pull request #8 from tfso/feature/translator
Browse files Browse the repository at this point in the history
feature/translator
  • Loading branch information
lostfields authored Jan 29, 2021
2 parents 5ef25da + 592dfa9 commit 7e828ae
Show file tree
Hide file tree
Showing 19 changed files with 778 additions and 403 deletions.
2 changes: 1 addition & 1 deletion src/linq/operator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type LinqOperatorSkip = { type: LinqType.Skip, count: number }
type LinqOperatorTake = { type: LinqType.Take, count: number }
type LinqOperatorSlice = { type: LinqType.Slice, begin: number | string, end?: number }
type LinqOperatorIncludes<T extends Entity = Entity> = { type: LinqType.Includes, entity: Partial<T> }
type LinqOperatorWhere<T extends Entity = Entity> = { type: LinqType.Where, expression: IExpression, readonly intersection: IterableIterator<WhereExpression>, readonly sets: IterableIterator<IterableIterator<WhereExpression>> }
type LinqOperatorWhere<T extends Entity = Entity> = { type: LinqType.Where, expression: IExpression, readonly intersection: IterableIterator<WhereExpression>, readonly sets: IterableIterator<IterableIterator<WhereExpression>>, toString(language?: 'javascript' | 'odata' | 'raw'): string }
type LinqOperatorOrderBy<T extends Entity = Entity> = { type: LinqType.OrderBy, property: undefined | keyof T | string }
type LinqOperatorSelect = { type: LinqType.Select }

Expand Down
35 changes: 28 additions & 7 deletions src/linq/operator/whereoperator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import { ODataVisitor } from './../peg/odatavisitor'
import { LogicalExpression } from './../peg/expression/logicalexpression'
import { LiteralExpression } from './../peg/expression/literalexpression'

import { ODataTranslator } from './../peg/translator/odatatranslator'

export function whereOperator<TEntity extends Entity>(predicate: string): LinqOperator<TEntity>
export function whereOperator<TEntity extends Entity>(predicate: (it: TEntity, ...param: any[]) => boolean, ...param: any[]): LinqOperator<TEntity>
export function whereOperator<TEntity extends Entity>(): LinqOperator<TEntity> {
let predicate: any = arguments[0],
parameters: Array<any> = [],
expression: IExpression,
original: string,
type: 'odata' | 'javascript',
validate: (entity: TEntity) => boolean,
scopeName: string

Expand All @@ -22,25 +26,23 @@ export function whereOperator<TEntity extends Entity>(): LinqOperator<TEntity> {

switch(typeof predicate) {
case 'string':
expression = new ODataVisitor().parseOData(predicate)
({ type, expression, original } = new ODataVisitor().parse('odata', predicate))

validate = (entity: TEntity) => ODataVisitor.evaluate(expression, entity) === true
scopeName = ''

break

case 'function':
let visitor = new ReducerVisitor()

expression = visitor.parseLambda(predicate, ...parameters)
({ type, expression, original } = new ReducerVisitor().parse('javascript', predicate, ...parameters))

validate = (entity: TEntity) => predicate.apply({}, [entity].concat(parameters))
if(LambdaExpression.instanceof(expression)) {
if(expression.parameters[0].type == ExpressionType.Identifier) {
scopeName = (<IIdentifierExpression>expression.parameters[0]).name
}
}

validate = (entity: TEntity) => predicate.apply({}, [entity].concat(parameters))


break

default:
Expand Down Expand Up @@ -70,6 +72,25 @@ export function whereOperator<TEntity extends Entity>(): LinqOperator<TEntity> {
}

return visit()
},
toString: (language?: 'javascript' | 'odata' | 'raw') => {
switch(language ?? type) {
case 'javascript':
if(type == 'javascript')
return expression.toString()

throw new Error('OData to javascript translator is not implemented')

case 'odata':
if(type == 'odata')
return new ODataTranslator().visit(expression)

throw new Error('Javascript to odata translator is not implemented')

default:
case 'raw':
return original
}
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/linq/peg/expression/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import { ILambdaExpression } from '../interface/ilambdaexpression'

import { IExpressionVisitor } from '../interface/iexpressionvisitor'

export abstract class IAccept {

}

export abstract class Expression implements IExpression {
private _type: ExpressionType;

Expand All @@ -33,8 +37,8 @@ export abstract class Expression implements IExpression {
this._type = value
}

public accept<T extends IExpressionVisitor>(visitor: T) {
let expression: IExpression
public accept<V, T extends IExpressionVisitor<V>>(visitor: T) {
let expression: V

// add this as parent to stack for next acceptance/visit
visitor.stack.push(this)
Expand Down
38 changes: 38 additions & 0 deletions src/linq/peg/expressionstack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { IExpression } from './interface/iexpression'
import { IExpressionStack } from './interface/iexpressionstack'

export class ExpressionStack implements IExpressionStack {
private items: Array<IExpression>
private count: number

constructor() {
this.items = []
this.count = 0
}

public length() {
return this.count
}

public push(item: IExpression) {
this.items.push(item)
this.count = this.count + 1
}

public pop(): IExpression {
if(this.count > 0) {
this.count = this.count - 1
}

return this.items.pop()
}

public peek(steps = 0): IExpression {
if((this.count + steps) <= 1)
return <any>{ // dummy
type: 0
}

return this.items[this.count - 2 + steps] // current object is always last
}
}
Loading

0 comments on commit 7e828ae

Please sign in to comment.