123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- import { isQueryCommand, isComparisonCommand, QUERY_COMMANDS_LITERAL } from '../commands/query';
- import { isLogicCommand, LOGIC_COMMANDS_LITERAL } from '../commands/logic';
- import { SYMBOL_UNSET_FIELD_NAME, SYMBOL_GEO_POINT } from '../helper/symbol';
- import { getType, isObject, isArray, isRegExp, isDate } from '../utils/type';
- import { operatorToString } from '../operator-map';
- import { flattenQueryObject, isConversionRequired, encodeInternalDataType } from './common';
- import { stringifyByEJSON } from '../utils/utils';
- import { Validate } from '../validate';
- export class QuerySerializer {
- constructor() { }
- static encode(query) {
- const encoder = new QueryEncoder();
- return encoder.encodeQuery(query);
- }
- static encodeEJSON(query) {
- const encoder = new QueryEncoder();
- return stringifyByEJSON(encoder.encodeQuery(query));
- }
- }
- class QueryEncoder {
- encodeQuery(query, key) {
- if (isConversionRequired(query)) {
- if (isLogicCommand(query)) {
- return this.encodeLogicCommand(query);
- }
- else if (isQueryCommand(query)) {
- return this.encodeQueryCommand(query);
- }
- else if (isRegExp(query)) {
- return { [key]: this.encodeRegExp(query) };
- }
- else if (isDate(query)) {
- return { [key]: query };
- }
- else {
- return { [key]: this.encodeQueryObject(query) };
- }
- }
- else {
- if (isObject(query)) {
- return this.encodeQueryObject(query);
- }
- else {
- return query;
- }
- }
- }
- encodeRegExp(query) {
- return {
- $regularExpression: {
- pattern: query.source,
- options: query.flags
- }
- };
- }
- encodeLogicCommand(query) {
- switch (query.operator) {
- case LOGIC_COMMANDS_LITERAL.NOR:
- case LOGIC_COMMANDS_LITERAL.AND:
- case LOGIC_COMMANDS_LITERAL.OR: {
- const $op = operatorToString(query.operator);
- const subqueries = query.operands.map((oprand) => this.encodeQuery(oprand, query.fieldName));
- return {
- [$op]: subqueries
- };
- }
- case LOGIC_COMMANDS_LITERAL.NOT: {
- const $op = operatorToString(query.operator);
- const operatorExpression = query.operands[0];
- if (isRegExp(operatorExpression)) {
- return {
- [query.fieldName]: {
- [$op]: this.encodeRegExp(operatorExpression)
- }
- };
- }
- else {
- const subqueries = this.encodeQuery(operatorExpression)[query.fieldName];
- return {
- [query.fieldName]: {
- [$op]: subqueries
- }
- };
- }
- }
- default: {
- const $op = operatorToString(query.operator);
- if (query.operands.length === 1) {
- const subquery = this.encodeQuery(query.operands[0]);
- return {
- [$op]: subquery
- };
- }
- else {
- const subqueries = query.operands.map(this.encodeQuery.bind(this));
- return {
- [$op]: subqueries
- };
- }
- }
- }
- }
- encodeQueryCommand(query) {
- if (isComparisonCommand(query)) {
- return this.encodeComparisonCommand(query);
- }
- else {
- return this.encodeComparisonCommand(query);
- }
- }
- encodeComparisonCommand(query) {
- if (query.fieldName === SYMBOL_UNSET_FIELD_NAME) {
- throw new Error('Cannot encode a comparison command with unset field name');
- }
- const $op = operatorToString(query.operator);
- switch (query.operator) {
- case QUERY_COMMANDS_LITERAL.EQ:
- case QUERY_COMMANDS_LITERAL.NEQ:
- case QUERY_COMMANDS_LITERAL.LT:
- case QUERY_COMMANDS_LITERAL.LTE:
- case QUERY_COMMANDS_LITERAL.GT:
- case QUERY_COMMANDS_LITERAL.GTE:
- case QUERY_COMMANDS_LITERAL.ELEM_MATCH:
- case QUERY_COMMANDS_LITERAL.EXISTS:
- case QUERY_COMMANDS_LITERAL.SIZE:
- case QUERY_COMMANDS_LITERAL.MOD: {
- return {
- [query.fieldName]: {
- [$op]: encodeInternalDataType(query.operands[0])
- }
- };
- }
- case QUERY_COMMANDS_LITERAL.IN:
- case QUERY_COMMANDS_LITERAL.NIN:
- case QUERY_COMMANDS_LITERAL.ALL: {
- return {
- [query.fieldName]: {
- [$op]: encodeInternalDataType(query.operands)
- }
- };
- }
- case QUERY_COMMANDS_LITERAL.GEO_NEAR: {
- const options = query.operands[0];
- return {
- [query.fieldName]: {
- $nearSphere: {
- $geometry: options.geometry.toJSON(),
- $maxDistance: options.maxDistance,
- $minDistance: options.minDistance
- }
- }
- };
- }
- case QUERY_COMMANDS_LITERAL.GEO_WITHIN: {
- const options = query.operands[0];
- if (options.centerSphere) {
- Validate.isCentersPhere(options.centerSphere);
- const centerSphere = options.centerSphere;
- if (centerSphere[0]._internalType === SYMBOL_GEO_POINT) {
- return {
- [query.fieldName]: {
- $geoWithin: {
- $centerSphere: [centerSphere[0].toJSON().coordinates, centerSphere[1]]
- }
- }
- };
- }
- return {
- [query.fieldName]: {
- $geoWithin: {
- $centerSphere: options.centerSphere
- }
- }
- };
- }
- return {
- [query.fieldName]: {
- $geoWithin: {
- $geometry: options.geometry.toJSON()
- }
- }
- };
- }
- case QUERY_COMMANDS_LITERAL.GEO_INTERSECTS: {
- const options = query.operands[0];
- return {
- [query.fieldName]: {
- $geoIntersects: {
- $geometry: options.geometry.toJSON()
- }
- }
- };
- }
- default: {
- return {
- [query.fieldName]: {
- [$op]: encodeInternalDataType(query.operands[0])
- }
- };
- }
- }
- }
- encodeQueryObject(query) {
- const flattened = flattenQueryObject(query);
- for (const key in flattened) {
- const val = flattened[key];
- if (isLogicCommand(val)) {
- flattened[key] = val._setFieldName(key);
- const condition = this.encodeLogicCommand(flattened[key]);
- this.mergeConditionAfterEncode(flattened, condition, key);
- }
- else if (isComparisonCommand(val)) {
- flattened[key] = val._setFieldName(key);
- const condition = this.encodeComparisonCommand(flattened[key]);
- this.mergeConditionAfterEncode(flattened, condition, key);
- }
- else if (isConversionRequired(val)) {
- flattened[key] = encodeInternalDataType(val);
- }
- }
- return flattened;
- }
- mergeConditionAfterEncode(query, condition, key) {
- if (!condition[key]) {
- delete query[key];
- }
- for (const conditionKey in condition) {
- if (query[conditionKey]) {
- if (isArray(query[conditionKey])) {
- query[conditionKey] = query[conditionKey].concat(condition[conditionKey]);
- }
- else if (isObject(query[conditionKey])) {
- if (isObject(condition[conditionKey])) {
- Object.assign(query, condition);
- }
- else {
- console.warn(`unmergable condition, query is object but condition is ${getType(condition)}, can only overwrite`, condition, key);
- query[conditionKey] = condition[conditionKey];
- }
- }
- else {
- console.warn(`to-merge query is of type ${getType(query)}, can only overwrite`, query, condition, key);
- query[conditionKey] = condition[conditionKey];
- }
- }
- else {
- query[conditionKey] = condition[conditionKey];
- }
- }
- }
- }
|