def test_filter_exists(self): xq = Xquery(xpath='/el') xq.add_filter('@id', 'exists', True) self.assertEqual('/el[@id]', xq.getQuery()) xq = Xquery(xpath='/el') xq.add_filter('@id', 'exists', False) self.assertEqual('/el[not(@id)]', xq.getQuery())
def test_not_filters(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'contains', 'dog', mode='NOT') self.assertEqual('/el[not(contains(., "dog"))]', xq.getQuery()) xq = Xquery(xpath='/el') xq.add_filter('.', 'contains', 'dog', mode='NOT') xq.add_filter('.', 'startswith', 'S', mode='NOT') self.assertEqual( '/el[not(contains(., "dog")) and not(starts-with(., "S"))]', xq.getQuery())
def test_filters(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'contains', 'dog') self.assertEqual('/el[contains(., "dog")]', xq.getQuery()) # filters are additive xq.add_filter('.', 'startswith', 'S') self.assertEqual('/el[contains(., "dog")][starts-with(., "S")]', xq.getQuery())
def test_return_also__fulltext_score(self): xq = Xquery(xpath='/el') xq.xq_var = '$n' xq.return_also({'fulltext_score': ''}) self.assertTrue('let $fulltext_score := ft:score($n)' in xq.getQuery()) self.assertTrue('<fulltext_score>{$fulltext_score}</fulltext_score>' in xq._constructReturn())
def test_fulltext_options(self): # pass in options for a full-text query xq = Xquery(xpath='/el', fulltext_options={'default-operator': 'and'}) xq.add_filter('.', 'fulltext_terms', 'dog') self.assertTrue( '<default-operator>and</default-operator>' in xq.getQuery()) self.assertTrue('/el[ft:query(., "dog", $ft_options)]', xq.getQuery())
def test_namespaces(self): xq = Xquery(xpath='/foo:el', namespaces={'foo': 'urn:foo#'}) ns_declaration = '''declare namespace foo='urn:foo#';''' # xpath-only xquery should have namespace declaration self.assertTrue(ns_declaration in xq.getQuery()) # full FLOWR xquery should also have declaration xq.return_only({'id': '@id'}) self.assertTrue(ns_declaration in xq.getQuery())
def test_or_filters(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'contains', 'dog', mode='OR') xq.add_filter('.', 'startswith', 'S', mode='OR') self.assertEqual('/el[contains(., "dog") or starts-with(., "S")]', xq.getQuery())
def test_prep_xpath(self): xq = Xquery() xq.xq_var = '$n' # handle attributes self.assertEqual('<field>{$n/@id}</field>', xq.prep_xpath('@id', return_field=True)) self.assertEqual('<field>{$n/../@id}</field>', xq.prep_xpath('../@id', return_field=True)) self.assertEqual('<field>{$n/parent::root/@id}</field>', xq.prep_xpath('parent::root/@id', return_field=True)) # handle regular nodes self.assertEqual('<field>{$n/title}</field>', xq.prep_xpath('title', return_field=True)) # function call - regular node self.assertEqual('substring($n/title,1,1)', xq.prep_xpath('substring(title,1,1)')) # function call - abbreviated step self.assertEqual('substring($n/.,1,1)', xq.prep_xpath('substring(.,1,1)')) # xpath with OR - absolute paths self.assertEqual('<field>{$n/name|$n/title}</field>', xq.prep_xpath('/name|/title', return_field=True)) # xpath with OR - relative paths self.assertEqual('<field>{$n/name|$n/title}</field>', xq.prep_xpath('name|title', return_field=True)) # xpath with OR - mixed absolute and relative paths self.assertEqual('<field>{$n/name|$n/title}</field>', xq.prep_xpath('/name|title', return_field=True)) # multiple ORs self.assertEqual( '<field>{$n/name|$n/title|$n/@year}</field>', xq.prep_xpath('/name|/title|@year', return_field=True)) # .//node inside a function call self.assertEqual( '<field>{normalize-space($n/.//name)}</field>', xq.prep_xpath('normalize-space($n/.//name)', return_field=True)) # node|node inside a function call self.assertEqual('fn:lower-case($n/name|$n/title)', xq.prep_xpath('fn:lower-case(name|title)')) # node|node inside a nested function call self.assertEqual( 'fn:lower-case(normalize-space($n/name|$n/title))', xq.prep_xpath('fn:lower-case(normalize-space(name|title))'))
def test_filter_gtlt(self): xq = Xquery(xpath='/el') xq.add_filter('@id', 'gt', 5) self.assertTrue('el[@id > 5]' in xq.getQuery()) xq = Xquery(xpath='/el') xq.add_filter('@id', 'gte', 5) self.assertTrue('/el[@id >= 5]' in xq.getQuery()) xq.add_filter('@id', 'lt', '10') self.assertTrue('el[@id >= 5]' in xq.getQuery()) self.assertTrue('[@id < "10"]' in xq.getQuery()) xq.add_filter('@id', 'lte', 3) self.assertTrue('[@id <= 3]' in xq.getQuery())
def test_filter_escaping(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'contains', '"&') self.assertEqual('/el[contains(., """&")]', xq.getQuery())
def test_filter_in(self): xq = Xquery(xpath='/el') xq.add_filter('@id', 'in', ['a', 'b', 'c']) self.assertEqual('/el[@id="a" or @id="b" or @id="c"]', xq.getQuery()) # filter on a 'special' field - requires let & where statements xq = Xquery(xpath='/el') xq.add_filter('document_name', 'in', ['a.xml', 'b.xml']) self.assertTrue('let $document_name' in xq.getQuery()) self.assertTrue( 'where $document_name="a.xml" or $document_name="b.xml"' in xq.getQuery())
def test_return_also_raw(self): xq = Xquery(xpath='/el') xq.xq_var = '$n' xq._raw_prefix = 'r_' xq.return_also({'myid': 'count(util:expand(%(xq_var)s/@id))'}, raw=True) self.assertTrue('<r_myid>{count(util:expand($n/@id))}</r_myid>' in xq._constructReturn()) xq = Xquery(xpath='/el') xq.xq_var = '$n' xq._raw_prefix = 'r_' xq.return_also({'myid': '@id'}, raw=True) self.assertTrue('<r_myid>{@id}</r_myid>' in xq._constructReturn())
def test_distinct(self): # distinct-values xq = Xquery(xpath='/el') xq.distinct() self.assertEqual('distinct-values(/el)', xq.getQuery())
def test_return_only(self): xq = Xquery(xpath='/el') xq.xq_var = '$n' xq.return_only({ 'myid': '@id', 'some_name': 'name', 'first_letter': 'substring(@n,1,1)' }) xq_return = xq._constructReturn() self.assertTrue('return <el>' in xq_return) self.assertTrue('<field>{$n/@id}</field>' in xq_return) self.assertTrue('<field>{$n/name}</field>' in xq_return) self.assertTrue('<field>{substring($n/@n,1,1)}</field>' in xq_return) self.assertTrue('</el>' in xq_return) xq = Xquery(xpath='/some/el/notroot') xq.return_only({'id': '@id'}) self.assertTrue('return <notroot>' in xq._constructReturn()) # case where node test can't be the return element xq = Xquery(xpath='/foo/bar/node()') xq.return_only({'myid': '@id'}) xq_return = xq._constructReturn() self.assertTrue('return <node>' in xq_return) xq = Xquery(xpath='/foo/bar/*') xq.return_only({'myid': '@id'}) xq_return = xq._constructReturn() self.assertTrue('return <node>' in xq_return)
def test_defaults(self): xq = Xquery() self.assertEqual('/node()', xq.getQuery())
def test_sort(self): xq = Xquery(collection="mycoll") xq.xq_var = '$n' xq.sort('@id') self.assertTrue('order by $n/@id ascending' in xq.getQuery()) self.assertTrue('collection("/db/mycoll")' in xq.getQuery()) # prep_xpath function should clean up more complicated xpaths xq.sort('name|@id') self.assertTrue('order by $n/name|$n/@id' in xq.getQuery()) # sort descending xq.sort('@id', ascending=False) self.assertTrue('order by $n/@id descending' in xq.getQuery()) # sort case-insensitive xq.sort('@id', case_insensitive=True) self.assertTrue( 'order by fn:lower-case($n/@id) ascending' in xq.getQuery()) # case-insensitive and descending xq.sort('@id', case_insensitive=True, ascending=False) self.assertTrue( 'order by fn:lower-case($n/@id) descending' in xq.getQuery())
def test_document(self): xq = Xquery(xpath='/el', document="/db/coll/file.xml") self.assertEqual('doc("/db/coll/file.xml")/el', xq.getQuery()) # document takes precedence over collection xq.set_collection('coll') # should be ignored self.assertEqual('doc("/db/coll/file.xml")/el', xq.getQuery())
def test_set_collection(self): # initialize with no collection xq = Xquery(xpath='/el') xq.set_collection('coll') self.assertEqual('collection("/db/coll")/el', xq.getQuery()) # initialize with one collection, then switch xq = Xquery(collection='coll1') xq.set_collection('coll2') self.assertEqual('collection("/db/coll2")/node()', xq.getQuery()) # leading slash is ok too xq.set_collection('/coll3') self.assertEqual('collection("/db/coll3")/node()', xq.getQuery()) # set to None xq.set_collection(None) self.assertEqual('/node()', xq.getQuery())
def test_coll(self): xq = Xquery(collection='myExistColl') self.assertEqual('collection("/db/myExistColl")/node()', xq.getQuery()) xq = Xquery(xpath='/root/el', collection='/coll/sub') self.assertEqual('collection("/db/coll/sub")/root/el', xq.getQuery())
def test_xpath(self): xq = Xquery(xpath='/path/to/el') self.assertEqual('/path/to/el', xq.getQuery())
def test_return_also(self): xq = Xquery(xpath='/el') xq.xq_var = '$n' xq.return_also({'myid': '@id', 'some_name': 'name'}) self.assertTrue('{$n}' in xq._constructReturn()) self.assertTrue('<field>{$n/@id}</field>' in xq._constructReturn())
def test_filters_fulltext(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'fulltext_terms', 'dog') self.assertEqual('/el[ft:query(., "dog")]', xq.getQuery())
def test_return_also__highlight(self): xq = Xquery(xpath='/el') xq.xq_var = '$n' xq.return_also({'fulltext_score': ''}) xq.add_filter('.', 'highlight', 'dog star') self.assertTrue('(/el[ft:query(., "dog star")]|/el)' in xq.getQuery())
def test_filters_highlight(self): xq = Xquery(xpath='/el') xq.add_filter('.', 'highlight', 'dog star') self.assertEqual('util:expand((/el[ft:query(., "dog star")]|/el))', xq.getQuery())
def test_set_limits(self): # subsequence with xpath xq = Xquery(xpath='/el') xq.xq_var = '$n' xq.set_limits(low=0, high=4) self.assertEqual('subsequence(/el, 1, 4)', xq.getQuery()) # subsequence with FLWR query xq.return_only({'name': 'name'}) self.assertTrue('subsequence(for $n in' in xq.getQuery()) # additive limits xq = Xquery(xpath='/el') xq.set_limits(low=2, high=10) xq.set_limits(low=1, high=5) self.assertEqual('subsequence(/el, 4, 4)', xq.getQuery()) # no high specified xq = Xquery(xpath='/el') xq.set_limits(low=10) self.assertEqual('subsequence(/el, 11, )', xq.getQuery()) # no low xq = Xquery(xpath='/el') xq.set_limits(high=15) self.assertEqual('subsequence(/el, 1, 15)', xq.getQuery())
def test_clear_limits(self): xq = Xquery(xpath='/el') xq.set_limits(low=2, high=5) xq.clear_limits() self.assertEqual('/el', xq.getQuery())