{ "info": { "author": "Thane Thomson", "author_email": "connect@thanethomson.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: MacOS", "Operating System :: POSIX", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Database", "Topic :: Software Development :: Libraries", "Topic :: Utilities" ], "description": "MLAlchemy\n=========\n\nOverview\n--------\n\nMLAlchemy is a Python-based utility library aimed at allowing relatively\nsafe conversion from YAML/JSON to SQLAlchemy read-only queries. One use\ncase here is to allow RESTful web applications (written in Python) to\nreceive YAML- or JSON-based queries for data, e.g. from a front-end\nJavaScript-based application.\n\nThe name \"MLAlchemy\" is an abbreviation for \"Markup Language for\nSQLAlchemy\".\n\nInstallation\n------------\n\nInstallation via PyPI:\n\n.. code:: bash\n\n > pip install mlalchemy\n\nQuery Examples\n--------------\n\nTo get a feel for what MLAlchemy queries look like, take a look at the\nfollowing. **Note**: All field names are converted from ``camelCase`` or\n``kebab-case`` to ``snake_case`` prior to query execution.\n\nExample YAML Queries\n~~~~~~~~~~~~~~~~~~~~\n\nFetching all the entries from a table called ``Users``:\n\n.. code:: yaml\n\n from: Users\n\nLimiting the users to only those with the last name \"Michaels\":\n\n.. code:: yaml\n\n from: Users\n where:\n last-name: Michaels\n\nA more complex YAML query:\n\n.. code:: yaml\n\n from: Users\n where:\n $or:\n last-name: Michaels\n first-name: Michael\n $gt:\n date-of-birth: 1984-01-01\n\nThe raw SQL query for the above would look like:\n\n.. code:: sql\n\n SELECT * FROM users WHERE\n (last_name = \"Michaels\" OR first_name = \"Michael\") AND\n (date_of_birth > \"1984-01-01\")\n\nExample JSON Queries\n~~~~~~~~~~~~~~~~~~~~\n\nThe same queries as above, but in JSON format. To fetch all entries in\nthe ``Users`` table:\n\n.. code:: json\n\n {\n \"from\": \"Users\"\n }\n\nLimiting the users to only those with the last name \"Michaels\":\n\n.. code:: json\n\n {\n \"from\": \"Users\",\n \"where\": {\n \"lastName\": \"Michaels\"\n }\n }\n\nAnd finally, the more complex query:\n\n.. code:: json\n\n {\n \"from\": \"Users\",\n \"where\": {\n \"$or\": {\n \"lastName\": \"Michaels\",\n \"firstName\": \"Michael\"\n },\n \"$gt\": {\n \"dateOfBirth\": \"1984-01-01\"\n }\n }\n }\n\nUsage\n-----\n\nA simple example of how to use MLAlchemy:\n\n.. code:: python\n\n from sqlalchemy import create_engine, Column, Integer, String, Date\n from sqlalchemy.ext.declarative import declarative_base\n from sqlalchemy.orm import sessionmaker\n\n from mlalchemy import parse_yaml_query, parse_json_query\n\n Base = declarative_base()\n\n\n class User(Base):\n __tablename__ = \"users\"\n\n id = Column(Integer, primary_key=True)\n first_name = Column(String)\n last_name = Column(String)\n date_of_birth = Column(Date)\n\n\n # use an in-memory SQLite database for this example\n engine = create_engine(\"sqlite:///:memory:\")\n Base.metadata.create_all(engine)\n Session = sessionmaker(bind=engine)\n session = Session()\n\n # add a couple of dummy users\n user1 = User(first_name=\"Michael\", last_name=\"Anderson\", date_of_birth=date(1980, 1, 1))\n user2 = User(first_name=\"James\", last_name=\"Michaels\", date_of_birth=date(1976, 10, 23))\n user3 = User(first_name=\"Andrew\", last_name=\"Michaels\", date_of_birth=date(1988, 8, 12))\n session.add_all([user1, user2, user3])\n session.commit()\n\n # we need a lookup table for MLAlchemy\n tables = {\n \"User\": User\n }\n\n # try a simple YAML-based query first\n all_users = parse_yaml_query(\"from: User\").to_sqlalchemy(session, tables).all()\n print(all_users)\n\n # same query, but this time in JSON\n all_users = parse_json_query(\"\"\"{\"from\": \"User\"}\"\"\").to_sqlalchemy(session, tables).all()\n print(all_users)\n\n # a slightly more complex query\n young_users = parse_yaml_query(\"\"\"from: User\n where:\n $gt:\n date-of-birth: 1988-01-01\n \"\"\").to_sqlalchemy(session, tables).all()\n print(young_users)\n\nQuery Language Syntax\n---------------------\n\nAs mentioned before, queries can either be supplied in YAML format or in\nJSON format to one of the respective parsers.\n\n``from``\n~~~~~~~~\n\nAt present, MLAlchemy can only support selecting data from a single\ntable (multi-table support is planned in future). Here, the ``from``\nparameter allows you to specify the name of the table from which to\nselect data.\n\n``where``\n~~~~~~~~~\n\nThe ``where`` parameter defines, in hierarchical fashion, the structure\nof the logical query to perform. There are 3 kinds of key types in the\nJSON/YAML structures, as described in the following table.\n\n+-----------------+----------------------------+---------------------------------------+\n| Kind | Description | Options |\n+=================+============================+=======================================+\n| **Operators** | Logical (boolean) | ``$and``, ``$or``, ``$not`` |\n| | operators for combining | |\n| | sub-clauses | |\n+-----------------+----------------------------+---------------------------------------+\n| **Comparators** | Comparative operators for | ``$eq``, ``$gt``, ``$gte``, ``$lt``, |\n| | comparing fields to values | ``$lte``, ``$like``, ``$neq``, |\n| | | ``$in``, ``$nin``, ``$is`` |\n+-----------------+----------------------------+---------------------------------------+\n| **Field Names** | The name of a field in the | (Depends on table) |\n| | ``from`` table | |\n+-----------------+----------------------------+---------------------------------------+\n\n``order-by`` (YAML) or ``orderBy`` (JSON)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProvides the ordering for the resulting query. Must either be a single\nfield name or a list of field names, with the direction specifier in\nfront of the field name. For example:\n\n.. code:: yaml\n\n # Order by \"field2\" in ascending order\n order-by: field2\n\nAnother example:\n\n.. code:: yaml\n\n # Order by \"field2\" in *descending* order\n order-by: \"-field2\"\n\nA more complex example:\n\n.. code:: yaml\n\n # Order first by \"field1\" in ascending order, then by \"field2\" in\n # descending order\n order-by:\n - field1\n - \"-field2\"\n\n``offset``\n~~~~~~~~~~\n\nSpecifies the number of results to skip before providing results. If not\nspecified, no results are skipped.\n\n``limit``\n~~~~~~~~~\n\nSpecifies the maximum number of results to return. If not specified,\nthere will be no limit to the number of returned results.\n\nQuery Examples\n--------------\n\nExample 1: Simple Query\n~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following is an example of a relatively simple query in YAML format:\n\n.. code:: yaml\n\n from: SomeTable\n where:\n - $gt:\n field1: 5\n - $lt:\n field2: 3\n order-by:\n - field1\n offset: 2\n limit: 10\n\nThis would translate into the following SQLAlchemy query:\n\n.. code:: python\n\n from sqlalchemy.sql.expression import and_\n\n session.query(SomeTable).filter(\n and_(SomeTable.field1 > 5, SomeTable.field2 < 3)\n ) \\\n .order_by(SomeTable.field1) \\\n .offset(2) \\\n .limit(10)\n\nExample 2: Slightly More Complex Query\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following is an example of a more complex query in YAML format:\n\n.. code:: yaml\n\n from: SomeTable\n where:\n - $or:\n field1: 5\n field2: something\n - $not:\n $like:\n field3: \"else%\"\n\nThis would translate into the following SQLAlchemy query:\n\n.. code:: python\n\n from sqlalchemy.sql.expression import and_, or_, not_\n\n session.query(SomeTable) \\\n .filter(\n and_(\n or_(\n SomeTable.field1 == 5,\n SomeTable.field2 == \"something\"\n ),\n not_(\n SomeTable.field3.like(\"else%\")\n )\n )\n )\n\nExample 3: Complex JSON Query\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following is an example of a relatively complex query in JSON\nformat:\n\n.. code:: json\n\n {\n \"from\": \"SomeTable\",\n \"where\": [\n {\n \"$or\": [\n {\"field1\": 10},\n {\n \"$gt\": {\n \"field2\": 5\n }\n }\n ],\n \"$and\": [\n {\"field3\": \"somevalue\"},\n {\"field4\": \"othervalue\"},\n {\n \"$or\": {\n \"field5\": 5,\n \"field6\": 6\n }\n }\n ]\n }\n ],\n \"orderBy\": [\n \"field1\",\n \"-field2\"\n ],\n \"offset\": 2,\n \"limit\": 10\n }\n\nThis query would be translated into the following SQLAlchemy code:\n\n.. code:: python\n\n from sqlalchemy.sql.expression import and_, or_, not_\n\n session.query(SomeTable) \\\n .filter(\n and_(\n or_(\n SomeTable.field1 == 10,\n SomeTable.field2 > 5\n ),\n and_(\n SomeTable.field3 == \"somevalue\",\n SomeTable.field4 == \"othervalue\",\n or_(\n SomeTable.field5 == 5,\n SomeTable.field6 == 6\n )\n )\n )\n ) \\\n .order_by(SomeTable.field1, SomeTable.field2.desc()) \\\n .offset(2) \\\n .limit(10)\n\nLicense\n-------\n\n**The MIT License (MIT)**\n\nCopyright (c) 2017 Thane Thomson\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/thanethomson/MLAlchemy", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "mlalchemy", "package_url": "https://pypi.org/project/mlalchemy/", "platform": "", "project_url": "https://pypi.org/project/mlalchemy/", "project_urls": { "Homepage": "https://github.com/thanethomson/MLAlchemy" }, "release_url": "https://pypi.org/project/mlalchemy/0.2.2/", "requires_dist": [ "PyYAML (>=3.11)", "future (>=0.16.0)", "sqlalchemy (>=1.1)" ], "requires_python": "", "summary": "Library for converting YAML/JSON to SQLAlchemy SELECT queries", "version": "0.2.2" }, "last_serial": 3312474, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "e0a932e0e47eedd0ec7d8dd90caec94d", "sha256": "5b69b0a0f796d29add8770eeabfae5cb46b4f641e72937a0dcc74c2fd9c524d4" }, "downloads": -1, "filename": "mlalchemy-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e0a932e0e47eedd0ec7d8dd90caec94d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14484, "upload_time": "2017-01-30T12:09:30", "url": "https://files.pythonhosted.org/packages/44/ad/b2c87d0a118fa07304d3c945210e8274803f07ee051f66df69ff1694dcde/mlalchemy-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "78323838ae8f1a771178d2d33bd4f3d7", "sha256": "7ef54506d2d561857e108441634062b627c016c7bef3f674a68a1f8812bd4598" }, "downloads": -1, "filename": "mlalchemy-0.1.0.tar.gz", "has_sig": false, "md5_digest": "78323838ae8f1a771178d2d33bd4f3d7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10506, "upload_time": "2017-01-30T12:09:31", "url": "https://files.pythonhosted.org/packages/63/ed/f837e84543290bcefc5798547734febade7d6eb03050191a2458d501ca25/mlalchemy-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "1e89e635356ede44ee5bb7fe0287230a", "sha256": "e6c6049611d0c4dc4f60642f11b28099ee5d8904830193ec1fc938aa19958113" }, "downloads": -1, "filename": "mlalchemy-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1e89e635356ede44ee5bb7fe0287230a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14261, "upload_time": "2017-01-30T12:11:22", "url": "https://files.pythonhosted.org/packages/3f/81/939282d7b2afd4d59f36e57f8fe128874eb84d362e85d0dda28e68168a0a/mlalchemy-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "afca2fa7a906ab20430d524265a0d0c0", "sha256": "54207a6f123b50c9d2bddde007001d7383034fd5509ff2d33847c5f78011d5be" }, "downloads": -1, "filename": "mlalchemy-0.1.1.tar.gz", "has_sig": false, "md5_digest": "afca2fa7a906ab20430d524265a0d0c0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10388, "upload_time": "2017-01-30T12:11:24", "url": "https://files.pythonhosted.org/packages/cb/9b/65ccf089c7f97a429c5e8079e2960c20609661ab659a675ad7fc1609c314/mlalchemy-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "8b9a39a275dc2db54296c791c2a48513", "sha256": "2bbc78a5263b8f005c112a8e64b634c4b503ed9b461a897ea0fbff8afcffadf0" }, "downloads": -1, "filename": "mlalchemy-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8b9a39a275dc2db54296c791c2a48513", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14894, "upload_time": "2017-01-30T13:50:10", "url": "https://files.pythonhosted.org/packages/a8/4c/7fb7cf3a7e6e06a852b4aa2ad9c8bc7a9d45496a8739e31c0728372a74fe/mlalchemy-0.1.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1e8fb2c8aec6b125058420150539e929", "sha256": "0878501b2d4103c1e9a253fa6e09e2e6b03e1c60be4251e810e6da4041467dab" }, "downloads": -1, "filename": "mlalchemy-0.1.2.tar.gz", "has_sig": false, "md5_digest": "1e8fb2c8aec6b125058420150539e929", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10933, "upload_time": "2017-01-30T13:50:13", "url": "https://files.pythonhosted.org/packages/ae/eb/2f68f6323011df59324323750ba389482bf8eef051355d4dfbc9e03df0d1/mlalchemy-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "a24c9a4d777ec34578bfdb9e261f26fc", "sha256": "8c66e1b8987f71497a5bbbd4941e3cfca621fe9d7bdd186516663c99064d82de" }, "downloads": -1, "filename": "mlalchemy-0.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a24c9a4d777ec34578bfdb9e261f26fc", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14900, "upload_time": "2017-01-30T14:00:13", "url": "https://files.pythonhosted.org/packages/5b/eb/42cd1d707753739467d885d956050efcfd2b1159c82ed8ac13574efd053e/mlalchemy-0.1.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4bd0bfa025207bd793aaed8c45b1811f", "sha256": "34e9a820ab75095f78d11f5e2dc88dee0ab9e90c942745ea4aa8011a81cf6198" }, "downloads": -1, "filename": "mlalchemy-0.1.3.tar.gz", "has_sig": false, "md5_digest": "4bd0bfa025207bd793aaed8c45b1811f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10938, "upload_time": "2017-01-30T14:00:16", "url": "https://files.pythonhosted.org/packages/d1/33/d2dd4ce8d946f5665b63f0cd616c197db1ccdd9720678382e1ca4f311d04/mlalchemy-0.1.3.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "5e34ea985f4faeada0d1045c13709147", "sha256": "cc6669b399b7e3a132168767dbcecc5664c64bc404b9137a640b9469f8db9cf4" }, "downloads": -1, "filename": "mlalchemy-0.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5e34ea985f4faeada0d1045c13709147", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15899, "upload_time": "2017-02-01T07:30:36", "url": "https://files.pythonhosted.org/packages/46/a3/6dc879039940a01e81dfcb9087b45535348cfc63672a84508cb3495401a8/mlalchemy-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a6e7a070eeea3566c8363c610832746a", "sha256": "21835e96c5f5f58bd3c3470549e71a64cbbc22847b48c053c080329b688776bb" }, "downloads": -1, "filename": "mlalchemy-0.2.0.tar.gz", "has_sig": false, "md5_digest": "a6e7a070eeea3566c8363c610832746a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11659, "upload_time": "2017-02-01T07:30:38", "url": "https://files.pythonhosted.org/packages/ac/aa/0abc3fa0d8e54d843e4249f4669c97efd3b106a613a4be5237681e890d28/mlalchemy-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "4f359a59fb27dfa7cba1d2dd537c4315", "sha256": "fa2d3b8d244b0b088ccf7d6e033f1a8bb872b51adf894ab3b0f6f64d95a1ef03" }, "downloads": -1, "filename": "mlalchemy-0.2.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4f359a59fb27dfa7cba1d2dd537c4315", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15900, "upload_time": "2017-02-01T07:43:50", "url": "https://files.pythonhosted.org/packages/9a/c8/0e53d5b343ba36d03432292fff55e7d01ff0416c308bf5fbb6cc211bade5/mlalchemy-0.2.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "04858d09376ffbeb78ddbb5ba16d71c3", "sha256": "c54afb1cc32ae8da31788f87027311a439b8616233655e473412940a9b664bfd" }, "downloads": -1, "filename": "mlalchemy-0.2.1.tar.gz", "has_sig": false, "md5_digest": "04858d09376ffbeb78ddbb5ba16d71c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11647, "upload_time": "2017-02-01T07:43:52", "url": "https://files.pythonhosted.org/packages/90/7c/5f81b6e8f399200c87a5947c3632d527f1df68264e89b2a88b8f15840f4e/mlalchemy-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "b0034748eae14fc28bd7bbcc45648faf", "sha256": "e86e97538a3dbcad1bf4a7688af344288ce8f2deb6b21201fac1f88d85a369e6" }, "downloads": -1, "filename": "mlalchemy-0.2.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b0034748eae14fc28bd7bbcc45648faf", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15897, "upload_time": "2017-11-07T11:37:34", "url": "https://files.pythonhosted.org/packages/08/54/0257ed3f2dd9fc81660c247070a55ec10c5e41f11ff1dd5a0590e95d8c2d/mlalchemy-0.2.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "33e4c3a48064f633defda0a21253739a", "sha256": "f7a1777dbd684cc56e5eef2215ab9461522cab61bc5364e05641a965ff710a82" }, "downloads": -1, "filename": "mlalchemy-0.2.2.tar.gz", "has_sig": false, "md5_digest": "33e4c3a48064f633defda0a21253739a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11655, "upload_time": "2017-11-07T11:37:36", "url": "https://files.pythonhosted.org/packages/a6/b5/01e08c666a644fdf057a5eea123bab5bc542d312dc53d26adf94f9959cb4/mlalchemy-0.2.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b0034748eae14fc28bd7bbcc45648faf", "sha256": "e86e97538a3dbcad1bf4a7688af344288ce8f2deb6b21201fac1f88d85a369e6" }, "downloads": -1, "filename": "mlalchemy-0.2.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b0034748eae14fc28bd7bbcc45648faf", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15897, "upload_time": "2017-11-07T11:37:34", "url": "https://files.pythonhosted.org/packages/08/54/0257ed3f2dd9fc81660c247070a55ec10c5e41f11ff1dd5a0590e95d8c2d/mlalchemy-0.2.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "33e4c3a48064f633defda0a21253739a", "sha256": "f7a1777dbd684cc56e5eef2215ab9461522cab61bc5364e05641a965ff710a82" }, "downloads": -1, "filename": "mlalchemy-0.2.2.tar.gz", "has_sig": false, "md5_digest": "33e4c3a48064f633defda0a21253739a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11655, "upload_time": "2017-11-07T11:37:36", "url": "https://files.pythonhosted.org/packages/a6/b5/01e08c666a644fdf057a5eea123bab5bc542d312dc53d26adf94f9959cb4/mlalchemy-0.2.2.tar.gz" } ] }