def test_distinct(self): qs = QuerySet(using=self.db, collection=COLLECTION, xpath='//name') vals = qs.distinct() self.assertTrue('one' in vals) self.assertTrue('two' in vals) self.assertTrue('three' in vals) self.assertTrue('four' in vals) self.assertTrue('abc' not in vals)
def setUp(self): self.db = ExistDB(server_url=EXISTDB_SERVER_URL, username=EXISTDB_SERVER_USER, password=EXISTDB_SERVER_PASSWORD) load_fixtures(self.db) self.qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel)
def test_filter_fulltext_options(self): qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel, fulltext_options={'default-operator': 'and'}) # search for terms present in fixtures - but not both present in one doc fqs = qs.filter(description__fulltext_terms='only third') # for now, just confirm that the option is passed through to query self.assertTrue( '<default-operator>and</default-operator>' in fqs.query.getQuery())
def setUp(self): self.db = ExistDB(server_url=EXISTDB_SERVER_URL, username=EXISTDB_SERVER_USER, password=EXISTDB_SERVER_PASSWORD) # create index for collection - should be applied to newly loaded files self.db.loadCollectionIndex(COLLECTION, self.FIXTURE_INDEX) load_fixtures(self.db) self.qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel)
def test_also_subfield(self): class SubqueryTestModel(xmlmap.XmlObject): subname = xmlmap.StringField('subname') parent = xmlmap.NodeField('parent::root', QueryTestModel) qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='//sub') name = qs.also('parent__id', 'parent__wnn').get(subname__exact='la') self.assertEqual('la', name.subname) self.assertEqual('one', name.parent.id) self.assertEqual(42, name.parent.wnn)
def test_also(self): class SubqueryTestModel(xmlmap.XmlObject): name = xmlmap.StringField('.') parent_id = xmlmap.StringField('parent::root/@id') qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='//name') name = qs.also('parent_id').get(name__exact='two') self.assertEqual( 'abc', name.parent_id, "parent id set correctly when returning at name level with also parent_id specified; should be 'abc', got '" + name.parent_id + "'")
def test_filter_gtelte(self): # < <= > >= # subclass to add a numeric field to test with class CountQueryTestModel(QueryTestModel): name_count = xmlmap.IntegerField('count(name)') qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=CountQueryTestModel) # each fixture has one and only one name self.assertEqual(0, qs.filter(name_count__gt=1).count()) self.assertEqual(4, qs.filter(name_count__gte=1).count()) self.assertEqual(4, qs.filter(name_count__lte=1).count()) self.assertEqual(0, qs.filter(name_count__lt=1).count())
def test_only_raw(self): qs = self.qs.only_raw( id='xs:string(%(xq_var)s//name/ancestor::root/@id)').filter( name='two') self.assertEqual('abc', qs[0].id) # filtered version obj = qs.get() self.assertEqual('abc', obj.id) # when combined with regular only, other fields come back correctly qs = self.qs.only('name', 'description', 'substring') obj = qs.only_raw( id='xs:string(%(xq_var)s//name/ancestor::root/@id)').get(id='abc') self.assertEqual('two', obj.name) self.assertEqual('t', obj.substring) self.assertEqual('this one only has two', obj.description) self.assertEqual('abc', obj.id) # subfield obj = qs.only_raw( sub__subname='normalize-space(%(xq_var)s//subname)').get(id='one') self.assertEqual('la', obj.sub.subname) # multiple parameters obj = self.qs.filter(id='abc').only_raw( id='string(%(xq_var)s/@id)', name='normalize-space(%(xq_var)s//name)').get(id='abc') self.assertEqual('abc', obj.id) self.assertEqual('two', obj.name) # list field - multiple return values class MyQueryTest(QueryTestModel): name = xmlmap.StringListField('name') qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=MyQueryTest) # return one object but find all the names in the test collection obj = qs.filter(id='abc').only_raw(name='collection("/db%s")//name' % COLLECTION).get(id='abc') # 4 names in test fixtures - should come back as a list of those 4 names self.assertEqual(4, len(obj.name))
def test_also_raw(self): class SubqueryTestModel(QueryTestModel): myid = xmlmap.StringField('@id') qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='/root') qs = qs.filter(id='abc').also_raw( myid='string(%(xq_var)s//name/ancestor::root/@id)') self.assertEqual('abc', qs[0].myid) # filtered version of the queryset with raw obj = qs.filter(name='two').get() self.assertEqual('abc', obj.myid) # multiple parameters obj = qs.filter(id='abc').also_raw( id='string(%(xq_var)s/@id)', name='normalize-space(%(xq_var)s//name)').get(id='abc') self.assertEqual('abc', obj.id) self.assertEqual('two', obj.name)
def get_query_set(self): """ Get the default :class:`pyexistdb.db.QuerySet` returned by this ``Manager``. Typically this returns a ``QuerySet`` based on the ``Manager``'s `xpath`, evaluated in the ``settings.EXISTDB_ROOT_COLLECTION`` on a default :class:`pyexistdb.db.ExistDB`. This is a convenient point for developers to customize an object's managers. Deriving a child class from Manager and overriding or extending this method is a handy way to create custom queries accessible from an :class:`~eulexistdb.models.XmlModel`. """ if hasattr(settings, 'EXISTDB_FULLTEXT_OPTIONS'): fulltext_opts = settings.EXISTDB_FULLTEXT_OPTIONS else: fulltext_opts = {} return QuerySet(model=self.model, xpath=self.xpath, using=ExistDB(), collection=settings.EXISTDB_ROOT_COLLECTION, fulltext_options=fulltext_opts)
class ExistQueryTest(unittest.TestCase): def setUp(self): self.db = ExistDB(server_url=EXISTDB_SERVER_URL, username=EXISTDB_SERVER_USER, password=EXISTDB_SERVER_PASSWORD) load_fixtures(self.db) self.qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel) def tearDown(self): self.db.removeCollection(COLLECTION) # release any queryset sessions before test user account # is removed in module teardown del self.qs def test_count(self): load_fixtures(self.db) self.assertEqual(NUM_FIXTURES, self.qs.count(), "queryset count returns number of fixtures") def test_getitem(self): qs = self.qs.order_by('id') # adding sort order to test reliably self.assertEqual("abc", qs[0].id) self.assertEqual("def", qs[1].id) self.assertEqual("one", qs[2].id) self.assertEqual("xyz", qs[3].id) # test getting single item beyond initial set qs = self.qs.order_by('id') # load initial result cache self.assertEqual("abc", qs[0].id) # retrieve individual items beyond the current cache self.assertEqual("one", qs[2].id) self.assertEqual("xyz", qs[3].id) def test_getitem_typeerror(self): self.assertRaises(TypeError, self.qs.__getitem__, "foo") def test_getitem_indexerror(self): self.assertRaises(IndexError, self.qs.__getitem__, -1) self.assertRaises(IndexError, self.qs.__getitem__, 23) def test_getslice(self): slice = self.qs.order_by('id')[0:2] self.assertTrue(isinstance(slice, QuerySet)) self.assertTrue(isinstance(slice[0], QueryTestModel)) self.assertEqual(2, slice.count()) self.assertEqual(2, len(slice)) self.assertEqual('abc', slice[0].id) self.assertEqual('def', slice[1].id) self.assertRaises(IndexError, slice.__getitem__, 2) slice = self.qs.order_by('id')[1:3] self.assertEqual('def', slice[0].id) self.assertEqual('one', slice[1].id) slice = self.qs.order_by('id')[3:5] self.assertEqual(1, slice.count()) self.assertEqual('xyz', slice[0].id) self.assertRaises(IndexError, slice.__getitem__, 1) # test slicing with unspecified bounds slice = self.qs.order_by('id')[:2] self.assertEqual(2, slice.count()) self.assertEqual('def', slice[1].id) slice = self.qs.order_by('id')[1:] self.assertEqual(3, slice.count()) self.assertEqual('one', slice[1].id) self.assertEqual('xyz', slice[2].id) def test_filter(self): fqs = self.qs.filter(contains="two") self.assertEqual(1, fqs.count(), "count returns 1 when filtered - contains 'two'") self.assertEqual("two", fqs[0].name, "name matches filter") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_field(self): fqs = self.qs.filter(name="one") self.assertEqual( 1, fqs.count(), "count returns 1 when filtered on name = 'one' (got %s)" % self.qs.count()) self.assertEqual("one", fqs[0].name, "name matches filter") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_xmlquery(self): fqs = self.qs.filter(name=XmlQuery(term="one")) self.assertEqual( 1, fqs.count(), "count returns 1 when filtered on name = <query><term>one</term></query> (got %s)" % self.qs.count()) self.assertEqual("one", fqs[0].name, "name matches filter") def test_filter_field_xpath(self): fqs = self.qs.filter(id="abc") self.assertEqual( 1, fqs.count(), "count returns 1 when filtered on @id = 'abc' (got %s)" % self.qs.count()) self.assertEqual("two", fqs[0].name, "name returned is correct for id filter") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_field_contains(self): fqs = self.qs.filter(name__contains="o") self.assertEqual( 3, fqs.count(), "should get 3 matches for filter on name contains 'o' (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_field_contains_special(self): fqs = self.qs.filter(description__contains=' "quote" ') self.assertEqual( 1, fqs.count(), "should get 1 match for filter on desc contains ' \"quote\" ' (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") fqs = self.qs.filter(description__contains=' &!') self.assertEqual( 1, fqs.count(), "should get 1 match for filter on desc contains ' &!' (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_field_startswith(self): fqs = self.qs.filter(name__startswith="o") self.assertEqual( 1, fqs.count(), "should get 1 match for filter on name starts with 'o' (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_subobject_field(self): fqs = self.qs.filter(sub__subname="la") self.assertEqual( 1, fqs.count(), "should get 1 match for filter on sub_subname = 'la' (got %s)" % fqs.count()) def test_filter_in(self): fqs = self.qs.filter(id__in=['abc', 'xyz', 'qrs']) self.assertEqual( 2, fqs.count(), "should get 2 matches for filter on id in list (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") fqs = self.qs.filter(document_name__in=['f1.xml', 'f2.xml']) self.assertEqual( 2, fqs.count(), "should get 2 matches for filter on document name in list (got %s)" % fqs.count()) self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") # filtering on a special field - should still be able to return/access it via only fqs = self.qs.filter(document_name__in=['f1.xml', 'f2.xml']) \ .only('id', 'document_name').order_by('document_name') self.assertEqual( 2, fqs.count(), "should get 2 matches for filter on document name in list (got %s)" % fqs.count()) self.assertEqual('f1.xml', fqs[0].document_name) fqs = self.qs.filter(document_name__in=['f1.xml', 'f2.xml']) \ .also('id', 'document_name').order_by('document_name') self.assertEqual( 2, fqs.count(), "should get 2 matches for filter on document name in list (got %s)" % fqs.count()) self.assertEqual('f1.xml', fqs[0].document_name) def test_filter_exists(self): fqs = self.qs.filter(id__exists=True) self.assertEqual(4, fqs.count(), "filter on id exists=true returns all documents") fqs = self.qs.filter(id__exists=False) self.assertEqual(0, fqs.count(), "filter on id exists=false returns no documents") fqs = self.qs.filter(wnn__exists=False) self.assertEqual( 3, fqs.count(), "filter on wacky node name exists=false returns 3 documents") def test_or_filter(self): fqs = self.qs.or_filter(id='abc', name='four').only('id') self.assertEqual( 2, fqs.count(), "should get 2 matches for OR filter on id='abc' or name='four' (got %s)" % fqs.count()) ids = [obj.id for obj in fqs.all()] self.assertTrue( 'abc' in ids, 'id "abc" in list of ids when OR filter includes id="abc"') self.assertTrue( 'def' in ids, 'id "def" in list of ids when OR filter includes name="four') def test_exclude(self): fqs = self.qs.exclude(id='abc', name='one').only('id') self.assertEqual( 2, fqs.count(), "should get 2 matches for exclude filter on id='abc' or name='one' (got %s)" % fqs.count()) ids = [obj.id for obj in fqs.all()] self.assertTrue( 'abc' not in ids, 'id "abc" should not be in list of ids when exclude id="abc"') def test_filter_gtelte(self): # < <= > >= # subclass to add a numeric field to test with class CountQueryTestModel(QueryTestModel): name_count = xmlmap.IntegerField('count(name)') qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=CountQueryTestModel) # each fixture has one and only one name self.assertEqual(0, qs.filter(name_count__gt=1).count()) self.assertEqual(4, qs.filter(name_count__gte=1).count()) self.assertEqual(4, qs.filter(name_count__lte=1).count()) self.assertEqual(0, qs.filter(name_count__lt=1).count()) def test_filter_document_path(self): # get full test path to first document item = self.qs.filter(name='one').only('document_name', 'collection_name').get() path = '%s/%s' % (item.collection_name, item.document_name) # fqs = self.qs.filter(document_path=path, name='one') self.assertEqual(1, fqs.count()) fqs = self.qs.filter(document_path=path, name='two') self.assertEqual(0, fqs.count()) def test_get(self): result = self.qs.get(contains="two") self.assertTrue(isinstance(result, QueryTestModel), "get() with contains returns single result") self.assertEqual(result.name, "two", "result returned by get() has correct data") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_get_toomany(self): self.assertRaises(ReturnedMultiple, self.qs.get, contains="one") def test_get_nomatch(self): self.assertRaises(DoesNotExist, self.qs.get, contains="fifty-four") def test_get_byname(self): result = self.qs.get(name="one") self.assertTrue(isinstance(result, QueryTestModel), "get() with contains returns single result") self.assertEqual(result.name, "one", "result returned by get() has correct data") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_filter_get(self): result = self.qs.filter(contains="one").filter(name="two").get() self.assertTrue(isinstance(result, QueryTestModel)) self.assertEqual("two", result.name, "filtered get() returns correct data") self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_reset(self): self.qs.filter(contains="two") self.qs.reset() self.assertEqual(NUM_FIXTURES, self.qs.count(), "main queryset remains unchanged by filter") def test_order_by(self): # element fqs = self.qs.order_by('name') self.assertEqual('four', fqs[0].name) self.assertEqual('one', fqs[1].name) self.assertEqual('three', fqs[2].name) self.assertEqual('two', fqs[3].name) self.assertTrue('order by ' not in self.qs.query.getQuery(), "main queryset unchanged by order_by()") # attribute fqs = self.qs.order_by('id') self.assertEqual('abc', fqs[0].id) self.assertEqual('def', fqs[1].id) self.assertEqual('one', fqs[2].id) self.assertEqual('xyz', fqs[3].id) # reverse sorting fqs = self.qs.order_by('-name') self.assertEqual('four', fqs[3].name) self.assertEqual('two', fqs[0].name) fqs = self.qs.order_by('-id') self.assertEqual('abc', fqs[3].id) self.assertEqual('xyz', fqs[0].id) # case-insensitive sorting - upper-case description should not sort first fqs = self.qs.order_by('~description') self.assertTrue(fqs[0].description.startswith('third')) self.assertTrue(fqs[1].description.startswith('This one contains')) # reverse case-insensitive sorting - flags in either order fqs = self.qs.order_by('~-description') self.assertTrue(fqs[3].description.startswith('third')) fqs = self.qs.order_by('-~description') self.assertTrue(fqs[3].description.startswith('third')) def test_order_by_raw(self): fqs = self.qs.order_by_raw('min(%(xq_var)s/year)') self.assertTrue('1990' in fqs[0].years) self.assertTrue('2001' in fqs[1].years) self.assertTrue('2010' in fqs[2].years) self.assertEqual([], fqs[3].years) fqs = self.qs.order_by_raw('min(%(xq_var)s/year)', ascending=False) self.assertEqual([], fqs[0].years) self.assertTrue('2010' in fqs[1].years) self.assertTrue('2001' in fqs[2].years) self.assertTrue('1990' in fqs[3].years) def test_only(self): self.qs.only('name') self.assertTrue('element name {' not in self.qs.query.getQuery(), "main queryset unchanged by only()") fqs = self.qs.filter(id='one').only('name', 'id', 'sub', 'or_field') self.assertTrue(isinstance( fqs[0], QueryTestModel)) # actually a Partial type derived from this # attributes that should be present self.assertNotEqual(fqs[0].id, None) self.assertNotEqual(fqs[0].sub, None) self.assertNotEqual(fqs[0].sub.subname, None) self.assertNotEqual(fqs[0].or_field, None) # attribute not returned self.assertEqual(fqs[0].description, None) self.assertEqual('one', fqs[0].id) self.assertEqual('one', fqs[0].name) self.assertEqual('la', fqs[0].sub.subname) self.assertEqual( 'one', fqs[0].or_field) # = name (first of ORed fields present) fqs = self.qs.filter(id='one').only('wnn') self.assertTrue(hasattr(fqs[0], "wnn")) self.assertEqual(42, fqs[0].wnn) # nested field return fqs = self.qs.filter(id='one').only('name', 'id', 'sub__subname') self.assertEqual('la', fqs[0].sub.subname) # xpath function return fqs = self.qs.filter(id='one').only('substring') self.assertEqual('o', fqs[0].substring) # sub-subclass fqs = self.qs.filter(id='one').only('sub__ssc') self.assertTrue(isinstance(fqs[0], QueryTestModel)) def test_only_hash(self): fqs = self.qs.only('hash') # no filters, should return all 3 test objects for result in fqs: # each return object should have a 40-character SHA-1 hash checksum self.assertEqual( 40, len(result.hash), 'xquery result should have 40-character checksum, got %s' % result.hash) def test_document_name(self): fqs = self.qs.filter(id='one').only('document_name') # document_name attribute should be present self.assertNotEqual(fqs[0].document_name, None) self.assertEqual(fqs[0].document_name, "f1.xml") fqs = self.qs.filter(id='one').also('document_name') self.assertNotEqual(fqs[0].document_name, None) self.assertEqual(fqs[0].document_name, "f1.xml") def test_collection_name(self): fqs = self.qs.filter(id='one').only('collection_name') self.assertEqual(fqs[0].collection_name, '/db' + COLLECTION) fqs = self.qs.filter(id='one').also('collection_name') self.assertEqual(fqs[0].collection_name, '/db' + COLLECTION) def test_only_lastmodified(self): fqs = self.qs.only('last_modified') # no filters, should return all 3 test objects for result in fqs: self.assertTrue(isinstance(result.last_modified, datetime)) def test_iter(self): for q in self.qs: self.assertTrue(isinstance(q, QueryTestModel)) def test_slice_iter(self): i = 0 for q in self.qs[1:2]: i += 1 self.assertEqual(1, i) def test_also(self): class SubqueryTestModel(xmlmap.XmlObject): name = xmlmap.StringField('.') parent_id = xmlmap.StringField('parent::root/@id') qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='//name') name = qs.also('parent_id').get(name__exact='two') self.assertEqual( 'abc', name.parent_id, "parent id set correctly when returning at name level with also parent_id specified; should be 'abc', got '" + name.parent_id + "'") def test_also_subfield(self): class SubqueryTestModel(xmlmap.XmlObject): subname = xmlmap.StringField('subname') parent = xmlmap.NodeField('parent::root', QueryTestModel) qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='//sub') name = qs.also('parent__id', 'parent__wnn').get(subname__exact='la') self.assertEqual('la', name.subname) self.assertEqual('one', name.parent.id) self.assertEqual(42, name.parent.wnn) def test_also_raw(self): class SubqueryTestModel(QueryTestModel): myid = xmlmap.StringField('@id') qs = QuerySet(using=self.db, collection=COLLECTION, model=SubqueryTestModel, xpath='/root') qs = qs.filter(id='abc').also_raw( myid='string(%(xq_var)s//name/ancestor::root/@id)') self.assertEqual('abc', qs[0].myid) # filtered version of the queryset with raw obj = qs.filter(name='two').get() self.assertEqual('abc', obj.myid) # multiple parameters obj = qs.filter(id='abc').also_raw( id='string(%(xq_var)s/@id)', name='normalize-space(%(xq_var)s//name)').get(id='abc') self.assertEqual('abc', obj.id) self.assertEqual('two', obj.name) def test_only_raw(self): qs = self.qs.only_raw( id='xs:string(%(xq_var)s//name/ancestor::root/@id)').filter( name='two') self.assertEqual('abc', qs[0].id) # filtered version obj = qs.get() self.assertEqual('abc', obj.id) # when combined with regular only, other fields come back correctly qs = self.qs.only('name', 'description', 'substring') obj = qs.only_raw( id='xs:string(%(xq_var)s//name/ancestor::root/@id)').get(id='abc') self.assertEqual('two', obj.name) self.assertEqual('t', obj.substring) self.assertEqual('this one only has two', obj.description) self.assertEqual('abc', obj.id) # subfield obj = qs.only_raw( sub__subname='normalize-space(%(xq_var)s//subname)').get(id='one') self.assertEqual('la', obj.sub.subname) # multiple parameters obj = self.qs.filter(id='abc').only_raw( id='string(%(xq_var)s/@id)', name='normalize-space(%(xq_var)s//name)').get(id='abc') self.assertEqual('abc', obj.id) self.assertEqual('two', obj.name) # list field - multiple return values class MyQueryTest(QueryTestModel): name = xmlmap.StringListField('name') qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=MyQueryTest) # return one object but find all the names in the test collection obj = qs.filter(id='abc').only_raw(name='collection("/db%s")//name' % COLLECTION).get(id='abc') # 4 names in test fixtures - should come back as a list of those 4 names self.assertEqual(4, len(obj.name)) def test_getDocument(self): obj = self.qs.getDocument("f1.xml") self.assertTrue( isinstance(obj, QueryTestModel), "object returned by getDocument is instance of QueryTestModel") self.assertEqual("one", obj.name) def test_distinct(self): qs = QuerySet(using=self.db, collection=COLLECTION, xpath='//name') vals = qs.distinct() self.assertTrue('one' in vals) self.assertTrue('two' in vals) self.assertTrue('three' in vals) self.assertTrue('four' in vals) self.assertTrue('abc' not in vals) def test_namespaces(self): # filter on a field with a namespace fqs = self.qs.filter(nsfield='namespaced').all() self.assertEqual('namespaced', fqs[0].nsfield)
class ExistQueryTest__FullText(unittest.TestCase): # when full-text indexing is enabled, eXist must index files when they are loaded to the db # this makes tests *significantly* slower # any tests that require full-text queries should be here # sample lucene configuration for testing full-text queries FIXTURE_INDEX = ''' <collection xmlns="http://exist-db.org/collection-config/1.0"> <index> <lucene> <analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/> <text qname="description"/> <text qname="root"/> </lucene> </index> </collection> ''' def setUp(self): self.db = ExistDB(server_url=EXISTDB_SERVER_URL, username=EXISTDB_SERVER_USER, password=EXISTDB_SERVER_PASSWORD) # create index for collection - should be applied to newly loaded files self.db.loadCollectionIndex(COLLECTION, self.FIXTURE_INDEX) load_fixtures(self.db) self.qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel) def tearDown(self): self.db.removeCollection(COLLECTION) self.db.removeCollectionIndex(COLLECTION) def test_filter_fulltext_terms(self): fqs = self.qs.filter(description__fulltext_terms='only two') self.assertEqual( 1, fqs.count(), "should get 1 match for fulltext_terms search on = 'only two' (got %s)" % fqs.count()) def test_filter_fulltext_options(self): qs = QuerySet(using=self.db, xpath='/root', collection=COLLECTION, model=QueryTestModel, fulltext_options={'default-operator': 'and'}) # search for terms present in fixtures - but not both present in one doc fqs = qs.filter(description__fulltext_terms='only third') # for now, just confirm that the option is passed through to query self.assertTrue( '<default-operator>and</default-operator>' in fqs.query.getQuery()) # TODO: test this properly! # query options not supported in current version of eXist # self.assertEqual(0, fqs.count()) def test_order_by__fulltext_score(self): fqs = self.qs.filter( description__fulltext_terms='one').order_by('-fulltext_score') self.assertEqual('one', fqs[0].name) # one appears 3 times, should be first def test_only__fulltext_score(self): fqs = self.qs.filter(description__fulltext_terms='one').only( 'fulltext_score', 'name') self.assertTrue(isinstance( fqs[0], QueryTestModel)) # actually a Partial type derived from this # fulltext score attribute should be present self.assertNotEqual(fqs[0].fulltext_score, None) self.assertTrue(float(fqs[0].fulltext_score) > 0.5) # full-text score should be a float def test_fulltext_highlight(self): fqs = self.qs.filter(description__fulltext_terms='only two') # result from fulltext search - by default, xml should have exist:match tags self.assertTrue('<exist:match'.encode( encoding='UTF-8') in fqs[0].serialize()) fqs = self.qs.filter(description__fulltext_terms='only two', highlight=False) # with highlighting disabled, should not have exist:match tags self.assertTrue('<exist:match'.encode( encoding='UTF-8') not in fqs[0].serialize()) # order of args in the same filter should not matter fqs = self.qs.filter(highlight=False, description__fulltext_terms='only two') # with highlighting disabled, should not have exist:match tags self.assertTrue('<exist:match'.encode( encoding='UTF-8') not in fqs[0].serialize()) # separate filters should also work fqs = self.qs.filter(description__fulltext_terms='only two').filter( highlight=False) # with highlighting disabled, should not have exist:match tags self.assertTrue('<exist:match'.encode( encoding='UTF-8') not in fqs[0].serialize()) def test_highlight(self): fqs = self.qs.filter(highlight='supercalifragilistic') self.assertEqual( 4, fqs.count(), "highlight filter returns all documents even though search term is not present" ) fqs = self.qs.filter(highlight='one').order_by('id') self.assertTrue('<exist:match'.encode( encoding='UTF-8') in fqs[0].serialize()) def test_match_count(self): fqs = self.qs.filter(id='one', highlight='one').only('match_count') self.assertEqual(fqs[0].match_count, 4, "4 matched words should be found") def test_using(self): fqs = self.qs.using('new-collection') # using should update the collection on the xquery object self.assertEqual('new-collection', fqs.query.collection)