diff --git a/README.md b/README.md index b21c90f..0ca1ae3 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,9 @@ Even more queries can be found [here](https://colab.research.google.com/github/R # Latest updates +## Version 2.0.2 +- Add MongoDB connection (mongodb-collection()). Requires including .withMongo() when creating the RumbleSession. + ## Version 2.0.1 - Update to Spark 4.0.1. - Add postgreSQL connection (postgresql-table()). diff --git a/pyproject.toml b/pyproject.toml index 08ce0da..640d497 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "jsoniq" -version = "2.0.1" +version = "2.0.2" description = "Python edition of RumbleDB, a JSONiq engine" requires-python = ">=3.11" dependencies = [ diff --git a/src/jsoniq/jars/rumbledb-2.0.0.jar b/src/jsoniq/jars/rumbledb-2.0.0.jar index fed7c39..b386861 100644 Binary files a/src/jsoniq/jars/rumbledb-2.0.0.jar and b/src/jsoniq/jars/rumbledb-2.0.0.jar differ diff --git a/src/jsoniq/session.py b/src/jsoniq/session.py index d26e307..8dcb76a 100644 --- a/src/jsoniq/session.py +++ b/src/jsoniq/session.py @@ -125,6 +125,11 @@ def withDelta(self): .config("spark.jars.packages", "io.delta:delta-spark_2.13:4.0.0") return self; + def withMongo(self): + self._sparkbuilder = self._sparkbuilder \ + .config("spark.jars.packages", "org.mongodb.spark:mongo-spark-connector_2.13:10.5.0") + return self; + def __getattr__(self, name): res = getattr(self._sparkbuilder, name); return res; diff --git a/tests/test_sample.py b/tests/test_sample.py index a4ca174..83b90bf 100644 --- a/tests/test_sample.py +++ b/tests/test_sample.py @@ -69,12 +69,12 @@ def test1(self): "sold" : $sale.product } return [$join] - """); + """) self.assertIn("DataFrame", seq.availableOutputs()) self.assertIn("RDD", seq.availableOutputs()) self.assertIn("Local", seq.availableOutputs()) - print(seq.json()); + print(seq.json()) self.assertTrue(json.dumps(seq.json()) == json.dumps(([{'nb': 1, 'state': 'MA', 'sold': 'broiler'}, {'nb': 1, 'state': 'MA', 'sold': 'socks'}, {'nb': 2, 'state': 'MA', 'sold': 'toaster'}, {'nb': 2, 'state': 'MA', 'sold': 'toaster'}, {'nb': 2, 'state': 'MA', 'sold': 'socks'}, {'nb': 3, 'state': 'CA', 'sold': 'toaster'}, {'nb': 3, 'state': 'CA', 'sold': 'blender'}, {'nb': 3, 'state': 'CA', 'sold': 'blender'}, {'nb': 3, 'state': 'CA', 'sold': 'shirt'}],))) seq = rumble.jsoniq(""" @@ -86,7 +86,7 @@ def test1(self): "products" : [ distinct-values($product.product) ] } """); - print(seq.json()); + print(seq.json()) self.assertTrue(json.dumps(seq.json()) == json.dumps(({'store': 1, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 2, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 3, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 4, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 5, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 6, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 7, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 8, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 9, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 10, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 11, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 12, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 13, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 14, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 15, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 16, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 17, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 18, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 19, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 20, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 21, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 22, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 23, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 24, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 25, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 26, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 27, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 28, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 29, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 30, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 31, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 32, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 33, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 34, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 35, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 36, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 37, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 38, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 39, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 40, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 41, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 42, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 43, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 44, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 45, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 46, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 47, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 48, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 49, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 50, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 51, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 52, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 53, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 54, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 55, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 56, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 57, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 58, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 59, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 60, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 61, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 62, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 63, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 64, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 65, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 66, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 67, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 68, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 69, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 70, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 71, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 72, 'products': ['shirt', 'toaster', 'phone', 'blender', 'tv', 'socks', 'broiler']}, {'store': 73, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 74, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 75, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 76, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 77, 'products': ['toaster', 'phone', 'blender', 'tv', 'socks', 'broiler', 'shirt']}, {'store': 78, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 79, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 80, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 81, 'products': ['phone', 'blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster']}, {'store': 82, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 83, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 84, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 85, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 86, 'products': ['blender', 'tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone']}, {'store': 87, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 88, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 89, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 90, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 91, 'products': ['tv', 'socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender']}, {'store': 92, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 93, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 94, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 95, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 96, 'products': ['socks', 'broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv']}, {'store': 97, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 98, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 99, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}, {'store': 100, 'products': ['broiler', 'shirt', 'toaster', 'phone', 'blender', 'tv', 'socks']}))) ############################################################ @@ -103,7 +103,7 @@ def test1(self): # JSONiq has a rich type system. rumble.bind('$c', (1,2,3,4, 5, 6)) - print(rumble.jsoniq(""" + seq = rumble.jsoniq(""" for $v in $c let $parity := $v mod 2 group by $parity @@ -112,16 +112,20 @@ def test1(self): case 1 return "odd" default return "?" : $v } - """).json()) + """) + print(seq.json()) + self.assertTrue(json.dumps(seq.json()) == json.dumps(({'even': [ 2, 4, 6 ] }, { 'odd': [ 1, 3, 5 ]},))) rumble.bind('$c', ([1,2,3],[4,5,6])) - print(rumble.jsoniq(""" + seq = rumble.jsoniq(""" for $i in $c return [ - for $j in $i + for $j in $i[] return { "foo" : $j } ] - """).json()) + """) + print(seq.json()) + self.assertTrue(json.dumps(seq.json()) == json.dumps(([{'foo': 1}, {'foo': 2}, {'foo': 3}], [{'foo': 4}, {'foo': 5}, {'foo': 6}]))) rumble.bind('$c', ({"foo":[1,2,3]},{"foo":[4,{"bar":[1,False, None]},6]})) print(rumble.jsoniq('{ "results" : $c.foo[[2]] }').json())