{ "info": { "author": "pwwang", "author_email": "pwwang@pwwang.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "# pymedoo - A lightweight database framework for python. \nit's inspired by [Medoo][1] for PHP and [Records][7] for python. \n\n![Pypi][8] ![Github][9] ![Codacy][10] ![Codacy coverage][11] ![Travis building][12]\n\n## Install\n```bash\npip install medoo\n```\n\n## Required packages for databases\n\n| Database | Package |\n|----------|--------- |\n| sqlite | [sqlite3][2] |\n| mysql | [pymysql][3] |\n| pgsql | [psycopg2][4] |\n| mssql | [pymssql][5] |\n| oracle | [cx_Oracle][6] |\n\n## Get started\n### SELECT\n\n```python\nfrom medoo import Medoo\n\n# For other arguments, please refer to the original connect function of each client.\nme = Medoo(dbtype = 'sqlite', database = 'file:///path/to/test.sqlite')\n\n# SELECT * FROM \"Customers\"\nrs = me.select('Customers')\n\nprint(rs.export('csv', delimiter = '\\t'))\n```\n|CustomerID|CustomerName|ContactName|Address|City|PostalCode|Country|\n|-|-|-|-|-|-|-|\n|1|Alfreds Futterkiste|Maria Anders|Obere Str. 57|Berlin|12209|Germany|\n|2|Ana Trujillo Emparedados y helados|Ana Trujillo|Avda. de la Constituci\u00f3n 2222|M\u00e9xico D.F.|5021|Mexico|\n|3|Antonio Moreno Taquer\u00eda|Antonio Moreno|Mataderos 2312|M\u00e9xico D.F.|5023|Mexico|\n|4|Around the Horn|Thomas Hardy|120 Hanover Sq.|London|WA1 1DP|UK|\n|5|Berglunds snabbk\u00f6p|Christina Berglund|Berguvsv\u00e4gen 8|Lule\u00e5|S-958 22|Sweden|\n\n```python\n# SELECT \"CustomerID\",\"CustomerName\" FROM \"Customers\"\nme.select('Customers', 'CustomerID, CustomerName')\nme.select('Customers', ['CustomerID', 'CustomerName'])\n\n# SELECT \"C\".\"CustomerID\" AS \"CustomerID\",\"C\".\"CustomerName\" AS \"name\" FROM \"Customers\" AS \"C\"\nme.select('Customers(C)', ['C.CustomerID(id)', 'C.CustomerName(name)'])\n\n# SELECT DISTINCT \"Country\" FROM \"Customers\"\nme.select('Customers', 'Country', distinct = True)\n\n# SELECT COUNT(\"CustomerID\") FROM \"Customers\"\nme.select('Customers', 'CustomerID|COUNT')\n\n# SELECT COUNT(DISTINCT \"CustomerID\") AS \"c\" FROM \"Customers\"\nme.select('Customers', 'CustomerID|.COUNT(c)')\n\n# SELECT \"CustomerID\"+1 FROM \"Customers\"\nfrom medoo import Field, Raw\nme.select('Customers', Field('CustomerID')+1)\n\n# SELECT 'Name: ' || CustomerName AS name FROM \"Customers\"\nrs = me.select('Customers', Raw(\"'Name: ' || CustomerName AS name\"))\nfor r in rs: print(r.name)\n```\n```\nName: Alfreds Futterkiste\nName: Ana Trujillo Emparedados y helados\nName: Antonio Moreno Taquer\u00eda\nName: Around the Horn\nName: Berglunds snabbk\u00f6p\n```\n\n### WHERE\n#### Single condition\n```python\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" = 1\nme.select('Customers', where = {'CustomerID': 1})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" < 3\nme.select('Customers', where = {'CustomerID[<]': 3})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" IN (1,2,3)\nme.select('Customers', where = {'CustomerID': (1,2,3)})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerName\" LIKE '%b%' OR \"CustomerName\" LIKE '%c%'\nme.select('Customers', where = {'CustomerName[~]': ('a', 'b')})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" BETWEEN 1 AND 3\nme.select('Customers', where = {'CustomerID[<>]': (1,3)})\n\n# SELECT * FROM \"Customers\" WHERE NOT \"CustomerID\" BETWEEN 1 AND 3\nme.select('Customers', where = {'!CustomerID[<>]': (1,3)})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" IS NULL\nme.select('Customers', where = {'CustomerID[is]': None}) # where = {'id[==]': None}\n\n# SELECT * FROM \"Customers\" WHERE INSTR(\"CustomerName\", 'Antonio')\nme.select('Customers', where = {Raw('INSTR(\"CustomerName\", \\'Antonio\\')'):None})\n```\n\n#### Compond\n```python\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" IN (1,2,3) AND \"CustomerName\" LIKE '%b%'\nme.select('Customers', where = {\n 'CustomerID': (1,2,3),\n 'CustomerName[~]': 'b'\n})\n# SELECT * FROM \"Customers\" \n# WHERE (\"CustomerID\" IN (1,2,3) AND \"CustomerName\" LIKE '%b%') AND\n#\t(\"CustomerName\" = 'cd' OR \"CustomerID\" = 2) AND\n#\t(\"CustomerID\" < 3 AND NOT \"CustomerName\" = 'bc')\nme.select('Customers', where = {\n 'AND': {\n 'CustomerID': (1,2,3),\n 'CustomerName[~]': 'b'\n },\n 'OR': {\n 'CustomerName': 'cd',\n 'CustomerID': 2\n },\n # you can use comment to distinguish multiple ANDs and ORs\n 'AND #2': {\n 'CustomerID[<]': 3,\n '!CustomerName': 'bc'\n }\n})\n```\n\n#### Modifier\n```python\n# SELECT * FROM \"Customers\" ORDER BY \"CustomerID\" DESC, \"CustomerName\" ASC LIMIT 2 OFFSET 1\n# MSSQL:\n# SELECT * FROM \"Customers\" ORDER BY \"CustomerID\" DESC, \"CustomerName\" ASC\n#\tOFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY\nme.select('Customers', where = {\n 'ORDER': {'CustomerID': 'desc', 'CustomerName': 'asc'},\n 'LIMIT': (2, 1)\n})\n\n# SELECT COUNT(\"CustomerID\") AS \"c\",\"CustomerName\" FROM \"Customers\" GROUP BY \"Country\" HAVING \"CustomerID\" > 1\nme.select('Customers', 'CustomerID|count(c), CustomerName', where = {\n 'GROUP': 'Country',\n 'HAVING': {'CustomerID[>]': 1}\n})\n```\n\n### Using subquery\n```python\nprint(me.select('Orders').export('csv', delimiter = '\\t'))\n```\n|OrderID|CustomerID|OrderDate|\n|-|-|-|\n|10308|2|1996-09-18|\n|10309|37|1996-09-19|\n|10310|77|1996-09-20|\n```python\n# SELECT * FROM \"Customers\" AS \"C\",(SELECT \"CustomerID\" FROM \"Orders\") AS \"O\" \n# WHERE \"C\".\"CustomerID\" = \"O\".\"CustomerID\"\nme.select([\n 'Customers(C)', # the first table\n me.builder.select('Orders', 'CustomerID', sub = 'O')\n], where = {\n 'C.CustomerID': Field('O.CustomerID')\n})\n\n# SELECT * FROM \"Customers\" WHERE \"CustomerID\" IN (SELECT \"CustomerID\" FROM \"Orders\")\nme.select('Customers', where = {\n 'CustomerID': me.builder.select('Orders', 'CustomerID')\n})\n```\n\n### JOIN\n```python\n# SELECT \"O\".\"OrderID\",\"C\".\"CustomerName\",\"O\".\"OrderDate\" FROM \"Orders\" AS \"O\" \n# INNER JOIN \"Customers\" AS \"C\" ON \"C\".\"CustomerID\"=\"O\".\"CustomerID\"\nme.select('Orders(O)', 'O.OrderID,C.CustomerName,O.OrderDate', join = {\n 'Customers(C)': 'CustomerID'\n})\n\n# equivalent to\nme.select('Orders(O)', 'O.OrderID,C.CustomerName,O.OrderDate', join = {\n 'Customers(C)[><]': 'CustomerID'\n})\n# [>] LEFT JOIN, [<] RIGHT JOIN [<>] FULL OUTER JOIN\n\n# Join on multiple columns (same in different tables)\n# join = { 'Customers(C)[><]': ['CustomerID', 'OtherColumn'] }\n\n# Join on different columns: JOIN \"Customers\" AS \"C\" ON \"C\".\"CustomerID\"=\"O\".\"OtherID\"\n# join = { 'Customers(C)[><]': {'CustomerID', 'OtherID'} }\n\n# You can join multiple tables, use OrderedDict if you want to keep the order.\n```\n\n### UNION\n```python\n# SELECT \"CustomerID\" FROM \"Customers\" UNION SELECT \"CustomerID\" FROM \"Orders\"\nme.union(\n me.builder.select('Customers', 'CustomerID'),\n me.builder.select('Orders', 'CustomerID')\n)\n\n# SELECT \"CustomerID\" FROM \"Customers\" UNION ALL SELECT \"CustomerID\" FROM \"Orders\"\nme.union(\n me.builder.select('Customers', 'CustomerID'),\n me.builder.select('Orders', 'CustomerID', sub = True)\n)\n```\n\n### Records\n`Medoo.select` and `Medoo.union` return a collection of records, which is basically a generator, but you can still get items from it, as it will consume the generate if necessary. The idea is borrowed from [Records][7].\n```python\nrecords = me.select('Customers', 'CustomerID(id)')\nrecord = records.first() # \n\n# equivalent to\nrecord = records[0] \n\n# you may also select other rows: records[1], records[2]\n# or return all rows: \nprint(records.all())\n\n# you can also export the records\n# this is the courtesy from tablib (https://github.com/kennethreitz/tablib)\n# check the kwargs with its documentation\nprint(records.export('csv', delimiter = '\\t'))\n\n# You can also apply tablib's other function on the data:\n# records.tldata.()\n\n# to get the value of each field from a record:\nprint(record[0]) # 1\nprint(record['id']) # 1\nprint(record.id) # 1\nprint(record.as_dict()) # {'id': 1}\n```\n\n### INSERT\n```python\n# INSERT INTO \"Orders\" (\"OrderID\",\"CustomerID\",\"OrderDate\") VALUES (1,2,'1999-09-09'),(2,8,'2001-10-12')\nme.insert(\n 'Orders', # table\n 'OrderID, CustomerID, OrderDate', # fields\n (1,2,'1999-09-09'), # values\n (2,8,'2001-10-12')\n # ...\n)\n# get the last insert row id\nprint(me.id()) # 5\n\n# INSERT INTO \"Orders\" (\"OrderID\",\"CustomerID\",\"OrderDate\") VALUES (1,2,'1999-09-09'),(2,8,'2001-10,12')\nme.insert(\n 'Orders', # table\n {'OrderID': 1, 'CustomerID': 2, 'OrderDate': '1999-09-09'}, # fields with the first value\n (2,8,'2001-10-12')\n # ...\n)\nme.insert(\n 'Orders', # table\n {'OrderID': 1, 'CustomerID': 2, 'OrderDate': '1999-09-09'}, # fields with the first value\n {'OrderID': 2, 'CustomerID': 8, 'OrderDate': '2001-10-12'} # specify the fields as well\n # ...\n)\n# Or if your values have all the fields\n# INSERT INTO \"Orders\" VALUES (1,2,'1999-09-09'),(2,8,'2001-10-12')\nme.insert(\n 'Orders', # table\n (1,2,'1999-09-09')\n (2,8,'2001-10-12')\n # ...\n)\n\n# You may hold the changes until all data inserted\nme.insert(..., commit = False)\nme.insert(..., commit = False)\nme.insert(..., commit = False)\nme.insert(..., commit = False)\nme.commit()\n# This applies with UPDATE and DELETE as well.\n```\n\n### UPDATE\n```python\n# UPDATE \"Orders\" SET \"CustomerID\"=10 WHERE \"OrderID\" = 2\nme.update(\n 'Orders', # table\n data = {'CustomerID': 10},\n where = {'OrderID': 2}\n)\n# UPDATE \"Orders\" SET \"CustomerID\"=\"CustomerID\"+1 WHERE \"OrderID\" = 2\nme.update(\n 'Orders', # table\n data = {'CustomerID[+]': 1},\n where = {'OrderID': 2}\n)\n```\n\n### DELETE\n```python\n# DELETE FROM \"Orders\" WHERE \"OrderID\" = 2\nme.delete('Orders', where = {'OrderID': 2})\n```\n\n### Other functions of `Medoo`\n```python\n# Fetch a single value\nme.get('Customers', 'CustomerID', where = {'CustomerName': 'Around the Horn'}) # == 1\n\n# Check if a record exists\nme.has('Customers', where = {'CustomerID': 10}) # == False\n\n# Return the last query\nme.last() # SELECT * FROM \"Customers\" WHERE \"CustomerID\" = 10\n\n# Show all the queries bound with `me`\n\n# You have to passing `logging = True` to `Medoo(..., logging = True)`\nme.log()\n\n# Return the errors\nme.error()\n\n# Submit an SQL query\nme.query(sql, commit = True)\n```\n\n### Extending `pymedoo`\n`pymedoo` is highly extendable, including the operators in `WHERE` conditions and `UPDATE SET` clause, `JOIN` operators, and some functions such as how to quote the table names, field names and values. All of these have been defined with `Dialect` class, what you need to do is just extend this class and specify it to the `Medoo` instance. \nFor example, let's define a case-insensitive `LIKE` operator using a shortcut `~~`:\n```python\nfrom medoo import Medoo, Dialect\n\nclass MyDialect(Dialect):\n OPERATOR_MAP = {\n '~~': 'ilike'\n }\n\n @classmethod\n def ilike(klass, field, value):\n # support single value\n if not isinstance(value, list):\n value = [value]\n \n terms = [\n \"UPPER({}) LIKE UPPER({})\".format(field, klass.value(v)) # quote the value\n for v in value\n ]\n # use OR to connect\n return ' OR '.join(terms)\n\n# tell medoo to use this dialect\nme = Medoo(...)\nme.dialect(MyDialect)\n\n# SELECT * FROM \"Customers\" WHERE UPPER(\"CustomerName\") LIKE UPPER('%an%')\nrecords = me.select('Customers', where = {\n 'CustomerName[~~]': '%an%'\n})\nprint(records.export('csv', delimiter = '\\t'))\n```\n|CustomerID|CustomerName|ContactName|Address|City|PostalCode|Country|\n|-|-|-|-|-|-|-|\n|2|Ana Trujillo Emparedados y helados|Ana Trujillo|Avda. de la Constituci\u00f3n 2222|M\u00e9xico D.F.|5021|Mexico|\n|3|Antonio Moreno Taquer\u00eda|Antonio Moreno|Mataderos 2312|M\u00e9xico D.F.|5023|Mexico|\n\n\n[1]: https://medoo.in/\n[2]: https://docs.python.org/2/library/sqlite3.html\n[3]: https://github.com/PyMySQL/PyMySQL\n[4]: http://initd.org/psycopg/docs/\n[5]: http://www.pymssql.org/en/stable/\n[6]: https://oracle.github.io/python-cx_Oracle/\n[7]: https://github.com/kennethreitz/records\n[8]: https://img.shields.io/pypi/v/medoo.svg?style=flat-square\n[9]: https://img.shields.io/github/tag/pwwang/pymedoo.svg?style=flat-square\n[10]: https://img.shields.io/codacy/grade/83a79e32a9414a08be67d17b3e93a2ad.svg?style=flat-square\n[11]: https://img.shields.io/codacy/coverage/83a79e32a9414a08be67d17b3e93a2ad.svg?style=flat-square\n[12]: https://img.shields.io/travis/pwwang/pymedoo.svg?style=flat-square", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pwwang/pymedoo", "keywords": "", "license": "MIT", "maintainer": "pwwang", "maintainer_email": "pwwang@pwwang.com", "name": "pymedoo", "package_url": "https://pypi.org/project/pymedoo/", "platform": "", "project_url": "https://pypi.org/project/pymedoo/", "project_urls": { "Homepage": "https://github.com/pwwang/pymedoo", "Repository": "https://github.com/pwwang/pymedoo" }, "release_url": "https://pypi.org/project/pymedoo/0.0.5/", "requires_dist": [ "six (>=1.12,<2.0); python_version >= \"2.7\" and python_version < \"2.8\"" ], "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "summary": "A lightweight database framework for python", "version": "0.0.5" }, "last_serial": 5493628, "releases": { "0.0.4": [ { "comment_text": "", "digests": { "md5": "f7f46e610d66fb6b581634e4ff473e2e", "sha256": "4dd2b0486cdc0ad34b4b9ceaa2037c9d4b0e34f733667b835c5dfc0e82fed6f1" }, "downloads": -1, "filename": "pymedoo-0.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f7f46e610d66fb6b581634e4ff473e2e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 19113, "upload_time": "2019-06-12T22:51:33", "url": "https://files.pythonhosted.org/packages/b1/50/f14dc5b5fde279fe195bb5633bed46b0b8e8e6a1c5f2e2a8cae751d93e7c/pymedoo-0.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b0e9b91e4e79e28183be9000693e6afa", "sha256": "109c2a4271d7adcc5f6fcbb8859c102b6e07100d88b1520d8ef6b34c634cdb22" }, "downloads": -1, "filename": "pymedoo-0.0.4.tar.gz", "has_sig": false, "md5_digest": "b0e9b91e4e79e28183be9000693e6afa", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 20769, "upload_time": "2019-06-12T22:51:35", "url": "https://files.pythonhosted.org/packages/61/11/9c5c1d956782f00145afe6c2f2a9757d489c64c2779f3b8dba6c99f4eb6b/pymedoo-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "c8b1e554fb6a67c6fa059d2593c104d3", "sha256": "71eb75e6fa4ea4937461435052c464ee065e7246b1a9f6587c94f875805a4a91" }, "downloads": -1, "filename": "pymedoo-0.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c8b1e554fb6a67c6fa059d2593c104d3", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "size": 19145, "upload_time": "2019-07-06T00:51:18", "url": "https://files.pythonhosted.org/packages/c4/fa/7fa215c2a24b7e32e0893b0857cae30389ebb2eaf99bfa17975386d65403/pymedoo-0.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6718c5f17449349ee216ca681d7cdbd9", "sha256": "db81f042166cd83485e365d8b73690e5724e57112b151993a3fce6a51135e37d" }, "downloads": -1, "filename": "pymedoo-0.0.5.tar.gz", "has_sig": false, "md5_digest": "6718c5f17449349ee216ca681d7cdbd9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "size": 20674, "upload_time": "2019-07-06T00:51:20", "url": "https://files.pythonhosted.org/packages/37/d7/6a2732e0996ede36d9bccae6f8a3ab6e18fd44530497c468cb199e613ebb/pymedoo-0.0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c8b1e554fb6a67c6fa059d2593c104d3", "sha256": "71eb75e6fa4ea4937461435052c464ee065e7246b1a9f6587c94f875805a4a91" }, "downloads": -1, "filename": "pymedoo-0.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c8b1e554fb6a67c6fa059d2593c104d3", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "size": 19145, "upload_time": "2019-07-06T00:51:18", "url": "https://files.pythonhosted.org/packages/c4/fa/7fa215c2a24b7e32e0893b0857cae30389ebb2eaf99bfa17975386d65403/pymedoo-0.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6718c5f17449349ee216ca681d7cdbd9", "sha256": "db81f042166cd83485e365d8b73690e5724e57112b151993a3fce6a51135e37d" }, "downloads": -1, "filename": "pymedoo-0.0.5.tar.gz", "has_sig": false, "md5_digest": "6718c5f17449349ee216ca681d7cdbd9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "size": 20674, "upload_time": "2019-07-06T00:51:20", "url": "https://files.pythonhosted.org/packages/37/d7/6a2732e0996ede36d9bccae6f8a3ab6e18fd44530497c468cb199e613ebb/pymedoo-0.0.5.tar.gz" } ] }