where-clause-tool.spec.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import {expect} from 'chai';
  2. import {format} from '@e22m4u/format';
  3. import {WhereClauseTool} from './where-clause-tool.js';
  4. const S = new WhereClauseTool();
  5. const OBJECTS = [
  6. {
  7. id: 1,
  8. name: 'John',
  9. surname: 'Doe',
  10. age: 21,
  11. hobbies: ['bicycle', 'yoga'],
  12. nickname: 'Spear',
  13. birthdate: '2002-04-14',
  14. },
  15. {
  16. id: 2,
  17. name: 'Mary',
  18. surname: 'Smith',
  19. age: 21,
  20. hobbies: ['yoga', 'meditation'],
  21. nickname: 'Flower',
  22. birthdate: '2002-01-12',
  23. },
  24. {
  25. id: 3,
  26. name: 'James',
  27. surname: 'Smith',
  28. age: 21,
  29. hobbies: [],
  30. nickname: null,
  31. birthdate: '2002-03-01',
  32. },
  33. {
  34. id: 4,
  35. name: 'Oliver',
  36. surname: 'Smith',
  37. age: 32,
  38. hobbies: ['bicycle'],
  39. birthdate: '1991-06-24',
  40. },
  41. ];
  42. describe('WhereClauseTool', function () {
  43. describe('filter', function () {
  44. it('returns the same array if no given condition', function () {
  45. const result = S.filter(OBJECTS);
  46. expect(result).to.be.eql(OBJECTS);
  47. });
  48. it('returns a filtered array by matched properties', function () {
  49. const result = S.filter(OBJECTS, {surname: 'Smith', age: 21});
  50. expect(result).to.have.length(2);
  51. expect(result[0]).to.be.eql(OBJECTS[1]);
  52. expect(result[1]).to.be.eql(OBJECTS[2]);
  53. });
  54. it('the and operator requires each given condition to be met', function () {
  55. const result = S.filter(OBJECTS, {
  56. and: [{name: 'James'}, {age: 21}],
  57. });
  58. expect(result).to.have.length(1);
  59. expect(result[0]).to.be.eql(OBJECTS[2]);
  60. });
  61. it('the or operator requires one of a given condition to be met', function () {
  62. const result = S.filter(OBJECTS, {
  63. or: [{name: 'James'}, {age: 21}],
  64. });
  65. expect(result).to.have.length(3);
  66. expect(result[0]).to.be.eql(OBJECTS[0]);
  67. expect(result[1]).to.be.eql(OBJECTS[1]);
  68. expect(result[2]).to.be.eql(OBJECTS[2]);
  69. });
  70. it('uses property value to match an array value', function () {
  71. const result = S.filter(OBJECTS, {hobbies: 'yoga'});
  72. expect(result).to.have.length(2);
  73. expect(result[0]).to.be.eql(OBJECTS[0]);
  74. expect(result[1]).to.be.eql(OBJECTS[1]);
  75. });
  76. it('uses given RegExp to match a property value', function () {
  77. const result = S.filter(OBJECTS, {surname: /^Sm.+/});
  78. expect(result).to.have.length(3);
  79. expect(result[0]).to.be.eql(OBJECTS[1]);
  80. expect(result[1]).to.be.eql(OBJECTS[2]);
  81. expect(result[2]).to.be.eql(OBJECTS[3]);
  82. });
  83. it('uses given RegExp to match an array value', function () {
  84. const result = S.filter(OBJECTS, {hobbies: /^\w+cycle/});
  85. expect(result).to.have.length(2);
  86. expect(result[0]).to.be.eql(OBJECTS[0]);
  87. expect(result[1]).to.be.eql(OBJECTS[3]);
  88. });
  89. it('skips not supported values for RegExp', function () {
  90. const result = S.filter(OBJECTS, {id: /test/});
  91. expect(result).to.be.empty;
  92. });
  93. it('uses an "eq" operator to match equality', function () {
  94. const result = S.filter(OBJECTS, {name: {eq: 'John'}});
  95. expect(result).to.have.length(1);
  96. expect(result[0]).to.be.eql(OBJECTS[0]);
  97. });
  98. it('uses a "neq" operator to match non-equality', function () {
  99. const result = S.filter(OBJECTS, {name: {neq: 'John'}});
  100. expect(result).to.have.length(3);
  101. expect(result[0]).to.be.eql(OBJECTS[1]);
  102. expect(result[1]).to.be.eql(OBJECTS[2]);
  103. expect(result[2]).to.be.eql(OBJECTS[3]);
  104. });
  105. it('uses a "neq" operator to match an empty array', function () {
  106. const result = S.filter(OBJECTS, {hobbies: {neq: 'bicycle'}});
  107. expect(result).to.have.length(2);
  108. expect(result[0]).to.be.eql(OBJECTS[1]);
  109. expect(result[1]).to.be.eql(OBJECTS[2]);
  110. });
  111. it('uses a "gt" operator to compare values', function () {
  112. const result = S.filter(OBJECTS, {id: {gt: 2}});
  113. expect(result).to.have.length(2);
  114. expect(result[0]).to.be.eql(OBJECTS[2]);
  115. expect(result[1]).to.be.eql(OBJECTS[3]);
  116. });
  117. it('uses a "gte" operator to compare values', function () {
  118. const result = S.filter(OBJECTS, {id: {gte: 2}});
  119. expect(result).to.have.length(3);
  120. expect(result[0]).to.be.eql(OBJECTS[1]);
  121. expect(result[1]).to.be.eql(OBJECTS[2]);
  122. expect(result[2]).to.be.eql(OBJECTS[3]);
  123. });
  124. it('uses a "lt" operator to compare values', function () {
  125. const result = S.filter(OBJECTS, {id: {lt: 3}});
  126. expect(result).to.have.length(2);
  127. expect(result[0]).to.be.eql(OBJECTS[0]);
  128. expect(result[1]).to.be.eql(OBJECTS[1]);
  129. });
  130. it('uses a "lte" operator to compare values', function () {
  131. const result = S.filter(OBJECTS, {id: {lte: 3}});
  132. expect(result).to.have.length(3);
  133. expect(result[0]).to.be.eql(OBJECTS[0]);
  134. expect(result[1]).to.be.eql(OBJECTS[1]);
  135. expect(result[2]).to.be.eql(OBJECTS[2]);
  136. });
  137. it('uses a "inq" operator to compare values', function () {
  138. const result = S.filter(OBJECTS, {id: {inq: [2, 3]}});
  139. expect(result).to.have.length(2);
  140. expect(result[0]).to.be.eql(OBJECTS[1]);
  141. expect(result[1]).to.be.eql(OBJECTS[2]);
  142. });
  143. it('uses a "nin" operator to compare values', function () {
  144. const result = S.filter(OBJECTS, {id: {nin: [2, 3]}});
  145. expect(result).to.have.length(2);
  146. expect(result[0]).to.be.eql(OBJECTS[0]);
  147. expect(result[1]).to.be.eql(OBJECTS[3]);
  148. });
  149. it('uses a "between" operator to compare values', function () {
  150. const result = S.filter(OBJECTS, {id: {between: [2, 3]}});
  151. expect(result).to.have.length(2);
  152. expect(result[0]).to.be.eql(OBJECTS[1]);
  153. expect(result[1]).to.be.eql(OBJECTS[2]);
  154. });
  155. it('uses an "exists" operator to check existence', function () {
  156. const result = S.filter(OBJECTS, {nickname: {exists: true}});
  157. expect(result).to.have.length(3);
  158. expect(result[0]).to.be.eql(OBJECTS[0]);
  159. expect(result[1]).to.be.eql(OBJECTS[1]);
  160. expect(result[2]).to.be.eql(OBJECTS[2]);
  161. });
  162. it('uses an "exists" operator to check non-existence', function () {
  163. const result = S.filter(OBJECTS, {nickname: {exists: false}});
  164. expect(result).to.have.length(1);
  165. expect(result[0]).to.be.eql(OBJECTS[3]);
  166. });
  167. it('uses a "like" operator to match by a substring', function () {
  168. const result = S.filter(OBJECTS, {name: {like: 'liv'}});
  169. expect(result).to.have.length(1);
  170. expect(result[0]).to.be.eql(OBJECTS[3]);
  171. });
  172. it('uses a "nlike" operator to exclude by a substring', function () {
  173. const result = S.filter(OBJECTS, {name: {nlike: 'liv'}});
  174. expect(result).to.have.length(3);
  175. expect(result[0]).to.be.eql(OBJECTS[0]);
  176. expect(result[1]).to.be.eql(OBJECTS[1]);
  177. expect(result[2]).to.be.eql(OBJECTS[2]);
  178. });
  179. it('uses a "ilike" operator to case-insensitively matching by a substring', function () {
  180. const result = S.filter(OBJECTS, {name: {ilike: 'LIV'}});
  181. expect(result).to.have.length(1);
  182. expect(result[0]).to.be.eql(OBJECTS[3]);
  183. });
  184. it('uses a "nilike" operator to exclude case-insensitively by a substring', function () {
  185. const result = S.filter(OBJECTS, {name: {nilike: 'LIV'}});
  186. expect(result).to.have.length(3);
  187. expect(result[0]).to.be.eql(OBJECTS[0]);
  188. expect(result[1]).to.be.eql(OBJECTS[1]);
  189. expect(result[2]).to.be.eql(OBJECTS[2]);
  190. });
  191. it('uses a "regexp" operator to compare values', function () {
  192. const result = S.filter(OBJECTS, {name: {regexp: '^Jam.*'}});
  193. expect(result).to.have.length(1);
  194. expect(result[0]).to.be.eql(OBJECTS[2]);
  195. });
  196. it('uses a null to match an undefined and null value', function () {
  197. const result = S.filter(OBJECTS, {nickname: null});
  198. expect(result).to.have.length(2);
  199. expect(result[0]).to.be.eql(OBJECTS[2]);
  200. expect(result[1]).to.be.eql(OBJECTS[3]);
  201. });
  202. it('uses a given function to filter values', function () {
  203. const result = S.filter(OBJECTS, v => v.nickname === 'Flower');
  204. expect(result).to.have.length(1);
  205. expect(result[0]).to.be.eql(OBJECTS[1]);
  206. });
  207. it('throws an error if a first argument is not an Array', function () {
  208. const throwable = () => S.filter(10);
  209. expect(throwable).to.throw(
  210. 'A first argument of WhereUtils.filter ' +
  211. 'should be an Array of Objects, but 10 given.',
  212. );
  213. });
  214. it('throws an error if elements of a first argument is not an Object', function () {
  215. const throwable = () => S.filter([10]);
  216. expect(throwable).to.throw(
  217. 'A first argument of WhereUtils.filter ' +
  218. 'should be an Array of Objects, but 10 given.',
  219. );
  220. });
  221. it('throws an error if a provided second argument is not an Object', function () {
  222. const throwable = () => S.filter([], 10);
  223. expect(throwable).to.throw(
  224. 'The provided option "where" should be an Object, but 10 given.',
  225. );
  226. });
  227. });
  228. describe('validateWhereClause', function () {
  229. it('requires an object value or a falsy value', function () {
  230. const validate = v => () => WhereClauseTool.validateWhereClause(v);
  231. const error = v =>
  232. format(
  233. 'The provided option "where" should be an Object, but %s given.',
  234. v,
  235. );
  236. expect(validate('str')).to.throw(error('"str"'));
  237. expect(validate(10)).to.throw(error('10'));
  238. expect(validate(true)).to.throw(error('true'));
  239. expect(validate([])).to.throw(error('Array'));
  240. validate('');
  241. validate(false);
  242. validate(undefined);
  243. validate(null);
  244. validate({});
  245. });
  246. });
  247. });