This project has retired. For details please refer to its
Attic page.
QueryTypesTest xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.inmemory.query;
20
21 import static org.junit.Assert.*;
22
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.antlr.runtime.RecognitionException;
28 import org.antlr.runtime.tree.Tree;
29 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
30 import org.apache.chemistry.opencmis.inmemory.TypeManagerImpl;
31 import org.apache.chemistry.opencmis.server.support.query.AbstractPredicateWalker;
32 import org.apache.chemistry.opencmis.server.support.query.CmisQueryWalker;
33 import org.apache.chemistry.opencmis.server.support.query.CmisSelector;
34 import org.apache.chemistry.opencmis.server.support.query.ColumnReference;
35 import org.apache.chemistry.opencmis.server.support.query.QueryObject;
36 import org.apache.chemistry.opencmis.server.support.query.QueryObject.SortSpec;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.junit.After;
40 import org.junit.Before;
41 import org.junit.Test;
42
43 public class QueryTypesTest extends AbstractQueryTest {
44
45 private static final Log LOG = LogFactory.getLog(QueryTypesTest.class);
46 private TypeManagerImpl tm;
47 private TestPredicateWalker pw;
48
49 public static class TestPredicateWalker extends AbstractPredicateWalker {
50 List<Integer> ids = new LinkedList<Integer>();
51 @Override
52 public Object walkId(Tree node) {
53 ids.add(node.getTokenStartIndex());
54 return null;
55 }
56 }
57
58 @Before
59 public void setUp() {
60 tm = new TypeManagerImpl();
61 tm.initTypeSystem(null);
62
63
64 List<TypeDefinition> typeDefs = super.createTypes();
65 for (TypeDefinition typeDef : typeDefs) {
66 tm.addTypeDefinition(typeDef);
67 }
68
69
70
71 pw = new TestPredicateWalker();
72 super.setUp(new QueryObject(tm), pw);
73 }
74
75 @After
76 public void tearDown() {
77 }
78
79 @Test
80 public void resolveTypesTest1() throws Exception {
81 String statement = "SELECT " + TITLE_PROP + ", " + AUTHOR_PROP + " FROM " + BOOK_TYPE + " AS BooksAlias WHERE " + ISBN_PROP + " = '100'";
82 verifyResolveSelect(statement);
83 }
84
85 @Test
86 public void resolveTypesTest2() throws Exception {
87 String statement = "SELECT BookType.Title, BookType.Author FROM BookType WHERE ISBN = '100'";
88 verifyResolveSelect(statement);
89 }
90
91 @Test
92 public void resolveTypesTest3() throws Exception {
93 String statement = "SELECT BookType.Title, BookType.Author FROM BookType AS BooksAlias WHERE ISBN = '100'";
94 verifyResolveSelect(statement);
95 }
96
97 @Test
98 public void resolveTypesTest4() throws Exception {
99 String statement = "SELECT BooksAlias.Title, BooksAlias.Author FROM BookType AS BooksAlias WHERE ISBN = '100'";
100 verifyResolveSelect(statement);
101 }
102
103 @Test
104 public void resolveTypesTest5() throws Exception {
105 String statement = "SELECT BooksAlias.Title AS abc, BooksAlias.Author def FROM BookType AS BooksAlias WHERE ISBN = '100'";
106 verifyResolveSelect(statement);
107 }
108
109 @Test
110 public void resolveTypesTest6() {
111 String statement = "SELECT BookType.UnknownProperty FROM BookType WHERE ISBN = '100'";
112 try {
113 verifyResolveSelect(statement);
114 fail("Select of unknown property in type should fail.");
115 } catch (Exception e) {
116 assertTrue(e instanceof RecognitionException);
117 LOG.debug("resolveTypesTest6(), e: " + e.getMessage());
118 assertTrue(e.toString().contains("is not a valid property query name in"));
119 }
120 }
121
122 @Test
123 public void resolveTypesTest7() {
124 String statement = "SELECT UnknownProperty FROM BookType WHERE ISBN = '100'";
125 try {
126 verifyResolveSelect(statement);
127 fail("Select of unknown property in type should fail.");
128 } catch (Exception e) {
129 assertTrue(e instanceof RecognitionException);
130 assertTrue(e.toString().contains("is not a property query name in any"));
131 }
132 }
133
134 @Test
135 public void resolveTypesTest8() throws Exception {
136 String statement = "SELECT BookType.Title, BookType.Author FROM BookType WHERE ISBN = '100'";
137 verifyResolveSelect(statement);
138 }
139
140 @Test
141 public void resolveTypesTest9() throws Exception {
142 String statement = "SELECT BookType.Author, Title TitleAlias FROM BookType WHERE TitleAlias <> 'Harry Potter'";
143 verifyResolveSelect(statement);
144 }
145
146 @Test
147 public void resolveTypesTest10() throws Exception {
148 String statement = "SELECT BookType.Author, BookType.Title TitleAlias FROM BookType WHERE TitleAlias <> 'Harry Potter'";
149 verifyResolveSelect(statement);
150 }
151
152 private void verifyResolveSelect(String statement) throws Exception {
153 CmisQueryWalker walker = traverseStatement(statement);
154 assertNotNull(walker);
155 Map<String,String> types = queryObj.getTypes();
156 assertTrue(1 == types.size());
157 List<CmisSelector> selects = queryObj.getSelectReferences();
158 assertTrue(2 == selects.size());
159 for (CmisSelector select : selects) {
160 assertTrue(select instanceof ColumnReference);
161 ColumnReference colRef = ((ColumnReference) select);
162 assertEquals(bookType, colRef.getTypeDefinition());
163 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP) || colRef.getPropertyQueryName().equals(AUTHOR_PROP));
164 }
165 }
166
167 @Test
168 public void resolveTypesWithTwoFromsQualified() throws Exception {
169 String statement = "SELECT BookType.Title, MyDocType.MyStringProp FROM BookType JOIN MyDocType WHERE BookType.ISBN = '100'";
170
171 CmisQueryWalker walker = traverseStatement(statement);
172 assertNotNull(walker);
173 Map<String,String> types = queryObj.getTypes();
174 assertTrue(2 == types.size());
175 List<CmisSelector> selects = queryObj.getSelectReferences();
176 assertTrue(2 == selects.size());
177
178 ColumnReference colRef = ((ColumnReference) selects.get(0));
179 assertEquals(colRef.getTypeDefinition(), bookType);
180 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP));
181
182 colRef = ((ColumnReference) selects.get(1));
183 assertEquals(colRef.getTypeDefinition(), myType);
184 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
185 }
186
187 @Test
188 public void resolveTypesWithTwoFromsSameTypeCorrectlyQualified()
189 throws Exception {
190 String statement = "SELECT A.Title FROM BookType A JOIN BookType B";
191
192 CmisQueryWalker walker = traverseStatement(statement);
193 assertNotNull(walker);
194 Map<String, String> types = queryObj.getTypes();
195 assertEquals(2, types.size());
196 List<CmisSelector> selects = queryObj.getSelectReferences();
197 assertEquals(1, selects.size());
198 ColumnReference colRef = ((ColumnReference) selects.get(0));
199 assertEquals(bookType, colRef.getTypeDefinition());
200 assertEquals(TITLE_PROP, colRef.getPropertyQueryName());
201 assertEquals("A", colRef.getQualifier());
202 }
203
204 @Test
205 public void resolveTypesWithTwoFromsSameTypeAmbiguouslyQualified()
206 throws Exception {
207 String statement = "SELECT BookType.Title FROM BookType A JOIN BookType B";
208 try {
209 traverseStatement(statement);
210 fail("Select with an ambiguously qualified property should fail.");
211 } catch (Exception e) {
212 assertTrue(e instanceof RecognitionException);
213 assertTrue(e.toString().contains(
214 "BookType is an ambiguous type query name"));
215 }
216 }
217
218 @Test
219 public void resolveTypesWithTwoFromsUnqualified() throws Exception {
220 String statement = "SELECT Title, MyStringProp FROM BookType JOIN MyDocType AS MyDocAlias WHERE BookType.ISBN = '100'";
221
222 CmisQueryWalker walker = traverseStatement(statement);
223 assertNotNull(walker);
224 Map<String,String> types = queryObj.getTypes();
225 assertTrue(2 == types.size());
226 List<CmisSelector> selects = queryObj.getSelectReferences();
227 assertTrue(2 == selects.size());
228
229 ColumnReference colRef = ((ColumnReference) selects.get(0));
230 assertEquals(colRef.getTypeDefinition(), bookType);
231 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP));
232
233 colRef = ((ColumnReference) selects.get(1));
234 assertEquals(colRef.getTypeDefinition(), myType);
235 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
236 }
237
238 @Test
239 public void resolveTypesWithTwoFromsNotUnique() {
240 String statement = "SELECT MyStringProp FROM MyDocTypeCopy JOIN MyDocType";
241
242 try {
243 traverseStatement(statement);
244 fail("Select with an unqualified property that is not unique should fail.");
245 } catch (Exception e) {
246 assertTrue(e instanceof RecognitionException);
247 assertTrue(e.toString().contains("is not a unique property query name within the types in from"));
248 }
249 }
250
251 @Test
252 public void resolveTypesWithTwoFromsUniqueByQualifying() throws Exception {
253 String statement = "SELECT MyDocType.MyStringProp FROM MyDocTypeCopy JOIN MyDocType";
254
255 CmisQueryWalker walker = traverseStatement(statement);
256 assertNotNull(walker);
257 Map<String,String> types = queryObj.getTypes();
258 assertTrue(2 == types.size());
259 List<CmisSelector> selects = queryObj.getSelectReferences();
260 assertTrue(1 == selects.size());
261 ColumnReference colRef = ((ColumnReference) selects.get(0));
262 assertEquals(myType, colRef.getTypeDefinition());
263 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
264 }
265
266 @Test
267 public void resolveTypesTest11() throws Exception {
268 String statement = "SELECT BookType.* FROM BookType WHERE ISBN = '100'";
269 CmisQueryWalker walker = traverseStatement(statement);
270 assertNotNull(walker);
271 Map<String,String> types = queryObj.getTypes();
272 assertTrue(1 == types.size());
273 List<CmisSelector> selects = queryObj.getSelectReferences();
274 assertTrue(1 == selects.size());
275 ColumnReference colRef = ((ColumnReference) selects.get(0));
276 assertTrue(colRef.getPropertyQueryName().equals("*"));
277 assertEquals(bookType, colRef.getTypeDefinition());
278 }
279
280 @Test
281 public void resolveTypesTest12() throws Exception {
282 String statement = "SELECT * FROM MyDocTypeCopy JOIN MyDocType";
283 CmisQueryWalker walker = traverseStatement(statement);
284 assertNotNull(walker);
285 Map<String,String> types = queryObj.getTypes();
286 assertTrue(2 == types.size());
287 List<CmisSelector> selects = queryObj.getSelectReferences();
288 assertTrue(1 == selects.size());
289 ColumnReference colRef = ((ColumnReference) selects.get(0));
290 assertTrue(colRef.getPropertyQueryName().equals("*"));
291 assertEquals(null, colRef.getTypeDefinition());
292 }
293
294 @Test
295 public void resolveTypesWhere1() throws Exception {
296 String statement = "SELECT * FROM BookType WHERE ISBN = '100'";
297 verifyResolveWhere(statement);
298 }
299
300 @Test
301 public void resolveTypesWhere2() throws Exception {
302 String statement = "SELECT * FROM BookType WHERE BookType.ISBN = '100'";
303 verifyResolveWhere(statement);
304 }
305
306 @Test
307 public void resolveTypesWhere3() throws Exception {
308 String statement = "SELECT * FROM BookType As BookAlias WHERE BookAlias.ISBN = '100'";
309 verifyResolveWhere(statement);
310 }
311
312 @Test
313 public void resolveTypesWhere4() throws Exception {
314 String statement = "SELECT BookType.ISBN IsbnAlias FROM BookType WHERE IsbnAlias < '100'";
315 verifyResolveWhere(statement);
316 }
317
318 @Test
319 public void resolveTypesWhereWithTwoFromsUnqualified() throws Exception {
320 String statement = "SELECT * FROM BookType JOIN MyDocType WHERE ISBN = '100'";
321 CmisQueryWalker walker = traverseStatement(statement);
322 assertNotNull(walker);
323 List<CmisSelector> wheres = queryObj.getWhereReferences();
324 assertTrue(1 == wheres.size());
325 for (CmisSelector where : wheres) {
326 assertTrue(where instanceof ColumnReference);
327 ColumnReference colRef = ((ColumnReference) where);
328 assertEquals(colRef.getTypeDefinition(), bookType);
329 assertTrue(colRef.getPropertyQueryName().equals(ISBN_PROP));
330 }
331 }
332
333 @Test
334 public void resolveTypesWhereWithTwoFromsQualified() throws Exception {
335 String statement = "SELECT * FROM BookType JOIN MyDocType AS MyDocAlias WHERE BookType.ISBN = '100'";
336 CmisQueryWalker walker = traverseStatement(statement);
337 assertNotNull(walker);
338 List<CmisSelector> wheres = queryObj.getWhereReferences();
339 assertTrue(1 == wheres.size());
340 for (CmisSelector where : wheres) {
341 assertTrue(where instanceof ColumnReference);
342 ColumnReference colRef = ((ColumnReference) where);
343 assertEquals(colRef.getTypeDefinition(), bookType);
344 assertTrue(colRef.getPropertyQueryName().equals(ISBN_PROP));
345 }
346 }
347
348
349 @Test
350 public void resolveTypesWhereWithTwoFromsQualifiedWithAlias() throws Exception {
351 String statement = "SELECT * FROM BookType AS MyBookAlias JOIN MyDocType WHERE MyBookAlias.ISBN = '100'";
352 CmisQueryWalker walker = traverseStatement(statement);
353 assertNotNull(walker);
354 List<CmisSelector> wheres = queryObj.getWhereReferences();
355 assertTrue(1 == wheres.size());
356 for (CmisSelector where : wheres) {
357 assertTrue(where instanceof ColumnReference);
358 ColumnReference colRef = ((ColumnReference) where);
359 assertEquals(colRef.getTypeDefinition(), bookType);
360 assertTrue(colRef.getPropertyQueryName().equals(ISBN_PROP));
361 }
362 }
363
364 @Test
365 public void resolveTypesWhereWithTwoFromsQualifiedWithAlias2() throws Exception {
366
367 String statement = "SELECT MyBookAlias.Title FROM BookType AS MyBookAlias WHERE MyBookAlias.ISBN = '100'";
368 CmisQueryWalker walker = traverseStatement(statement);
369 assertNotNull(walker);
370 List<CmisSelector> wheres = queryObj.getWhereReferences();
371 assertTrue(1 == wheres.size());
372 for (CmisSelector where : wheres) {
373 assertTrue(where instanceof ColumnReference);
374 ColumnReference colRef = ((ColumnReference) where);
375 assertEquals(colRef.getTypeDefinition(), bookType);
376 }
377 }
378
379 private void verifyResolveWhere(String statement) throws Exception {
380 CmisQueryWalker walker = traverseStatement(statement);
381 assertNotNull(walker);
382 Map<String,String> types = queryObj.getTypes();
383 assertTrue(1 == types.size());
384 List<CmisSelector> wheres = queryObj.getWhereReferences();
385 assertTrue(1 == wheres.size());
386 for (CmisSelector where : wheres) {
387 assertTrue(where instanceof ColumnReference);
388 ColumnReference colRef = ((ColumnReference) where);
389 assertEquals(bookType, colRef.getTypeDefinition());
390 assertTrue(colRef.getPropertyQueryName().equals(ISBN_PROP));
391 }
392 }
393
394 @Test
395 public void resolveTypesWhereWithTwoFromsNotUnique() {
396 String statement = "SELECT * FROM MyDocTypeCopy JOIN MyDocType WHERE MyStringProp = '100'";
397
398 try {
399 traverseStatement(statement);
400 fail("Select with an unqualified property that is not unique should fail.");
401 } catch (Exception e) {
402 assertTrue(e instanceof RecognitionException);
403 assertTrue(e.toString().contains("is not a unique property query name within the types in from"));
404 }
405 }
406
407 @Test
408 public void resolveTypesWhereWithTwoFromsUniqueByQualifying() throws Exception {
409 String statement = "SELECT * FROM MyDocTypeCopy JOIN MyDocType WHERE MyDocType.MyStringProp = '100'";
410 CmisQueryWalker walker = traverseStatement(statement);
411 assertNotNull(walker);
412 List<CmisSelector> wheres = queryObj.getWhereReferences();
413 assertTrue(1 == wheres.size());
414 for (CmisSelector where : wheres) {
415 assertTrue(where instanceof ColumnReference);
416 ColumnReference colRef = ((ColumnReference) where);
417 assertEquals(colRef.getTypeDefinition(), myType);
418 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
419 }
420 }
421
422 @Test
423 public void resolveTypesOrderBy() throws Exception {
424 String statement = "SELECT Title AS TitleAlias FROM BookType WHERE Author = 'Jim' ORDER BY TitleAlias";
425 CmisQueryWalker walker = traverseStatement(statement);
426 assertNotNull(walker);
427 List<SortSpec> sorts = queryObj.getOrderBys();
428 assertTrue(1 == sorts.size());
429 for (SortSpec sort : sorts) {
430 assertTrue(sort.getSelector() instanceof ColumnReference);
431 ColumnReference colRef = ((ColumnReference) sort.getSelector());
432 assertEquals(colRef.getTypeDefinition(), bookType);
433 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP));
434 }
435 }
436
437 @Test
438 public void resolveTypesOrderBy2() throws Exception {
439 String statement = "SELECT Title AS TitleAlias FROM BookType WHERE Author = 'Jim' ORDER BY BookType.Author";
440 CmisQueryWalker walker = traverseStatement(statement);
441 assertNotNull(walker);
442 List<SortSpec> sorts = queryObj.getOrderBys();
443 assertTrue(1 == sorts.size());
444 for (SortSpec sort : sorts) {
445 assertTrue(sort.getSelector() instanceof ColumnReference);
446 ColumnReference colRef = ((ColumnReference) sort.getSelector());
447 assertEquals(colRef.getTypeDefinition(), bookType);
448 assertTrue(colRef.getPropertyQueryName().equals(AUTHOR_PROP));
449 }
450 }
451
452 @Test
453 public void resolveTypesOrderBy3() throws Exception {
454 String statement = "SELECT Title FROM BookType WHERE ISBN < '100' ORDER BY Author";
455 CmisQueryWalker walker = traverseStatement(statement);
456 assertNotNull(walker);
457 List<SortSpec> sorts = queryObj.getOrderBys();
458 assertTrue(1 == sorts.size());
459 for (SortSpec sort : sorts) {
460 assertTrue(sort.getSelector() instanceof ColumnReference);
461 ColumnReference colRef = ((ColumnReference) sort.getSelector());
462 assertEquals(colRef.getTypeDefinition(), bookType);
463 assertTrue(colRef.getPropertyQueryName().equals(AUTHOR_PROP));
464 }
465 }
466
467 @Test
468 public void resolveJoinTypesSimple() throws Exception {
469 String statement = "SELECT * FROM MyDocType JOIN BookType ON MyDocType.MyStringProp = BookType.Title";
470 CmisQueryWalker walker = traverseStatement(statement);
471 assertNotNull(walker);
472 List<CmisSelector> joins = queryObj.getJoinReferences();
473 assertTrue(2 == joins.size());
474 for (CmisSelector join : joins) {
475 assertTrue(join instanceof ColumnReference);
476 ColumnReference colRef = ((ColumnReference) join);
477 if (myType.equals(colRef.getTypeDefinition())) {
478 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
479 } else if (bookType.equals(colRef.getTypeDefinition())) {
480 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP));
481 } else {
482 fail("Unexpected type in JOIN reference");
483 }
484 }
485 }
486
487 @Test
488 public void resolveJoinTypesWithAlias() throws Exception {
489 String statement = "SELECT Y.ISBN, X.MyBooleanProp, Y.Author FROM (MyDocType AS X JOIN BookType AS Y ON X.MyStringProp = Y.Title) "+
490 "WHERE ('Joe' = ANY Y.Author)";
491
492
493
494 CmisQueryWalker walker = traverseStatement(statement);
495 assertNotNull(walker);
496 List<CmisSelector> joins = queryObj.getJoinReferences();
497 assertTrue(2 == joins.size());
498 for (CmisSelector join : joins) {
499 assertTrue(join instanceof ColumnReference);
500 ColumnReference colRef = ((ColumnReference) join);
501 if (myType.equals(colRef.getTypeDefinition())) {
502 assertTrue(colRef.getPropertyQueryName().equals(STRING_PROP));
503 } else if (bookType.equals(colRef.getTypeDefinition())) {
504 assertTrue(colRef.getPropertyQueryName().equals(TITLE_PROP));
505 } else {
506 fail("Unexpected type in JOIN reference");
507 }
508 }
509 }
510
511 @Test
512 public void resolveTypeQualifiers1() throws Exception {
513 String statement = "SELECT Title FROM BookType WHERE IN_TREE(BookType, 'foo')";
514 CmisQueryWalker walker = traverseStatement(statement);
515 assertNotNull(walker);
516 assertEquals("BookType", queryObj.getTypeReference(pw.ids.get(0)));
517 }
518
519 @Test
520 public void resolveTypeQualifiers2() throws Exception {
521 String statement = "SELECT Title FROM BookType B WHERE IN_TREE(B, 'foo')";
522 CmisQueryWalker walker = traverseStatement(statement);
523 assertNotNull(walker);
524 assertEquals("B", queryObj.getTypeReference(pw.ids.get(0)));
525 }
526
527 @Test
528 public void resolveTypeQualifiers3() throws Exception {
529 String statement = "SELECT Title FROM BookType B WHERE IN_TREE(BookType, 'foo')";
530 CmisQueryWalker walker = traverseStatement(statement);
531 assertNotNull(walker);
532 assertEquals("B", queryObj.getTypeReference(pw.ids.get(0)));
533 }
534
535 @Test
536 public void resolveTypeQualifiers4() throws Exception {
537 String statement = "SELECT Title FROM BookType B WHERE IN_TREE(dummy, 'foo')";
538 try {
539 traverseStatement(statement);
540 fail("invalid correlation name should fail");
541 } catch (Exception e) {
542 assertTrue(e instanceof RecognitionException);
543 assertTrue(e.toString().contains(
544 "dummy is neither a type query name nor an alias"));
545 }
546 }
547
548 @Test
549 public void resolveTypeQualifiers5() throws Exception {
550 String statement = "SELECT B1.Title FROM BookType B1 JOIN BookType B2"
551 + " WHERE IN_TREE(B1, 'foo') OR IN_TREE(B2, 'bar')";
552 CmisQueryWalker walker = traverseStatement(statement);
553 assertNotNull(walker);
554 assertEquals("B1", queryObj.getTypeReference(pw.ids.get(0)));
555 assertEquals("B2", queryObj.getTypeReference(pw.ids.get(1)));
556 }
557
558 @Test
559 public void resolveTypeQualifiers6() throws Exception {
560 String statement = "SELECT B.Title FROM BookType B JOIN MyDocType D"
561 + " WHERE IN_TREE(MyDocType, 'foo')";
562 CmisQueryWalker walker = traverseStatement(statement);
563 assertNotNull(walker);
564 assertEquals("D", queryObj.getTypeReference(pw.ids.get(0)));
565 }
566
567 @Test
568 public void resolveTypeQualifiers7() throws Exception {
569 String statement = "SELECT B1.Title FROM BookType B1 JOIN BookType B2"
570 + " WHERE IN_TREE(BookType, 'foo')";
571 try {
572 traverseStatement(statement);
573 fail("ambiguous correlation name should fail");
574 } catch (Exception e) {
575 assertTrue(e instanceof RecognitionException);
576 assertTrue(e.toString().contains(
577 "BookType is an ambiguous type query name"));
578 }
579 }
580
581 }