{ "info": { "author": "Hiroaki Yamamoto", "author_email": "hiroaki@hysoftware.net", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python :: 2", "Programming Language :: Python :: 3" ], "description": "# Object Model Mapper\n\n[![CircleCI]][CircleCI Link]\n[![Maintainability]][Maintainability Link]\n[![Test Coverage]][Test Coverage Link]\n[![PyPI version]][PyPI link]\n\n[Coverage Status]: https://coveralls.io/repos/github/hiroaki-yamamoto/omm/badge.svg?branch=master\n[Coverage Link]: https://coveralls.io/github/hiroaki-yamamoto/omm?branch=master\n[CircleCI]: https://circleci.com/gh/hiroaki-yamamoto/omm.svg?style=svg\n[CircleCI Link]: https://circleci.com/gh/hiroaki-yamamoto/omm\n[Maintainability]: https://api.codeclimate.com/v1/badges/73d2a6e16877ee2855a7/maintainability\n[Maintainability Link]: https://codeclimate.com/github/hiroaki-yamamoto/omm/maintainability\n[Test Coverage]: https://api.codeclimate.com/v1/badges/73d2a6e16877ee2855a7/test_coverage\n[Test Coverage Link]: https://codeclimate.com/github/hiroaki-yamamoto/omm/test_coverage\n[PyPI version]: https://badge.fury.io/py/OMM.svg\n[PyPI link]: https://badge.fury.io/py/OMM\n\n\n## What This?\nThis script enables to flat/bump the model depth.\n\n## Why I Make This?\nWhen I used MongoEngine, I needed to design the model like this:\n\n```python\nimport mongoengine as db\n\nclass RecentPrevAmount(db.EmbeddedDocument):\n recent = db.FloatField()\n prev = db.FloatField()\n\nclass AssetInfo(db.Document):\n assets = db.EmbeddedDocumentField(RecentPrevAmount)\n cash = db.EmbeddedDocumentField(RecentPrevAmount)\n receivable = db.EmbeddedDocumentField(RecentPrevAmount)\n revenue = db.EmbeddedDocumentField(RecentPrevAmount)\n cogs = db.EmbeddedDocumentField(RecentPrevAmount)\n```\n\nAnd creating RestAPI in above order without \"Undefiend property\" error,\nit is needed to create 5 CRUD resources:\n\n* `[GET, POST, PUT, DELETE] /assets`\n* `[GET, POST, PUT, DELETE] /cash`\n* `[GET, POST, PUT, DELETE] /receivable`\n* `[GET, POST, PUT, DELETE] /revenue`\n* `[GET, POST, PUT, DELETE] /cogs`\n\nFor each resource, the text like following is output/input:\n```JSON\n{\"recent\": 10.0, \"prev\": 14.0}\n```\n\nThis means, sending tons of requests is needed to file asset information and\nit may have frontend slow. To avoid the problem, the number of request to send\nshould be reduced as far as possible. The ideal resource is one resource with\nthe following format:\n\n```JSON\n{\n \"assets_recent\": 10.0,\n \"assets_prev\": 11.0,\n \"cash_recent\": 12.0,\n \"receivable_prev\": 13.0,\n \"revenue_recent\": 14.0,\n \"cogs_prev\": 15.0\n}\n```\n\nOf course, above is not good for public api\n(On public api, recent and prev should be embedded in a field),\nbut above structure reduces the number of requests.\n\n## How to use\n\nI think you must need example code than the doc.\n\n### Flat the model\n\n```Python\n#!/usr/bin/env python\n# coding=utf-8\n\n\"\"\"\nExample code.\n\nNote that this is just an example.\n\"\"\"\nimport mongoengine as db\nimport omm\nimport wtforms.forms as forms\nimport wtforms.fields as fld\nimport wtforms.validators as vld\nfrom ..api import api, render, login_only\n\n# First, let's define the target models as usual.\nclass Address(db.EmbeddedDocument):\n street = db.ListField(db.StringField, required=True)\n city = db.StringField(required=True)\n state = db.StringField(required=True)\n country = db.StringField(required=True)\n\nclass User(db.Document):\n email = EmailField(primary_key=True)\n first_name = StringField(required=True)\n last_name = StringField(required=True)\n address = db.EmbeddedDocument(Address, required=True)\n\n @property\n def full_name(self):\n return (\" \").join([self.first_name, self.last_name])\n\n @full_name.setter\n def full_name(self, value):\n try:\n (self.first_name, self.last_name) = value.split(\" \")\n except ValueError:\n pass\n\n# Then, define the map.\nclass UserMapper(omm.Mapper):\n # Note that set_cast can be non-list, i.e. str. However, in this case,\n # we use User because the root object type is User.\n fullname = omm.MapField(\"full_name\", set_cast=[User, str])\n email = omm.MapField(\"email\", set_cast=[User, str])\n # For third element should be list or any class that inherits list because\n # the target is typed as list.\n street1 = omm.MapField(\n \"address.street[0]\", set_cast=[User, Address, list, str]\n )\n street2 = omm.MapField(\n \"address.street[1]\", set_cast=[User, Address, list, str]\n )\n # Note that dot-notation is used to specify the member.\n city = omm.MapField(\"address.city\", set_cast=[User, Address, str])\n state = omm.MapField(\"address.state\", set_cast=[User, Address, str])\n country = omm.MapField(\"address.country\", set_cast=[User, Address, str])\n\nclass UserForm(forms.Form):\n fullname = fld.StringField(validators=[vld.DataRequired()])\n email = fld.StringField(validators=[vld.Email()])\n street1 = fld.StringField(validators=[vld.DataRequired()])\n street2 = fld.StringField(validators=[vld.Optional()])\n city = fld.StringField(validators=[vld.DataRequired()])\n state = fld.StringField(validators=[vld.DataRequired()])\n country = fld.StringField(validators=[vld.DataRequired()])\n\nclass UserController(object):\n # User API\n\n def get(self, id):\n # GET request.\n user = User.objects()\n mapper = UserMapper(user)\n return render(mapper.to_json(), mimetype=\"application/json\")\n\n def post(self):\n # POST request.\n form = UserForm(api.request.json())\n if not form.validate():\n return render(\n api.jsonify(form.errors),\n mimetype=\"application/json\",\n code=417\n )\n mapper = UserMapper()\n form.populate_obj(mapper)\n mapper.connected_object.save()\n\n @login_only\n def put(self, uid):\n # PUT request.\n form = UserForm(api.request.json())\n if not form.validate():\n return render(\n api.jsonify(form.errors),\n mimetype=\"application/json\",\n code=417\n )\n mapper = UserMapper(User.objects(uid))\n form.populate_obj(mapper)\n mapper.connected_object.save()\n\napi.register(UserController)\n```\n\n### Increment the model depth\n\nCurrently, I'm considering (and designing) the way to access multiple models\nthru the mapper. Unfortunately the functionalities are not implemented yet.\n\n### Other functionalities\nRead the [code]\n\n[code]: omm\n\n## License (MIT License)\n\nCopyright (c) 2016 Hiroaki Yamamoto\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", "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/hiroaki-yamamoto/omm.git", "keywords": "json OMM Object Model Mapper Relational Document", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "OMM", "package_url": "https://pypi.org/project/OMM/", "platform": "", "project_url": "https://pypi.org/project/OMM/", "project_urls": { "Homepage": "https://github.com/hiroaki-yamamoto/omm.git" }, "release_url": "https://pypi.org/project/OMM/1.0.1/", "requires_dist": null, "requires_python": "", "summary": "Object Model Mapper for Python-based web apps and/or APIs", "version": "1.0.1" }, "last_serial": 5341593, "releases": { "0.5.0": [ { "comment_text": "", "digests": { "md5": "3ff176455e3b61069fc9584770222365", "sha256": "b992ab1717699954ad55e7a6b7f6a21f6968ff420a35a6f250b9bff60878f93b" }, "downloads": -1, "filename": "OMM-0.5.0.tar.gz", "has_sig": false, "md5_digest": "3ff176455e3b61069fc9584770222365", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16325, "upload_time": "2016-05-23T04:56:13", "url": "https://files.pythonhosted.org/packages/45/b0/9a34568af41df811ce393b16078e6659c9e62156e19a9ad16044bfe0d1a1/OMM-0.5.0.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "3bf9b93fd07a431f67621d094b572230", "sha256": "625bdc34e1da3b03c9d431761c3d3f4ea0ef779cfb85426dee332f89bedc5a79" }, "downloads": -1, "filename": "OMM-0.5.2.tar.gz", "has_sig": false, "md5_digest": "3bf9b93fd07a431f67621d094b572230", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13599, "upload_time": "2016-07-20T10:02:44", "url": "https://files.pythonhosted.org/packages/4d/58/a0e8aa27f83cccf24950da4372a0c7bda09bb924d45b8083561c572a0dda/OMM-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "60e8ac88ec47dcf2368159fe81542c3d", "sha256": "ae736023068f3cd2aea8f864fbcb125708b946a1713f3df97dbaa8d13b020c7e" }, "downloads": -1, "filename": "OMM-0.5.3.tar.gz", "has_sig": false, "md5_digest": "60e8ac88ec47dcf2368159fe81542c3d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16888, "upload_time": "2016-07-20T10:05:10", "url": "https://files.pythonhosted.org/packages/f7/a8/d460aed9a428944cd4c9753c438d6df5b47e79b25e7747d6c5d704e4c4e5/OMM-0.5.3.tar.gz" } ], "0.8.0": [ { "comment_text": "", "digests": { "md5": "db4dbb231611453ecd07cbe713998b3e", "sha256": "a5ed76f7da2aaa9637a38e5d394afb61956680bcea0c228a7ccb807f9225c300" }, "downloads": -1, "filename": "OMM-0.8.0.tar.gz", "has_sig": false, "md5_digest": "db4dbb231611453ecd07cbe713998b3e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17366, "upload_time": "2016-07-21T04:56:50", "url": "https://files.pythonhosted.org/packages/bf/0a/6c2c846e45973786f753ae60112ce0fcd0359eafbb9a880af52136809e77/OMM-0.8.0.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "5127df99ffd76581ebb19947efc18c88", "sha256": "c032f574d502fc4f2b9574f74a108c8fc5ff536daf40b088d1286f571f07f0c2" }, "downloads": -1, "filename": "OMM-1.0.0.tar.gz", "has_sig": false, "md5_digest": "5127df99ffd76581ebb19947efc18c88", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20760, "upload_time": "2016-07-24T09:40:23", "url": "https://files.pythonhosted.org/packages/b5/93/b271914aa35a9e8f466806feebfba1f4cd88e2b3112159b88674ed4cf0d7/OMM-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "f562e1e40c9b0a8a5bc9b05ca10cc23b", "sha256": "211ced97c1e3cb50d6cbd6bf51c250eba59b9c5d7f492c5c2c05338781da886c" }, "downloads": -1, "filename": "OMM-1.0.1.tar.gz", "has_sig": false, "md5_digest": "f562e1e40c9b0a8a5bc9b05ca10cc23b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20950, "upload_time": "2019-05-31T08:14:56", "url": "https://files.pythonhosted.org/packages/3f/6a/534932b28c02b557f902989b5efb62db22f6c1ea89f3ffb545f4d96b685b/OMM-1.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f562e1e40c9b0a8a5bc9b05ca10cc23b", "sha256": "211ced97c1e3cb50d6cbd6bf51c250eba59b9c5d7f492c5c2c05338781da886c" }, "downloads": -1, "filename": "OMM-1.0.1.tar.gz", "has_sig": false, "md5_digest": "f562e1e40c9b0a8a5bc9b05ca10cc23b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20950, "upload_time": "2019-05-31T08:14:56", "url": "https://files.pythonhosted.org/packages/3f/6a/534932b28c02b557f902989b5efb62db22f6c1ea89f3ffb545f4d96b685b/OMM-1.0.1.tar.gz" } ] }