ObjectExpression.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /** Empty object spec. */
  2. class Empty : public ExpectedResultBase {
  3. public:
  4. void prepareExpression() {}
  5. BSONObj expected() { return BSON( "_id" << 0 ); }
  6. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  7. BSONObj expectedBsonRepresentation() { return BSONObj(); }
  8. };
  9. /** Include 'a' field only. */
  10. class Include : public ExpectedResultBase {
  11. public:
  12. void prepareExpression() { expression()->includePath( "a" ); }
  13. BSONObj expected() { return BSON( "_id" << 0 << "a" << 1 ); }
  14. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a" ); }
  15. BSONObj expectedBsonRepresentation() {
  16. return BSON( "a" << true );
  17. }
  18. };
  19. /** Cannot include missing 'a' field. */
  20. class MissingInclude : public ExpectedResultBase {
  21. public:
  22. virtual BSONObj source() { return BSON( "_id" << 0 << "b" << 2 ); }
  23. void prepareExpression() { expression()->includePath( "a" ); }
  24. BSONObj expected() { return BSON( "_id" << 0 ); }
  25. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a" ); }
  26. BSONObj expectedBsonRepresentation() {
  27. return BSON( "a" << true );
  28. }
  29. };
  30. /** Include '_id' field only. */
  31. class IncludeId : public ExpectedResultBase {
  32. public:
  33. void prepareExpression() { expression()->includePath( "_id" ); }
  34. BSONObj expected() { return BSON( "_id" << 0 ); }
  35. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  36. BSONObj expectedBsonRepresentation() {
  37. return BSON( "_id" << true );
  38. }
  39. };
  40. /** Exclude '_id' field. */
  41. class ExcludeId : public ExpectedResultBase {
  42. public:
  43. void prepareExpression() {
  44. expression()->includePath( "b" );
  45. expression()->excludeId( true );
  46. }
  47. BSONObj expected() { return BSON( "b" << 2 ); }
  48. BSONArray expectedDependencies() { return BSON_ARRAY( "b" ); }
  49. BSONObj expectedBsonRepresentation() {
  50. return BSON( "_id" << false << "b" << true );
  51. }
  52. };
  53. /** Result order based on source document field order, not inclusion spec field order. */
  54. class SourceOrder : public ExpectedResultBase {
  55. public:
  56. void prepareExpression() {
  57. expression()->includePath( "b" );
  58. expression()->includePath( "a" );
  59. }
  60. BSONObj expected() { return source(); }
  61. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a" << "b" ); }
  62. BSONObj expectedBsonRepresentation() {
  63. return BSON( "b" << true << "a" << true );
  64. }
  65. };
  66. /** Include a nested field. */
  67. class IncludeNested : public ExpectedResultBase {
  68. public:
  69. void prepareExpression() { expression()->includePath( "a.b" ); }
  70. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 5 ) ); }
  71. BSONObj source() {
  72. return BSON( "_id" << 0 << "a" << BSON( "b" << 5 << "c" << 6 ) << "z" << 2 );
  73. }
  74. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" ); }
  75. BSONObj expectedBsonRepresentation() {
  76. return BSON( "a" << BSON( "b" << true ) );
  77. }
  78. };
  79. /** Include two nested fields. */
  80. class IncludeTwoNested : public ExpectedResultBase {
  81. public:
  82. void prepareExpression() {
  83. expression()->includePath( "a.b" );
  84. expression()->includePath( "a.c" );
  85. }
  86. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 5 << "c" << 6 ) ); }
  87. BSONObj source() {
  88. return BSON( "_id" << 0 << "a" << BSON( "b" << 5 << "c" << 6 ) << "z" << 2 );
  89. }
  90. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" << "a.c" ); }
  91. BSONObj expectedBsonRepresentation() {
  92. return BSON( "a" << BSON( "b" << true << "c" << true ) );
  93. }
  94. };
  95. /** Include two fields nested within different parents. */
  96. class IncludeTwoParentNested : public ExpectedResultBase {
  97. public:
  98. void prepareExpression() {
  99. expression()->includePath( "a.b" );
  100. expression()->includePath( "c.d" );
  101. }
  102. BSONObj expected() {
  103. return BSON( "_id" << 0 << "a" << BSON( "b" << 5 ) << "c" << BSON( "d" << 6 ) );
  104. }
  105. BSONObj source() {
  106. return BSON( "_id" << 0 << "a" << BSON( "b" << 5 )
  107. << "c" << BSON( "d" << 6 ) << "z" << 2 );
  108. }
  109. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" << "c.d" ); }
  110. BSONObj expectedBsonRepresentation() {
  111. return BSON( "a" << BSON( "b" << true ) << "c" << BSON( "d" << true ) );
  112. }
  113. };
  114. /** Attempt to include a missing nested field. */
  115. class IncludeMissingNested : public ExpectedResultBase {
  116. public:
  117. void prepareExpression() { expression()->includePath( "a.b" ); }
  118. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSONObj() ); }
  119. BSONObj source() {
  120. return BSON( "_id" << 0 << "a" << BSON( "c" << 6 ) << "z" << 2 );
  121. }
  122. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" ); }
  123. BSONObj expectedBsonRepresentation() {
  124. return BSON( "a" << BSON( "b" << true ) );
  125. }
  126. };
  127. /** Attempt to include a nested field within a non object. */
  128. class IncludeNestedWithinNonObject : public ExpectedResultBase {
  129. public:
  130. void prepareExpression() { expression()->includePath( "a.b" ); }
  131. BSONObj expected() { return BSON( "_id" << 0 ); }
  132. BSONObj source() {
  133. return BSON( "_id" << 0 << "a" << 2 << "z" << 2 );
  134. }
  135. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" ); }
  136. BSONObj expectedBsonRepresentation() {
  137. return BSON( "a" << BSON( "b" << true ) );
  138. }
  139. };
  140. /** Include a nested field within an array. */
  141. class IncludeArrayNested : public ExpectedResultBase {
  142. public:
  143. void prepareExpression() { expression()->includePath( "a.b" ); }
  144. BSONObj expected() { return fromjson( "{_id:0,a:[{b:5},{b:2},{}]}" ); }
  145. BSONObj source() {
  146. return fromjson( "{_id:0,a:[{b:5,c:6},{b:2,c:9},{c:7},[],2],z:1}" );
  147. }
  148. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" ); }
  149. BSONObj expectedBsonRepresentation() {
  150. return BSON( "a" << BSON( "b" << true ) );
  151. }
  152. };
  153. /** Don't include not root '_id' field implicitly. */
  154. class ExcludeNonRootId : public ExpectedResultBase {
  155. public:
  156. virtual BSONObj source() {
  157. return BSON( "_id" << 0 << "a" << BSON( "_id" << 1 << "b" << 1 ) );
  158. }
  159. void prepareExpression() { expression()->includePath( "a.b" ); }
  160. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 1 ) ); }
  161. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "a.b" ); }
  162. BSONObj expectedBsonRepresentation() {
  163. return BSON( "a" << BSON( "b" << true ) );
  164. }
  165. };
  166. /** Project a computed expression. */
  167. class Computed : public ExpectedResultBase {
  168. public:
  169. virtual BSONObj source() {
  170. return BSON( "_id" << 0 );
  171. }
  172. void prepareExpression() {
  173. expression()->addField( mongo::FieldPath( "a" ),
  174. ExpressionConstant::create( Value::createInt( 5 ) ) );
  175. }
  176. BSONObj expected() { return BSON( "_id" << 0 << "a" << 5 ); }
  177. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  178. BSONObj expectedBsonRepresentation() {
  179. return BSON( "a" << BSON( "$const" << 5 ) );
  180. }
  181. bool expectedIsSimple() { return false; }
  182. };
  183. /** Project a computed expression replacing an existing field. */
  184. class ComputedReplacement : public Computed {
  185. virtual BSONObj source() {
  186. return BSON( "_id" << 0 << "a" << 99 );
  187. }
  188. };
  189. /** An undefined value is not projected.. */
  190. class ComputedUndefined : public ExpectedResultBase {
  191. public:
  192. virtual BSONObj source() {
  193. return BSON( "_id" << 0 );
  194. }
  195. void prepareExpression() {
  196. expression()->addField( mongo::FieldPath( "a" ),
  197. ExpressionConstant::create( Value::getUndefined() ) );
  198. }
  199. BSONObj expected() { return BSON( "_id" << 0 ); }
  200. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  201. BSONObj expectedBsonRepresentation() {
  202. return fromjson( "{a:{$const:undefined}}" );
  203. }
  204. bool expectedIsSimple() { return false; }
  205. };
  206. /** Project a computed expression replacing an existing field with Undefined. */
  207. class ComputedUndefinedReplacement : public ComputedUndefined {
  208. virtual BSONObj source() {
  209. return BSON( "_id" << 0 << "a" << 99 );
  210. }
  211. };
  212. /** A null value is projected. */
  213. class ComputedNull : public ExpectedResultBase {
  214. public:
  215. virtual BSONObj source() {
  216. return BSON( "_id" << 0 );
  217. }
  218. void prepareExpression() {
  219. expression()->addField( mongo::FieldPath( "a" ),
  220. ExpressionConstant::create( Value::getNull() ) );
  221. }
  222. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSONNULL ); }
  223. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  224. BSONObj expectedBsonRepresentation() {
  225. return BSON( "a" << BSON( "$const" << BSONNULL ) );
  226. }
  227. bool expectedIsSimple() { return false; }
  228. };
  229. /** A nested value is projected. */
  230. class ComputedNested : public ExpectedResultBase {
  231. public:
  232. virtual BSONObj source() { return BSON( "_id" << 0 ); }
  233. void prepareExpression() {
  234. expression()->addField( mongo::FieldPath( "a.b" ),
  235. ExpressionConstant::create( Value::createInt( 5 ) ) );
  236. }
  237. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 5 ) ); }
  238. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  239. BSONObj expectedBsonRepresentation() {
  240. return BSON( "a" << BSON( "b" << BSON( "$const" << 5 ) ) );
  241. }
  242. bool expectedIsSimple() { return false; }
  243. };
  244. /** A field path is projected. */
  245. class ComputedFieldPath : public ExpectedResultBase {
  246. public:
  247. virtual BSONObj source() { return BSON( "_id" << 0 << "x" << 4 ); }
  248. void prepareExpression() {
  249. expression()->addField( mongo::FieldPath( "a" ),
  250. ExpressionFieldPath::create( "x" ) );
  251. }
  252. BSONObj expected() { return BSON( "_id" << 0 << "a" << 4 ); }
  253. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "x" ); }
  254. BSONObj expectedBsonRepresentation() { return BSON( "a" << "$x" ); }
  255. bool expectedIsSimple() { return false; }
  256. };
  257. /** A nested field path is projected. */
  258. class ComputedNestedFieldPath : public ExpectedResultBase {
  259. public:
  260. virtual BSONObj source() { return BSON( "_id" << 0 << "x" << BSON( "y" << 4 ) ); }
  261. void prepareExpression() {
  262. expression()->addField( mongo::FieldPath( "a.b" ),
  263. ExpressionFieldPath::create( "x.y" ) );
  264. }
  265. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 4 ) ); }
  266. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" << "x.y" ); }
  267. BSONObj expectedBsonRepresentation() { return BSON( "a" << BSON( "b" << "$x.y" ) ); }
  268. bool expectedIsSimple() { return false; }
  269. };
  270. /** An empty subobject expression for a missing field is not projected. */
  271. class EmptyNewSubobject : public ExpectedResultBase {
  272. public:
  273. virtual BSONObj source() {
  274. return BSON( "_id" << 0 );
  275. }
  276. void prepareExpression() {
  277. // Create a sub expression returning an empty object.
  278. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  279. subExpression->addField( mongo::FieldPath( "b" ),
  280. ExpressionConstant::create( Value::getUndefined() ) );
  281. expression()->addField( mongo::FieldPath( "a" ), subExpression );
  282. }
  283. BSONObj expected() { return BSON( "_id" << 0 ); }
  284. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  285. BSONObj expectedBsonRepresentation() {
  286. return fromjson( "{a:{b:{$const:undefined}}}" );
  287. }
  288. bool expectedIsSimple() { return false; }
  289. };
  290. /** A non empty subobject expression for a missing field is projected. */
  291. class NonEmptyNewSubobject : public ExpectedResultBase {
  292. public:
  293. virtual BSONObj source() {
  294. return BSON( "_id" << 0 );
  295. }
  296. void prepareExpression() {
  297. // Create a sub expression returning an empty object.
  298. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  299. subExpression->addField( mongo::FieldPath( "b" ),
  300. ExpressionConstant::create( Value::createInt( 6 ) ) );
  301. expression()->addField( mongo::FieldPath( "a" ), subExpression );
  302. }
  303. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 6 ) ); }
  304. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  305. BSONObj expectedBsonRepresentation() {
  306. return fromjson( "{a:{b:{$const:6}}}" );
  307. }
  308. bool expectedIsSimple() { return false; }
  309. };
  310. /** Two computed fields within a common parent. */
  311. class AdjacentDottedComputedFields : public ExpectedResultBase {
  312. public:
  313. virtual BSONObj source() {
  314. return BSON( "_id" << 0 );
  315. }
  316. void prepareExpression() {
  317. expression()->addField( mongo::FieldPath( "a.b" ),
  318. ExpressionConstant::create( Value::createInt( 6 ) ) );
  319. expression()->addField( mongo::FieldPath( "a.c" ),
  320. ExpressionConstant::create( Value::createInt( 7 ) ) );
  321. }
  322. BSONObj expected() { return BSON( "_id" << 0 << "a" << BSON( "b" << 6 << "c" << 7 ) ); }
  323. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  324. BSONObj expectedBsonRepresentation() {
  325. return fromjson( "{a:{b:{$const:6},c:{$const:7}}}" );
  326. }
  327. bool expectedIsSimple() { return false; }
  328. };
  329. /** Two computed fields within a common parent, in one case dotted. */
  330. class AdjacentDottedAndNestedComputedFields : public AdjacentDottedComputedFields {
  331. void prepareExpression() {
  332. expression()->addField( mongo::FieldPath( "a.b" ),
  333. ExpressionConstant::create( Value::createInt( 6 ) ) );
  334. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  335. subExpression->addField( mongo::FieldPath( "c" ),
  336. ExpressionConstant::create( Value::createInt( 7 ) ) );
  337. expression()->addField( mongo::FieldPath( "a" ), subExpression );
  338. }
  339. };
  340. /** Two computed fields within a common parent, in another case dotted. */
  341. class AdjacentNestedAndDottedComputedFields : public AdjacentDottedComputedFields {
  342. void prepareExpression() {
  343. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  344. subExpression->addField( mongo::FieldPath( "b" ),
  345. ExpressionConstant::create( Value::createInt( 6 ) ) );
  346. expression()->addField( mongo::FieldPath( "a" ), subExpression );
  347. expression()->addField( mongo::FieldPath( "a.c" ),
  348. ExpressionConstant::create( Value::createInt( 7 ) ) );
  349. }
  350. };
  351. /** Two computed fields within a common parent, nested rather than dotted. */
  352. class AdjacentNestedComputedFields : public AdjacentDottedComputedFields {
  353. void prepareExpression() {
  354. intrusive_ptr<ExpressionObject> firstSubExpression = ExpressionObject::create();
  355. firstSubExpression->addField( mongo::FieldPath( "b" ),
  356. ExpressionConstant::create( Value::createInt( 6 ) ) );
  357. expression()->addField( mongo::FieldPath( "a" ), firstSubExpression );
  358. intrusive_ptr<ExpressionObject> secondSubExpression = ExpressionObject::create();
  359. secondSubExpression->addField( mongo::FieldPath( "c" ),
  360. ExpressionConstant::create
  361. ( Value::createInt( 7 ) ) );
  362. expression()->addField( mongo::FieldPath( "a" ), secondSubExpression );
  363. }
  364. };
  365. /** Field ordering is preserved when nested fields are merged. */
  366. class AdjacentNestedOrdering : public ExpectedResultBase {
  367. public:
  368. virtual BSONObj source() {
  369. return BSON( "_id" << 0 );
  370. }
  371. void prepareExpression() {
  372. expression()->addField( mongo::FieldPath( "a.b" ),
  373. ExpressionConstant::create( Value::createInt( 6 ) ) );
  374. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  375. // Add field 'd' then 'c'. Expect the same field ordering in the result doc.
  376. subExpression->addField( mongo::FieldPath( "d" ),
  377. ExpressionConstant::create( Value::createInt( 7 ) ) );
  378. subExpression->addField( mongo::FieldPath( "c" ),
  379. ExpressionConstant::create( Value::createInt( 8 ) ) );
  380. expression()->addField( mongo::FieldPath( "a" ), subExpression );
  381. }
  382. BSONObj expected() {
  383. return BSON( "_id" << 0 << "a" << BSON( "b" << 6 << "d" << 7 << "c" << 8 ) );
  384. }
  385. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  386. BSONObj expectedBsonRepresentation() {
  387. return fromjson( "{a:{b:{$const:6},d:{$const:7},c:{$const:8}}}" );
  388. }
  389. bool expectedIsSimple() { return false; }
  390. };
  391. /** Adjacent fields two levels deep. */
  392. class MultipleNestedFields : public ExpectedResultBase {
  393. public:
  394. virtual BSONObj source() {
  395. return BSON( "_id" << 0 );
  396. }
  397. void prepareExpression() {
  398. expression()->addField( mongo::FieldPath( "a.b.c" ),
  399. ExpressionConstant::create( Value::createInt( 6 ) ) );
  400. intrusive_ptr<ExpressionObject> bSubExpression = ExpressionObject::create();
  401. bSubExpression->addField( mongo::FieldPath( "d" ),
  402. ExpressionConstant::create( Value::createInt( 7 ) ) );
  403. intrusive_ptr<ExpressionObject> aSubExpression = ExpressionObject::create();
  404. aSubExpression->addField( mongo::FieldPath( "b" ), bSubExpression );
  405. expression()->addField( mongo::FieldPath( "a" ), aSubExpression );
  406. }
  407. BSONObj expected() {
  408. return BSON( "_id" << 0 << "a" << BSON( "b" << BSON( "c" << 6 << "d" << 7 ) ) );
  409. }
  410. BSONArray expectedDependencies() { return BSON_ARRAY( "_id" ); }
  411. BSONObj expectedBsonRepresentation() {
  412. return fromjson( "{a:{b:{c:{$const:6},d:{$const:7}}}}" );
  413. }
  414. bool expectedIsSimple() { return false; }
  415. };
  416. /** Two expressions cannot generate the same field. */
  417. class ConflictingExpressionFields : public Base {
  418. public:
  419. void run() {
  420. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  421. expression->addField( mongo::FieldPath( "a" ),
  422. ExpressionConstant::create( Value::createInt( 5 ) ) );
  423. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ), // Duplicate field.
  424. ExpressionConstant::create
  425. ( Value::createInt( 6 ) ) ),
  426. UserException );
  427. }
  428. };
  429. /** An expression field conflicts with an inclusion field. */
  430. class ConflictingInclusionExpressionFields : public Base {
  431. public:
  432. void run() {
  433. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  434. expression->includePath( "a" );
  435. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ),
  436. ExpressionConstant::create
  437. ( Value::createInt( 6 ) ) ),
  438. UserException );
  439. }
  440. };
  441. /** An inclusion field conflicts with an expression field. */
  442. class ConflictingExpressionInclusionFields : public Base {
  443. public:
  444. void run() {
  445. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  446. expression->addField( mongo::FieldPath( "a" ),
  447. ExpressionConstant::create( Value::createInt( 5 ) ) );
  448. ASSERT_THROWS( expression->includePath( "a" ),
  449. UserException );
  450. }
  451. };
  452. /** An object expression conflicts with a constant expression. */
  453. class ConflictingObjectConstantExpressionFields : public Base {
  454. public:
  455. void run() {
  456. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  457. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  458. subExpression->includePath( "b" );
  459. expression->addField( mongo::FieldPath( "a" ), subExpression );
  460. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a.b" ),
  461. ExpressionConstant::create
  462. ( Value::createInt( 6 ) ) ),
  463. UserException );
  464. }
  465. };
  466. /** A constant expression conflicts with an object expression. */
  467. class ConflictingConstantObjectExpressionFields : public Base {
  468. public:
  469. void run() {
  470. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  471. expression->addField( mongo::FieldPath( "a.b" ),
  472. ExpressionConstant::create( Value::createInt( 6 ) ) );
  473. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  474. subExpression->includePath( "b" );
  475. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ), subExpression ),
  476. UserException );
  477. }
  478. };
  479. /** Two nested expressions cannot generate the same field. */
  480. class ConflictingNestedFields : public Base {
  481. public:
  482. void run() {
  483. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  484. expression->addField( mongo::FieldPath( "a.b" ),
  485. ExpressionConstant::create( Value::createInt( 5 ) ) );
  486. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a.b" ), // Duplicate field.
  487. ExpressionConstant::create
  488. ( Value::createInt( 6 ) ) ),
  489. UserException );
  490. }
  491. };
  492. /** An expression cannot be created for a subfield of another expression. */
  493. class ConflictingFieldAndSubfield : public Base {
  494. public:
  495. void run() {
  496. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  497. expression->addField( mongo::FieldPath( "a" ),
  498. ExpressionConstant::create( Value::createInt( 5 ) ) );
  499. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a.b" ),
  500. ExpressionConstant::create
  501. ( Value::createInt( 5 ) ) ),
  502. UserException );
  503. }
  504. };
  505. /** An expression cannot be created for a nested field of another expression. */
  506. class ConflictingFieldAndNestedField : public Base {
  507. public:
  508. void run() {
  509. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  510. expression->addField( mongo::FieldPath( "a" ),
  511. ExpressionConstant::create( Value::createInt( 5 ) ) );
  512. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  513. subExpression->addField( mongo::FieldPath( "b" ),
  514. ExpressionConstant::create( Value::createInt( 5 ) ) );
  515. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ), subExpression ),
  516. UserException );
  517. }
  518. };
  519. /** An expression cannot be created for a parent field of another expression. */
  520. class ConflictingSubfieldAndField : public Base {
  521. public:
  522. void run() {
  523. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  524. expression->addField( mongo::FieldPath( "a.b" ),
  525. ExpressionConstant::create( Value::createInt( 5 ) ) );
  526. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ),
  527. ExpressionConstant::create
  528. ( Value::createInt( 5 ) ) ),
  529. UserException );
  530. }
  531. };
  532. /** An expression cannot be created for a parent of a nested field. */
  533. class ConflictingNestedFieldAndField : public Base {
  534. public:
  535. void run() {
  536. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  537. intrusive_ptr<ExpressionObject> subExpression = ExpressionObject::create();
  538. subExpression->addField( mongo::FieldPath( "b" ),
  539. ExpressionConstant::create( Value::createInt( 5 ) ) );
  540. expression->addField( mongo::FieldPath( "a" ), subExpression );
  541. ASSERT_THROWS( expression->addField( mongo::FieldPath( "a" ),
  542. ExpressionConstant::create
  543. ( Value::createInt( 5 ) ) ),
  544. UserException );
  545. }
  546. };
  547. /** Dependencies for non inclusion expressions. */
  548. class NonInclusionDependencies : public Base {
  549. public:
  550. void run() {
  551. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  552. expression->addField( mongo::FieldPath( "a" ),
  553. ExpressionConstant::create( Value::createInt( 5 ) ) );
  554. assertDependencies( BSON_ARRAY( "_id" ), expression, true );
  555. assertDependencies( BSONArray(), expression, false );
  556. expression->addField( mongo::FieldPath( "b" ),
  557. ExpressionFieldPath::create( "c.d" ) );
  558. assertDependencies( BSON_ARRAY( "_id" << "c.d" ), expression, true );
  559. assertDependencies( BSON_ARRAY( "c.d" ), expression, false );
  560. }
  561. };
  562. /** Dependencies for inclusion expressions. */
  563. class InclusionDependencies : public Base {
  564. public:
  565. void run() {
  566. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  567. expression->includePath( "a" );
  568. assertDependencies( BSON_ARRAY( "_id" << "a" ), expression, true );
  569. set<string> unused;
  570. // 'path' must be provided for inclusion expressions.
  571. ASSERT_THROWS( expression->addDependencies( unused ), UserException );
  572. }
  573. };
  574. /** Optimizing an object expression optimizes its sub expressions. */
  575. class Optimize : public Base {
  576. public:
  577. void run() {
  578. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  579. // Add inclusion.
  580. expression->includePath( "a" );
  581. // Add non inclusion.
  582. expression->addField( mongo::FieldPath( "b" ), ExpressionAnd::create() );
  583. expression->optimize();
  584. // Optimizing 'expression' optimizes its non inclusion sub expressions, while
  585. // inclusion sub expressions are passed through.
  586. ASSERT_EQUALS( BSON( "a" << true << "b" << BSON( "$const" << true ) ),
  587. expressionToBson( expression ) );
  588. }
  589. };
  590. /** Serialize to a BSONObj. */
  591. class AddToBsonObj : public Base {
  592. public:
  593. void run() {
  594. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  595. expression->addField( mongo::FieldPath( "a" ),
  596. ExpressionConstant::create( Value::createInt( 5 ) ) );
  597. BSONObjBuilder bob;
  598. expression->addToBsonObj( &bob, "foo", false );
  599. ASSERT_EQUALS( BSON( "foo" << BSON( "a" << 5 ) ), bob.obj() );
  600. }
  601. };
  602. /** Serialize to a BSONObj, with constants represented by expressions. */
  603. class AddToBsonObjRequireExpression : public Base {
  604. public:
  605. void run() {
  606. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  607. expression->addField( mongo::FieldPath( "a" ),
  608. ExpressionConstant::create( Value::createInt( 5 ) ) );
  609. BSONObjBuilder bob;
  610. expression->addToBsonObj( &bob, "foo", true );
  611. ASSERT_EQUALS( BSON( "foo" << BSON( "a" << BSON( "$const" << 5 ) ) ), bob.obj() );
  612. }
  613. };
  614. /** Serialize to a BSONArray. */
  615. class AddToBsonArray : public Base {
  616. public:
  617. void run() {
  618. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  619. expression->addField( mongo::FieldPath( "a" ),
  620. ExpressionConstant::create( Value::createInt( 5 ) ) );
  621. BSONArrayBuilder bab;
  622. expression->addToBsonArray( &bab );
  623. ASSERT_EQUALS( BSON_ARRAY( BSON( "a" << 5 ) ), bab.arr() );
  624. }
  625. };
  626. /**
  627. * evaluate() does not supply an inclusion document. Inclusion spec'd fields are not
  628. * included. (Inclusion specs are not generally expected/allowed in cases where evaluate
  629. * is called instead of addToDocument.)
  630. */
  631. class Evaluate : public Base {
  632. public:
  633. void run() {
  634. intrusive_ptr<ExpressionObject> expression = ExpressionObject::create();
  635. expression->includePath( "a" );
  636. expression->addField( mongo::FieldPath( "b" ),
  637. ExpressionConstant::create( Value::createInt( 5 ) ) );
  638. expression->addField( mongo::FieldPath( "c" ),
  639. ExpressionFieldPath::create( "a" ) );
  640. ASSERT_EQUALS( BSON( "b" << 5 << "c" << 1 ),
  641. toBson( expression->evaluate
  642. ( fromBson
  643. ( BSON( "_id" << 0 << "a" << 1 ) ) )->getDocument() ) );
  644. }
  645. };