UNPKG

@odata/parser

Version:
1,028 lines 31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.aliasAndValue = exports.skiptoken = exports.qualifiedFunctionName = exports.qualifiedActionName = exports.selectPath = exports.selectProperty = exports.allOperationsInSchema = exports.selectItem = exports.select = exports.inlinecount = exports.format = exports.top = exports.skip = exports.orderbyItem = exports.orderby = exports.filter = exports.levels = exports.searchParenExpr = exports.searchWord = exports.searchPhrase = exports.searchAndExpr = exports.searchOrExpr = exports.searchNotExpr = exports.searchTerm = exports.searchExpr = exports.search = exports.expandPath = exports.expandOption = exports.expandRefOption = exports.expandCountOption = exports.expandItem = exports.expand = exports.id = exports.customQueryOption = exports.systemQueryOption = exports.queryOption = exports.queryOptions = void 0; const Expressions = require("./expressions"); const Lexer = require("./lexer"); const NameOrIdentifier = require("./nameOrIdentifier"); const PrimitiveLiteral = require("./primitiveLiteral"); const utils_1 = require("./utils"); function queryOptions(value, index, metadataContext) { if (value.length <= index) { return Lexer.tokenize(value, index, index, { options: null }, Lexer.TokenType.QueryOptions); } let token = queryOption(value, index, metadataContext); if (!token) { return; } const start = index; index = token.next; const options = []; while (token) { options.push(token); // & if (value[index] !== 0x26) { break; } index++; token = queryOption(value, index, metadataContext); if (!token) { return; } index = token.next; } return Lexer.tokenize(value, start, index, { options }, Lexer.TokenType.QueryOptions); } exports.queryOptions = queryOptions; function queryOption(value, index, metadataContext) { return (systemQueryOption(value, index, metadataContext) || aliasAndValue(value, index) || customQueryOption(value, index)); } exports.queryOption = queryOption; function systemQueryOption(value, index, metadataContext) { return (expand(value, index, metadataContext) || filter(value, index) || format(value, index) || id(value, index) || inlinecount(value, index) || orderby(value, index) || search(value, index) || select(value, index) || skip(value, index) || skiptoken(value, index) || top(value, index)); } exports.systemQueryOption = systemQueryOption; function customQueryOption(value, index) { const key = NameOrIdentifier.odataIdentifier(value, index); if (!key) { return; } const start = index; index = key.next; const 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_1.default.stringify(value, eq, index) }, Lexer.TokenType.CustomQueryOption); } exports.customQueryOption = customQueryOption; function id(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24id')) { index += 5; } else if (utils_1.default.equals(value, index, '$id')) { index += 3; } else { return; } const 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_1.default.stringify(value, eq, index), Lexer.TokenType.Id); } exports.id = id; function expand(value, index, metadataContext) { const start = index; if (utils_1.default.equals(value, index, '%24expand')) { index += 9; } else if (utils_1.default.equals(value, index, '$expand')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const items = []; let token = expandItem(value, index, metadataContext); if (!token) { return; } index = token.next; while (token) { items.push(token); const comma = Lexer.COMMA(value, index); if (comma) { index = comma; token = expandItem(value, index, metadataContext); if (!token) { return; } index = token.next; } else { break; } } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.Expand); } exports.expand = expand; function expandItem(value, index, metadataContext) { const start = index; const star = Lexer.STAR(value, index); if (star) { index = star; if (index == value.length) { return Lexer.tokenize(value, start, index, { path: '*' }, Lexer.TokenType.ExpandItem); } const ref = Expressions.refExpr(value, index); if (ref) { index = ref.next; return Lexer.tokenize(value, start, index, { path: '*', ref }, Lexer.TokenType.ExpandItem); } const open = Lexer.OPEN(value, index); if (open) { index = open; const token = levels(value, index); if (!token) { return; } index = token.next; const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; return Lexer.tokenize(value, start, index, { path: '*', levels: token }, Lexer.TokenType.ExpandItem); } } const path = expandPath(value, index, metadataContext); if (!path) { return; } index = path.next; const tokenValue = { path }; const ref = Expressions.refExpr(value, index); if (ref) { index = ref.next; tokenValue.ref = ref; const open = Lexer.OPEN(value, index); if (open) { index = open; let option = expandRefOption(value, index); if (!option) { return; } const refOptions = []; while (option) { refOptions.push(option); index = option.next; const semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = expandRefOption(value, index); if (!option) { return; } } else { break; } } const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; tokenValue.options = refOptions; } } else { const count = Expressions.countExpr(value, index); if (count) { index = count.next; tokenValue.count = count; const open = Lexer.OPEN(value, index); if (open) { index = open; let option = expandCountOption(value, index); if (!option) { return; } const countOptions = []; while (option) { countOptions.push(option); index = option.next; const semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = expandCountOption(value, index); if (!option) { return; } } else { break; } } const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; tokenValue.options = countOptions; } } else { const open = Lexer.OPEN(value, index); if (open) { index = open; let option = expandOption(value, index); if (!option) { return; } const options = []; while (option) { options.push(option); index = option.next; const semi = Lexer.SEMI(value, index); if (semi) { index = semi; option = expandOption(value, index); if (!option) { return; } } else { break; } } const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; tokenValue.options = options; } } } return Lexer.tokenize(value, start, index, tokenValue, Lexer.TokenType.ExpandItem); } exports.expandItem = expandItem; function expandCountOption(value, index) { return filter(value, index) || search(value, index); } exports.expandCountOption = expandCountOption; function expandRefOption(value, index) { return (expandCountOption(value, index) || orderby(value, index) || skip(value, index) || top(value, index) || inlinecount(value, index)); } exports.expandRefOption = expandRefOption; function expandOption(value, index) { return (expandRefOption(value, index) || select(value, index) || expand(value, index) || levels(value, index)); } exports.expandOption = expandOption; function expandPath(value, index, metadataContext) { const start = index; const path = []; const 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); const 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; } } const 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) { const 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); } exports.expandPath = expandPath; function search(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24search')) { index += 9; } else if (utils_1.default.equals(value, index, '$search')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const expr = searchExpr(value, index); if (!expr) { return; } index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.Search); } exports.search = search; function searchExpr(value, index) { const token = searchParenExpr(value, index) || searchTerm(value, index); if (!token) { return; } const start = index; index = token.next; const expr = searchAndExpr(value, index) || searchOrExpr(value, index); if (expr) { const left = Lexer.clone(token); token.next = expr.value.next; token.value = { left, right: expr.value }; token.type = expr.type; token.raw = utils_1.default.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; } exports.searchExpr = searchExpr; function searchTerm(value, index) { return (searchNotExpr(value, index) || searchPhrase(value, index) || searchWord(value, index)); } exports.searchTerm = searchTerm; function searchNotExpr(value, index) { let rws = Lexer.RWS(value, index); if (!utils_1.default.equals(value, rws, 'NOT')) { return; } const start = index; index = rws + 3; rws = Lexer.RWS(value, index); if (rws === index) { return; } index = rws; const expr = searchPhrase(value, index) || searchWord(value, index); if (!expr) { return; } index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.SearchNotExpression); } exports.searchNotExpr = searchNotExpr; function searchOrExpr(value, index) { let rws = Lexer.RWS(value, index); if (rws === index || !utils_1.default.equals(value, rws, 'OR')) { return; } const start = index; index = rws + 2; rws = Lexer.RWS(value, index); if (rws === index) { return; } index = rws; const token = searchExpr(value, index); if (!token) { return; } index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.SearchOrExpression); } exports.searchOrExpr = searchOrExpr; function searchAndExpr(value, index) { let rws = Lexer.RWS(value, index); if (rws === index || !utils_1.default.equals(value, rws, 'AND')) { return; } const start = index; index = rws + 3; rws = Lexer.RWS(value, index); if (rws === index) { return; } index = rws; const token = searchExpr(value, index); if (!token) { return; } index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.SearchAndExpression); } exports.searchAndExpr = searchAndExpr; function searchPhrase(value, index) { let mark = Lexer.quotationMark(value, index); if (mark === index) { return; } const start = index; index = mark; const 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); } const valueEnd = index; mark = Lexer.quotationMark(value, index); if (!mark) { return; } index = mark; return Lexer.tokenize(value, start, index, utils_1.default.stringify(value, valueStart, valueEnd), Lexer.TokenType.SearchPhrase); } exports.searchPhrase = searchPhrase; function searchWord(value, index) { const next = utils_1.default.required(value, index, Lexer.ALPHA, 1); if (!next) { return; } const start = index; index = next; const token = Lexer.tokenize(value, start, index, null, Lexer.TokenType.SearchWord); token.value = token.raw; return token; } exports.searchWord = searchWord; function searchParenExpr(value, index) { const open = Lexer.OPEN(value, index); if (!open) { return; } const start = index; index = open; index = Lexer.BWS(value, index); const expr = searchExpr(value, index); if (!expr) { return; } index = expr.next; index = Lexer.BWS(value, index); const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.SearchParenExpression); } exports.searchParenExpr = searchParenExpr; function levels(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24levels')) { index += 9; } else if (utils_1.default.equals(value, index, '$levels')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; let level; if (utils_1.default.equals(value, index, 'max')) { level = 'max'; index += 3; } else { const token = PrimitiveLiteral.int32Value(value, index); if (!token) { return; } level = token.raw; index = token.next; } return Lexer.tokenize(value, start, index, level, Lexer.TokenType.Levels); } exports.levels = levels; function filter(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24filter')) { index += 9; } else if (utils_1.default.equals(value, index, '$filter')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const expr = Expressions.boolCommonExpr(value, index); if (!expr) { return; } index = expr.next; return Lexer.tokenize(value, start, index, expr, Lexer.TokenType.Filter); } exports.filter = filter; function orderby(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24orderby')) { index += 10; } else if (utils_1.default.equals(value, index, '$orderby')) { index += 8; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const items = []; let token = orderbyItem(value, index); if (!token) { return; } index = token.next; while (token) { items.push(token); const comma = Lexer.COMMA(value, index); if (comma) { index = comma; const space = Lexer.OWS(value, index); if (space) { index = space; } token = orderbyItem(value, index); if (!token) { return; } index = token.next; } else { break; } } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.OrderBy); } exports.orderby = orderby; function orderbyItem(value, index) { const expr = Expressions.commonExpr(value, index); if (!expr) { return; } const start = index; index = expr.next; let direction = 1; const rws = Lexer.RWS(value, index); if (rws > index) { index = rws; if (utils_1.default.equals(value, index, 'asc')) { index += 3; } else if (utils_1.default.equals(value, index, 'desc')) { index += 4; direction = -1; } else { return; } } return Lexer.tokenize(value, start, index, { expr, direction }, Lexer.TokenType.OrderByItem); } exports.orderbyItem = orderbyItem; function skip(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24skip')) { index += 7; } else if (utils_1.default.equals(value, index, '$skip')) { index += 5; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const token = PrimitiveLiteral.int32Value(value, index); if (!token) { return; } index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.Skip); } exports.skip = skip; function top(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24top')) { index += 6; } else if (utils_1.default.equals(value, index, '$top')) { index += 4; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const token = PrimitiveLiteral.int32Value(value, index); if (!token) { return; } index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.Top); } exports.top = top; function format(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24format')) { index += 9; } else if (utils_1.default.equals(value, index, '$format')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; let format; if (utils_1.default.equals(value, index, 'atom')) { format = 'atom'; index += 4; } else if (utils_1.default.equals(value, index, 'json')) { format = 'json'; index += 4; } else if (utils_1.default.equals(value, index, 'JSON')) { format = 'json'; index += 4; } else if (utils_1.default.equals(value, index, 'xml')) { format = 'xml'; index += 3; } else if (utils_1.default.equals(value, index, 'text/html')) { format = 'xml'; index += 9; } if (format) { return Lexer.tokenize(value, start, index, { format }, Lexer.TokenType.Format); } } exports.format = format; function inlinecount(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24count')) { index += 8; } else if (utils_1.default.equals(value, index, '$count')) { index += 6; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const token = PrimitiveLiteral.booleanValue(value, index); if (!token) { return; } index = token.next; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.InlineCount); } exports.inlinecount = inlinecount; function select(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24select')) { index += 9; } else if (utils_1.default.equals(value, index, '$select')) { index += 7; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const items = []; let token = selectItem(value, index); if (!token) { return; } while (token) { items.push(token); index = token.next; const comma = Lexer.COMMA(value, index); if (comma) { index = comma; const space = Lexer.OWS(value, index); if (space) { index = space; } token = selectItem(value, index); if (!token) { return; } } else { break; } } return Lexer.tokenize(value, start, index, { items }, Lexer.TokenType.Select); } exports.select = select; function selectItem(value, index) { const start = index; let item; const op = allOperationsInSchema(value, index); const star = Lexer.STAR(value, index); if (op > index) { item = { namespace: utils_1.default.stringify(value, index, op - 2), value: '*' }; index = op; } else if (star) { item = { value: '*' }; index = star; } else { item = {}; const 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; } const select = selectProperty(value, index) || qualifiedActionName(value, index) || 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); } } exports.selectItem = selectItem; function allOperationsInSchema(value, index) { const namespaceNext = NameOrIdentifier.namespace(value, index); const star = Lexer.STAR(value, namespaceNext + 1); if (namespaceNext > index && value[namespaceNext] === 0x2e && star) { return star; } return index; } exports.allOperationsInSchema = allOperationsInSchema; function selectProperty(value, index) { const token = selectPath(value, index) || NameOrIdentifier.primitiveProperty(value, index) || NameOrIdentifier.primitiveColProperty(value, index) || NameOrIdentifier.navigationProperty(value, index); if (!token) { return; } const start = index; index = token.next; if (token.type === Lexer.TokenType.SelectPath) { if (value[index] === 0x2f) { index++; const prop = selectProperty(value, index); if (!prop) { return; } const path = Lexer.clone(token); token.next = prop.next; token.raw = utils_1.default.stringify(value, start, token.next); token.value = { path, next: prop }; } } return token; } exports.selectProperty = selectProperty; function selectPath(value, index) { const token = NameOrIdentifier.complexProperty(value, index) || NameOrIdentifier.complexColProperty(value, index); if (!token) { return; } const start = index; index = token.next; let tokenValue = token; if (value[index] === 0x2f) { const 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); } exports.selectPath = selectPath; function qualifiedActionName(value, index) { const namespaceNext = NameOrIdentifier.namespace(value, index); if (namespaceNext === index || value[namespaceNext] !== 0x2e) { return; } const start = index; index = namespaceNext + 1; const action = NameOrIdentifier.action(value, index); if (!action) { return; } action.value.namespace = utils_1.default.stringify(value, start, namespaceNext); return Lexer.tokenize(value, start, action.next, action, Lexer.TokenType.Action); } exports.qualifiedActionName = qualifiedActionName; function qualifiedFunctionName(value, index) { const namespaceNext = NameOrIdentifier.namespace(value, index); if (namespaceNext === index || value[namespaceNext] !== 0x2e) { return; } const start = index; index = namespaceNext + 1; const fn = NameOrIdentifier.odataFunction(value, index); if (!fn) { return; } fn.value.namespace = utils_1.default.stringify(value, start, namespaceNext); index = fn.next; const tokenValue = { name: fn }; const open = Lexer.OPEN(value, index); if (open) { index = open; tokenValue.parameters = []; const param = Expressions.parameterName(value, index); if (!param) { return; } while (param) { index = param.next; tokenValue.parameters.push(param); const comma = Lexer.COMMA(value, index); if (comma) { index = comma; const param = Expressions.parameterName(value, index); if (!param) { return; } } else { break; } } const close = Lexer.CLOSE(value, index); if (!close) { return; } index = close; } return Lexer.tokenize(value, start, index, tokenValue, Lexer.TokenType.Function); } exports.qualifiedFunctionName = qualifiedFunctionName; function skiptoken(value, index) { const start = index; if (utils_1.default.equals(value, index, '%24skiptoken')) { index += 12; } else if (utils_1.default.equals(value, index, '$skiptoken')) { index += 10; } else { return; } const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; let ch = Lexer.qcharNoAMP(value, index); if (!ch) { return; } const valueStart = index; while (ch > index) { index = ch; ch = Lexer.qcharNoAMP(value, index); } return Lexer.tokenize(value, start, index, utils_1.default.stringify(value, valueStart, index), Lexer.TokenType.SkipToken); } exports.skiptoken = skiptoken; function aliasAndValue(value, index) { const alias = Expressions.parameterAlias(value, index); if (!alias) { return; } const start = index; index = alias.next; const eq = Lexer.EQ(value, index); if (!eq) { return; } index = eq; const paramValue = Expressions.parameterValue(value, index); if (!paramValue) { return; } index = paramValue.next; return Lexer.tokenize(value, start, index, { alias, value: paramValue }, Lexer.TokenType.AliasAndValue); } exports.aliasAndValue = aliasAndValue; //# sourceMappingURL=query.js.map