UNPKG

trader-server

Version:

OData server for testing strategies, simulating and real trading.

886 lines (728 loc) 30.1 kB
import Utils from "./utils"; import Lexer from "./lexer"; import PrimitiveLiteral from "./primitiveLiteral"; import NameOrIdentifier from "./nameOrIdentifier"; import Expressions from "./expressions"; export namespace Query { export function queryOptions(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { let token = Query.queryOption(value, index, metadataContext); if (!token) return; let start = index; index = token.next; let options = []; while (token) { options.push(token); // & if (value[index] !== 0x26) break; index++; token = Query.queryOption(value, index, metadataContext); if (!token) return; index = token.next; } return Lexer.tokenize(value, start, index, { options }, Lexer.TokenType.QueryOptions); } export function queryOption(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { return Query.systemQueryOption(value, index, metadataContext) || Query.aliasAndValue(value, index) || Query.customQueryOption(value, index); } export function systemQueryOption(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { return Query.expand(value, index, metadataContext) || Query.filter(value, index) || Query.format(value, index) || Query.id(value, index) || Query.inlinecount(value, index) || Query.orderby(value, index) || Query.search(value, index) || Query.select(value, index) || Query.skip(value, index) || Query.skiptoken(value, index) || Query.top(value, index); } export function customQueryOption(value: Utils.SourceArray, index: number): Lexer.Token { let key = NameOrIdentifier.odataIdentifier(value, index); if (!key) return; let start = index; index = key.next; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; while (value[index] !== 0x26 && index < value.length) index++; if (index === eq) return; return Lexer.tokenize(value, start, index, { key: key.raw, value: Utils.stringify(value, eq, index) }, Lexer.TokenType.CustomQueryOption); } export function id(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24id")) { index += 5; }else if (Utils.equals(value, index, "$id")) { index += 3; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; while (value[index] !== 0x26 && index < value.length) index++; if (index === eq) return; return Lexer.tokenize(value, start, index, Utils.stringify(value, eq, index), Lexer.TokenType.Id); } export function expand(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24expand")) { index += 9; }else if (Utils.equals(value, index, "$expand")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let items = []; let token = Query.expandItem(value, index, metadataContext); if (!token) return; index = token.next; while (token) { items.push(token); let comma = Lexer.COMMA(value, index); if (comma) { index = comma; token = Query.expandItem(value, index, metadataContext); if (!token) return; index = token.next; }else break; } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.Expand); } export function expandItem(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { let start = index; let star = Lexer.STAR(value, index); if (star) { index = star; let ref = Expressions.refExpr(value, index); if (ref) { index = ref.next; return Lexer.tokenize(value, start, index, { path: "*", ref }, Lexer.TokenType.ExpandItem); } else { let open = Lexer.OPEN(value, index); if (open) { index = open; let token = Query.levels(value, index); if (!token) return; index = token.next; let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { path: "*", levels: token }, Lexer.TokenType.ExpandItem); } } } let path = Query.expandPath(value, index, metadataContext); if (!path) return; index = path.next; let tokenValue: any = { path }; let ref = Expressions.refExpr(value, index); if (ref) { index = ref.next; tokenValue.ref = ref; let open = Lexer.OPEN(value, index); if (open) { index = open; let option = Query.expandRefOption(value, index); if (!option) return; let refOptions = []; while (option) { refOptions.push(option); index = option.next; let semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = Query.expandRefOption(value, index); if (!option) return; }else break; } let close = Lexer.CLOSE(value, index); if (!close) return; index = close; tokenValue.options = refOptions; } } else { let count = Expressions.countExpr(value, index); if (count) { index = count.next; tokenValue.count = count; let open = Lexer.OPEN(value, index); if (open) { index = open; let option = Query.expandCountOption(value, index); if (!option) return; let countOptions = []; while (option) { countOptions.push(option); index = option.next; let semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = Query.expandCountOption(value, index); if (!option) return; }else break; } let close = Lexer.CLOSE(value, index); if (!close) return; index = close; tokenValue.options = countOptions; } } else { let open = Lexer.OPEN(value, index); if (open) { index = open; let option = Query.expandOption(value, index); if (!option) return; let options = []; while (option) { options.push(option); index = option.next; let semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = Query.expandOption(value, index); if (!option) return; }else break; } let close = Lexer.CLOSE(value, index); if (!close) return; index = close; tokenValue.options = options; } } } return Lexer.tokenize(value, start, index, tokenValue, Lexer.TokenType.ExpandItem); } export function expandCountOption(value: Utils.SourceArray, index: number): Lexer.Token { return Query.filter(value, index) || Query.search(value, index); } export function expandRefOption(value: Utils.SourceArray, index: number): Lexer.Token { return Query.expandCountOption(value, index) || Query.orderby(value, index) || Query.skip(value, index) || Query.top(value, index) || Query.inlinecount(value, index); } export function expandOption(value: Utils.SourceArray, index: number): Lexer.Token { return Query.expandRefOption(value, index) || Query.select(value, index) || Query.expand(value, index) || Query.levels(value, index); } export function expandPath(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { let start = index; let path = []; let token = NameOrIdentifier.qualifiedEntityTypeName(value, index, metadataContext) || NameOrIdentifier.qualifiedComplexTypeName(value, index, metadataContext); if (token) { index = token.next; path.push(token); if (value[index] !== 0x2f) return; index++; metadataContext = token.value.metadata; delete token.value.metadata; } let complex = NameOrIdentifier.complexProperty(value, index, metadataContext) || NameOrIdentifier.complexColProperty(value, index, metadataContext); while (complex) { if (value[complex.next] === 0x2f) { index = complex.next + 1; path.push(complex); let complexTypeName = NameOrIdentifier.qualifiedComplexTypeName(value, index, metadataContext); if (complexTypeName) { if (value[complexTypeName.next] === 0x2f) { index = complexTypeName.next + 1; path.push(complexTypeName); } metadataContext = complexTypeName.value.metadata; delete complexTypeName.value.metadata; } complex = NameOrIdentifier.complexProperty(value, index, metadataContext) || NameOrIdentifier.complexColProperty(value, index, metadataContext); }else break; } let nav = NameOrIdentifier.navigationProperty(value, index, metadataContext); if (!nav) return; index = nav.next; path.push(nav); metadataContext = nav.metadata; delete nav.metadata; if (value[index] === 0x2f) { let typeName = NameOrIdentifier.qualifiedEntityTypeName(value, index + 1, metadataContext); if (typeName) { index = typeName.next; path.push(typeName); metadataContext = typeName.value.metadata; delete typeName.value.metadata; } } return Lexer.tokenize(value, start, index, path, Lexer.TokenType.ExpandPath); } export function search(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24search")) { index += 9; }else if (Utils.equals(value, index, "$search")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let expr = Query.searchExpr(value, index); if (!expr) return; index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.Search); } export function searchExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = Query.searchParenExpr(value, index) || Query.searchTerm(value, index); if (!token) return; let start = index; index = token.next; let expr = Query.searchAndExpr(value, index) || Query.searchOrExpr(value, index); if (expr) { const left = Lexer.clone(token); token.next = expr.value.next; token.value = { left: left, right: expr.value }; token.type = expr.type; token.raw = Utils.stringify(value, token.position, token.next); if (token.type === Lexer.TokenType.SearchAndExpression && token.value.right.type === Lexer.TokenType.SearchOrExpression) { token.value.left = Lexer.tokenize(value, token.value.left.position, token.value.right.value.left.next, { left: token.value.left, right: token.value.right.value.left }, token.type); token.type = token.value.right.type; token.value.right = token.value.right.value.right; } } return token; } export function searchTerm(value: Utils.SourceArray, index: number): Lexer.Token { return Query.searchNotExpr(value, index) || Query.searchPhrase(value, index) || Query.searchWord(value, index); } export function searchNotExpr(value: Utils.SourceArray, index: number): Lexer.Token { let rws = Lexer.RWS(value, index); if (!Utils.equals(value, rws, "NOT")) return; let start = index; index = rws + 3; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let expr = Query.searchPhrase(value, index) || Query.searchWord(value, index); if (!expr) return; index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.SearchNotExpression); } export function searchOrExpr(value: Utils.SourceArray, index: number): Lexer.Token { let rws = Lexer.RWS(value, index); if (rws === index || !Utils.equals(value, rws, "OR")) return; let start = index; index = rws + 2; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = Query.searchExpr(value, index); if (!token) return; index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.SearchOrExpression); } export function searchAndExpr(value: Utils.SourceArray, index: number): Lexer.Token { let rws = Lexer.RWS(value, index); if (rws === index || !Utils.equals(value, rws, "AND")) return; let start = index; index = rws + 3; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = Query.searchExpr(value, index); if (!token) return; index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.SearchAndExpression); } export function searchPhrase(value: Utils.SourceArray, index: number): Lexer.Token { let mark = Lexer.quotationMark(value, index); if (mark === index) return; let start = index; index = mark; let valueStart = index; let ch = Lexer.qcharNoAMPDQUOTE(value, index); while (ch > index && !Lexer.OPEN(value, index) && !Lexer.CLOSE(value, index)) { index = ch; ch = Lexer.qcharNoAMPDQUOTE(value, index); } let valueEnd = index; mark = Lexer.quotationMark(value, index); if (!mark) return; index = mark; return Lexer.tokenize(value, start, index, Utils.stringify(value, valueStart, valueEnd), Lexer.TokenType.SearchPhrase); } export function searchWord(value: Utils.SourceArray, index: number): Lexer.Token { let next = Utils.required(value, index, Lexer.ALPHA, 1); if (!next) return; let start = index; index = next; let token = Lexer.tokenize(value, start, index, null, Lexer.TokenType.SearchWord); token.value = token.raw; return token; } export function searchParenExpr(value: Utils.SourceArray, index: number): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; index = Lexer.BWS(value, index); let expr = Query.searchExpr(value, index); if (!expr) return; index = expr.next; index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.SearchParenExpression); } export function levels(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24levels")) { index += 9; }else if (Utils.equals(value, index, "$levels")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let level; if (Utils.equals(value, index, "max")) { level = "max"; index += 3; } else { let token = PrimitiveLiteral.int32Value(value, index); if (!token) return; level = token.raw; index = token.next; } return Lexer.tokenize(value, start, index, level, Lexer.TokenType.Levels); } export function filter(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24filter")) { index += 9; }else if (Utils.equals(value, index, "$filter")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let expr = Expressions.boolCommonExpr(value, index); if (!expr) return; index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.Filter); } export function orderby(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24orderby")) { index += 10; }else if (Utils.equals(value, index, "$orderby")) { index += 8; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let items = []; let token = Query.orderbyItem(value, index); if (!token) return; index = token.next; while (token) { items.push(token); let comma = Lexer.COMMA(value, index); if (comma) { index = comma; token = Query.orderbyItem(value, index); if (!token) return; index = token.next; }else break; } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.OrderBy); } export function orderbyItem(value: Utils.SourceArray, index: number): Lexer.Token { let expr = Expressions.commonExpr(value, index); if (!expr) return; let start = index; index = expr.next; let direction = 1; let rws = Lexer.RWS(value, index); if (rws > index) { index = rws; if (Utils.equals(value, index, "asc")) index += 3; else if (Utils.equals(value, index, "desc")) { index += 4; direction = -1; }else return; } return Lexer.tokenize(value, start, index, { expr, direction }, Lexer.TokenType.OrderByItem); } export function skip(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24skip")) { index += 7; }else if (Utils.equals(value, index, "$skip")) { index += 5; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let token = PrimitiveLiteral.int32Value(value, index); if (!token) return; index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.Skip); } export function top(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24top")) { index += 6; }else if (Utils.equals(value, index, "$top")) { index += 4; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let token = PrimitiveLiteral.int32Value(value, index); if (!token) return; index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.Top); } export function format(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24format")) { index += 9; }else if (Utils.equals(value, index, "$format")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let format; if (Utils.equals(value, index, "atom")) { format = "atom"; index += 4; }else if (Utils.equals(value, index, "json")) { format = "json"; index += 4; }else if (Utils.equals(value, index, "xml")) { format = "xml"; index += 3; } if (format) return Lexer.tokenize(value, start, index, { format }, Lexer.TokenType.Format); } export function inlinecount(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24count")) { index += 8; }else if (Utils.equals(value, index, "$count")) { index += 6; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let token = PrimitiveLiteral.booleanValue(value, index); if (!token) return; index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.InlineCount); } export function select(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24select")) { index += 9; }else if (Utils.equals(value, index, "$select")) { index += 7; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let items = []; let token = Query.selectItem(value, index); if (!token) return; while (token) { items.push(token); index = token.next; let comma = Lexer.COMMA(value, index); if (comma) { index = comma; token = Query.selectItem(value, index); if (!token) return; }else break; } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.Select); } export function selectItem(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; let item; let op = Query.allOperationsInSchema(value, index); let star = Lexer.STAR(value, index); if (op > index) { item = { namespace: Utils.stringify(value, index, op - 2), value: "*" }; index = op; }else if (star) { item = { value: "*" }; index = star; } else { item = {}; let name = NameOrIdentifier.qualifiedEntityTypeName(value, index) || NameOrIdentifier.qualifiedComplexTypeName(value, index); if (name && value[name.next] !== 0x2f) return; else if (name && value[name.next] === 0x2f) { index++; item.name = name; } let select = Query.selectProperty(value, index) || Query.qualifiedActionName(value, index) || Query.qualifiedFunctionName(value, index); if (!select) return; index = select.next; item = name ? { name, select } : select; } if (index > start) return Lexer.tokenize(value, start, index, item, Lexer.TokenType.SelectItem); } export function allOperationsInSchema(value: Utils.SourceArray, index: number): number { let namespaceNext = NameOrIdentifier.namespace(value, index); let star = Lexer.STAR(value, namespaceNext + 1); if (namespaceNext > index && value[namespaceNext] === 0x2e && star) return star; return index; } export function selectProperty(value: Utils.SourceArray, index: number): Lexer.Token { let token = Query.selectPath(value, index) || NameOrIdentifier.primitiveProperty(value, index) || NameOrIdentifier.primitiveColProperty(value, index) || NameOrIdentifier.navigationProperty(value, index); if (!token) return; let start = index; index = token.next; if (token.type === Lexer.TokenType.SelectPath) { if (value[index] === 0x2f) { index++; let prop = Query.selectProperty(value, index); if (!prop) return; let path = Lexer.clone(token); token.next = prop.next; token.raw = Utils.stringify(value, start, token.next); token.value = { path, next: prop }; } } return token; } export function selectPath(value: Utils.SourceArray, index: number): Lexer.Token { let token = NameOrIdentifier.complexProperty(value, index) || NameOrIdentifier.complexColProperty(value, index); if (!token) return; let start = index; index = token.next; let tokenValue: any = token; if (value[index] === 0x2f) { let name = NameOrIdentifier.qualifiedComplexTypeName(value, index + 1); if (name) { index = name.next; tokenValue = { prop: token, name }; } } return Lexer.tokenize(value, start, index, tokenValue, Lexer.TokenType.SelectPath); } export function qualifiedActionName(value: Utils.SourceArray, index: number): Lexer.Token { let namespaceNext = NameOrIdentifier.namespace(value, index); if (namespaceNext === index || value[namespaceNext] !== 0x2e) return; let start = index; index = namespaceNext + 1; let action = NameOrIdentifier.action(value, index); if (!action) return; action.value.namespace = Utils.stringify(value, start, namespaceNext); return Lexer.tokenize(value, start, action.next, action, Lexer.TokenType.Action); } export function qualifiedFunctionName(value: Utils.SourceArray, index: number): Lexer.Token { let namespaceNext = NameOrIdentifier.namespace(value, index); if (namespaceNext === index || value[namespaceNext] !== 0x2e) return; let start = index; index = namespaceNext + 1; let fn = NameOrIdentifier.odataFunction(value, index); if (!fn) return; fn.value.namespace = Utils.stringify(value, start, namespaceNext); index = fn.next; let tokenValue: any = { name: fn }; let open = Lexer.OPEN(value, index); if (open) { index = open; tokenValue.parameters = []; let param = Expressions.parameterName(value, index); if (!param) return; while (param) { index = param.next; tokenValue.parameters.push(param); let comma = Lexer.COMMA(value, index); if (comma) { index = comma; let param = Expressions.parameterName(value, index); if (!param) return; }else break; } let close = Lexer.CLOSE(value, index); if (!close) return; index = close; } return Lexer.tokenize(value, start, index, tokenValue, Lexer.TokenType.Function); } export function skiptoken(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; if (Utils.equals(value, index, "%24skiptoken")) { index += 12; }else if (Utils.equals(value, index, "$skiptoken")) { index += 10; }else return; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let ch = Lexer.qcharNoAMP(value, index); if (!ch) return; let valueStart = index; while (ch > index) { index = ch; ch = Lexer.qcharNoAMP(value, index); } return Lexer.tokenize(value, start, index, Utils.stringify(value, valueStart, index), Lexer.TokenType.SkipToken); } export function aliasAndValue(value: Utils.SourceArray, index: number): Lexer.Token { let alias = Expressions.parameterAlias(value, index); if (!alias) return; let start = index; index = alias.next; let eq = Lexer.EQ(value, index); if (!eq) return; index = eq; let paramValue = Expressions.parameterValue(value, index); if (!paramValue) return; index = paramValue.next; return Lexer.tokenize(value, start, index, { alias, value: paramValue }, Lexer.TokenType.AliasAndValue); } } export default Query;