query.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const query_1 = require("../commands/query");
  4. const logic_1 = require("../commands/logic");
  5. const symbol_1 = require("../helper/symbol");
  6. const type_1 = require("../utils/type");
  7. const operator_map_1 = require("../operator-map");
  8. const common_1 = require("./common");
  9. const utils_1 = require("../utils/utils");
  10. const validate_1 = require("../validate");
  11. class QuerySerializer {
  12. constructor() { }
  13. static encode(query) {
  14. const encoder = new QueryEncoder();
  15. return encoder.encodeQuery(query);
  16. }
  17. static encodeEJSON(query) {
  18. const encoder = new QueryEncoder();
  19. return utils_1.stringifyByEJSON(encoder.encodeQuery(query));
  20. }
  21. }
  22. exports.QuerySerializer = QuerySerializer;
  23. class QueryEncoder {
  24. encodeQuery(query, key) {
  25. if (common_1.isConversionRequired(query)) {
  26. if (logic_1.isLogicCommand(query)) {
  27. return this.encodeLogicCommand(query);
  28. }
  29. else if (query_1.isQueryCommand(query)) {
  30. return this.encodeQueryCommand(query);
  31. }
  32. else if (type_1.isRegExp(query)) {
  33. return { [key]: this.encodeRegExp(query) };
  34. }
  35. else if (type_1.isDate(query)) {
  36. return { [key]: query };
  37. }
  38. else {
  39. return { [key]: this.encodeQueryObject(query) };
  40. }
  41. }
  42. else {
  43. if (type_1.isObject(query)) {
  44. return this.encodeQueryObject(query);
  45. }
  46. else {
  47. return query;
  48. }
  49. }
  50. }
  51. encodeRegExp(query) {
  52. return {
  53. $regularExpression: {
  54. pattern: query.source,
  55. options: query.flags
  56. }
  57. };
  58. }
  59. encodeLogicCommand(query) {
  60. switch (query.operator) {
  61. case logic_1.LOGIC_COMMANDS_LITERAL.NOR:
  62. case logic_1.LOGIC_COMMANDS_LITERAL.AND:
  63. case logic_1.LOGIC_COMMANDS_LITERAL.OR: {
  64. const $op = operator_map_1.operatorToString(query.operator);
  65. const subqueries = query.operands.map((oprand) => this.encodeQuery(oprand, query.fieldName));
  66. return {
  67. [$op]: subqueries
  68. };
  69. }
  70. case logic_1.LOGIC_COMMANDS_LITERAL.NOT: {
  71. const $op = operator_map_1.operatorToString(query.operator);
  72. const operatorExpression = query.operands[0];
  73. if (type_1.isRegExp(operatorExpression)) {
  74. return {
  75. [query.fieldName]: {
  76. [$op]: this.encodeRegExp(operatorExpression)
  77. }
  78. };
  79. }
  80. else {
  81. const subqueries = this.encodeQuery(operatorExpression)[query.fieldName];
  82. return {
  83. [query.fieldName]: {
  84. [$op]: subqueries
  85. }
  86. };
  87. }
  88. }
  89. default: {
  90. const $op = operator_map_1.operatorToString(query.operator);
  91. if (query.operands.length === 1) {
  92. const subquery = this.encodeQuery(query.operands[0]);
  93. return {
  94. [$op]: subquery
  95. };
  96. }
  97. else {
  98. const subqueries = query.operands.map(this.encodeQuery.bind(this));
  99. return {
  100. [$op]: subqueries
  101. };
  102. }
  103. }
  104. }
  105. }
  106. encodeQueryCommand(query) {
  107. if (query_1.isComparisonCommand(query)) {
  108. return this.encodeComparisonCommand(query);
  109. }
  110. else {
  111. return this.encodeComparisonCommand(query);
  112. }
  113. }
  114. encodeComparisonCommand(query) {
  115. if (query.fieldName === symbol_1.SYMBOL_UNSET_FIELD_NAME) {
  116. throw new Error('Cannot encode a comparison command with unset field name');
  117. }
  118. const $op = operator_map_1.operatorToString(query.operator);
  119. switch (query.operator) {
  120. case query_1.QUERY_COMMANDS_LITERAL.EQ:
  121. case query_1.QUERY_COMMANDS_LITERAL.NEQ:
  122. case query_1.QUERY_COMMANDS_LITERAL.LT:
  123. case query_1.QUERY_COMMANDS_LITERAL.LTE:
  124. case query_1.QUERY_COMMANDS_LITERAL.GT:
  125. case query_1.QUERY_COMMANDS_LITERAL.GTE:
  126. case query_1.QUERY_COMMANDS_LITERAL.ELEM_MATCH:
  127. case query_1.QUERY_COMMANDS_LITERAL.EXISTS:
  128. case query_1.QUERY_COMMANDS_LITERAL.SIZE:
  129. case query_1.QUERY_COMMANDS_LITERAL.MOD: {
  130. return {
  131. [query.fieldName]: {
  132. [$op]: common_1.encodeInternalDataType(query.operands[0])
  133. }
  134. };
  135. }
  136. case query_1.QUERY_COMMANDS_LITERAL.IN:
  137. case query_1.QUERY_COMMANDS_LITERAL.NIN:
  138. case query_1.QUERY_COMMANDS_LITERAL.ALL: {
  139. return {
  140. [query.fieldName]: {
  141. [$op]: common_1.encodeInternalDataType(query.operands)
  142. }
  143. };
  144. }
  145. case query_1.QUERY_COMMANDS_LITERAL.GEO_NEAR: {
  146. const options = query.operands[0];
  147. return {
  148. [query.fieldName]: {
  149. $nearSphere: {
  150. $geometry: options.geometry.toJSON(),
  151. $maxDistance: options.maxDistance,
  152. $minDistance: options.minDistance
  153. }
  154. }
  155. };
  156. }
  157. case query_1.QUERY_COMMANDS_LITERAL.GEO_WITHIN: {
  158. const options = query.operands[0];
  159. if (options.centerSphere) {
  160. validate_1.Validate.isCentersPhere(options.centerSphere);
  161. const centerSphere = options.centerSphere;
  162. if (centerSphere[0]._internalType === symbol_1.SYMBOL_GEO_POINT) {
  163. return {
  164. [query.fieldName]: {
  165. $geoWithin: {
  166. $centerSphere: [centerSphere[0].toJSON().coordinates, centerSphere[1]]
  167. }
  168. }
  169. };
  170. }
  171. return {
  172. [query.fieldName]: {
  173. $geoWithin: {
  174. $centerSphere: options.centerSphere
  175. }
  176. }
  177. };
  178. }
  179. return {
  180. [query.fieldName]: {
  181. $geoWithin: {
  182. $geometry: options.geometry.toJSON()
  183. }
  184. }
  185. };
  186. }
  187. case query_1.QUERY_COMMANDS_LITERAL.GEO_INTERSECTS: {
  188. const options = query.operands[0];
  189. return {
  190. [query.fieldName]: {
  191. $geoIntersects: {
  192. $geometry: options.geometry.toJSON()
  193. }
  194. }
  195. };
  196. }
  197. default: {
  198. return {
  199. [query.fieldName]: {
  200. [$op]: common_1.encodeInternalDataType(query.operands[0])
  201. }
  202. };
  203. }
  204. }
  205. }
  206. encodeQueryObject(query) {
  207. const flattened = common_1.flattenQueryObject(query);
  208. for (const key in flattened) {
  209. const val = flattened[key];
  210. if (logic_1.isLogicCommand(val)) {
  211. flattened[key] = val._setFieldName(key);
  212. const condition = this.encodeLogicCommand(flattened[key]);
  213. this.mergeConditionAfterEncode(flattened, condition, key);
  214. }
  215. else if (query_1.isComparisonCommand(val)) {
  216. flattened[key] = val._setFieldName(key);
  217. const condition = this.encodeComparisonCommand(flattened[key]);
  218. this.mergeConditionAfterEncode(flattened, condition, key);
  219. }
  220. else if (common_1.isConversionRequired(val)) {
  221. flattened[key] = common_1.encodeInternalDataType(val);
  222. }
  223. }
  224. return flattened;
  225. }
  226. mergeConditionAfterEncode(query, condition, key) {
  227. if (!condition[key]) {
  228. delete query[key];
  229. }
  230. for (const conditionKey in condition) {
  231. if (query[conditionKey]) {
  232. if (type_1.isArray(query[conditionKey])) {
  233. query[conditionKey] = query[conditionKey].concat(condition[conditionKey]);
  234. }
  235. else if (type_1.isObject(query[conditionKey])) {
  236. if (type_1.isObject(condition[conditionKey])) {
  237. Object.assign(query, condition);
  238. }
  239. else {
  240. console.warn(`unmergable condition, query is object but condition is ${type_1.getType(condition)}, can only overwrite`, condition, key);
  241. query[conditionKey] = condition[conditionKey];
  242. }
  243. }
  244. else {
  245. console.warn(`to-merge query is of type ${type_1.getType(query)}, can only overwrite`, query, condition, key);
  246. query[conditionKey] = condition[conditionKey];
  247. }
  248. }
  249. else {
  250. query[conditionKey] = condition[conditionKey];
  251. }
  252. }
  253. }
  254. }