{"action":"created","comment":{"url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/comments/200288286","pull_request_review_id":134566067,"id":200288286,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMDI4ODI4Ng==","diff_hunk":"@@ -1,8 +1,33 @@\n+from decimal import Decimal\n+\n from pypika import Table\n \n+from tortoise import fields\n from tortoise.backends.base.executor import BaseExecutor\n \n \n+def to_db_bool(self, value):\n+    if value is None:\n+        return None\n+    return int(bool(value))\n+\n+\n+def to_db_decimal(self, value):\n+    if value is None:\n+        return None\n+    if self.decimal_places == 0:\n+        quant = '1'\n+    else:\n+        quant = '1.{}'.format('0' * self.decimal_places)\n+    return Decimal(value).quantize(Decimal(quant)).normalize()\n+\n+\n+TO_DB_OVERRIDE = {\n+    fields.BooleanField: to_db_bool,\n+    fields.DecimalField: to_db_decimal,\n+}","path":"tortoise/backends/sqlite/executor.py","position":28,"original_position":28,"commit_id":"8c4d373c6cb7f6409c59cfa1dde2b06fabf83ee6","original_commit_id":"8c4d373c6cb7f6409c59cfa1dde2b06fabf83ee6","user":{"login":"Zeliboba5","id":10978839,"node_id":"MDQ6VXNlcjEwOTc4ODM5","avatar_url":"https://avatars1.githubusercontent.com/u/10978839?v=4","gravatar_id":"","url":"https://api.github.com/users/Zeliboba5","html_url":"https://github.com/Zeliboba5","followers_url":"https://api.github.com/users/Zeliboba5/followers","following_url":"https://api.github.com/users/Zeliboba5/following{/other_user}","gists_url":"https://api.github.com/users/Zeliboba5/gists{/gist_id}","starred_url":"https://api.github.com/users/Zeliboba5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zeliboba5/subscriptions","organizations_url":"https://api.github.com/users/Zeliboba5/orgs","repos_url":"https://api.github.com/users/Zeliboba5/repos","events_url":"https://api.github.com/users/Zeliboba5/events{/privacy}","received_events_url":"https://api.github.com/users/Zeliboba5/received_events","type":"User","site_admin":false},"body":"Such way to implement custom behaviour for fields in drivers seems quite hacky and not flexible enough, because it only allows to override already existing methods.\r\nHow about we do it this way:\r\n\r\n- In module of driver you implement custom fields inheriting from their basic parent (Like `PostgresJSONField(fields.JSONField):`\r\n- You create a mapping of `{<Base class>: <Driver custom class>}` somewhere in module\r\n- On `Tortoise.init()` you patch models based on their driver class  replacing original class with a class from driver app\r\n\r\nThere is one more tricky moment with this strategy - different drivers can have different name for field type in db. To have better control over it - fields themselfs should have method like `get_db_type()` which will return their type definition. This way we can remove `FIELD_TYPE_MAP` from `SchemaGenerator` and users will be able to define custom fields with custom db type. This way we can also remove hardcode like this from `SchemaGenerator`:\r\n\r\n```\r\nif isinstance(field_object, fields.DecimalField):\r\n    field_type = field_type.format(field_object.max_digits, field_object.decimal_places)\r\nelif isinstance(field_object, fields.CharField):\r\n    field_type = field_type.format(field_object.max_length)\r\n```\r\n\r\nand replace it with graceful:\r\n\r\n```\r\n    def get_db_type(self):\r\n        return 'DECIMAL({},{})'.format(self.max_digits, self.decimal_places)\r\n```","created_at":"2018-07-05T09:29:04Z","updated_at":"2018-07-05T09:29:53Z","html_url":"https://github.com/Zeliboba5/tortoise-orm/pull/20#discussion_r200288286","pull_request_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/comments/200288286"},"html":{"href":"https://github.com/Zeliboba5/tortoise-orm/pull/20#discussion_r200288286"},"pull_request":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20"}}},"pull_request":{"url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20","id":199307810,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk5MzA3ODEw","html_url":"https://github.com/Zeliboba5/tortoise-orm/pull/20","diff_url":"https://github.com/Zeliboba5/tortoise-orm/pull/20.diff","patch_url":"https://github.com/Zeliboba5/tortoise-orm/pull/20.patch","issue_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/20","number":20,"state":"open","locked":false,"title":"More field tests + JSONField","user":{"login":"grigi","id":1309160,"node_id":"MDQ6VXNlcjEzMDkxNjA=","avatar_url":"https://avatars2.githubusercontent.com/u/1309160?v=4","gravatar_id":"","url":"https://api.github.com/users/grigi","html_url":"https://github.com/grigi","followers_url":"https://api.github.com/users/grigi/followers","following_url":"https://api.github.com/users/grigi/following{/other_user}","gists_url":"https://api.github.com/users/grigi/gists{/gist_id}","starred_url":"https://api.github.com/users/grigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grigi/subscriptions","organizations_url":"https://api.github.com/users/grigi/orgs","repos_url":"https://api.github.com/users/grigi/repos","events_url":"https://api.github.com/users/grigi/events{/privacy}","received_events_url":"https://api.github.com/users/grigi/received_events","type":"User","site_admin":false},"body":"I did some more Field tests, and ported JSONField to be more generic.\r\n\r\nItems of work:\r\n* [x] Test all data fields\r\n* [x] Test that nullable works\r\n* [x] Test behaviour specs of fields (DecimalField/DateTimeField)\r\n* [x] Generic IntegrityError\r\n* [x] DecimalField → fix quantization misbehaviour for SQLite\r\n* [x] DB-executor level `to_db_value` overrides (for SQLite)\r\n* [x] JSONField is now generic\r\n* [x] Update docs re supported PostgreSQL versions.\r\n* [x] Added queryset.get() method (currently just a shortcut for filter.first)\r\n\r\nBugs uncovered/fixed:\r\n* FloatField was never mapped to DB type\r\n* SQLite doesn't respect Decimal quantization (easily emulatable)\r\n* SQLite requires BOOL to be emulated as integer. So `0`, `1` & `null`.\r\n* PostgreSQL 9.4 needed for JSONB type (updated travis and should update docs)\r\n","created_at":"2018-07-04T18:28:53Z","updated_at":"2018-07-05T09:29:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2b644fc17384337b1b67abf2644633e699612bfe","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20/commits","review_comments_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20/comments","review_comment_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/20/comments","statuses_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/statuses/8c4d373c6cb7f6409c59cfa1dde2b06fabf83ee6","head":{"label":"grigi:feature/testing","ref":"feature/testing","sha":"8c4d373c6cb7f6409c59cfa1dde2b06fabf83ee6","user":{"login":"grigi","id":1309160,"node_id":"MDQ6VXNlcjEzMDkxNjA=","avatar_url":"https://avatars2.githubusercontent.com/u/1309160?v=4","gravatar_id":"","url":"https://api.github.com/users/grigi","html_url":"https://github.com/grigi","followers_url":"https://api.github.com/users/grigi/followers","following_url":"https://api.github.com/users/grigi/following{/other_user}","gists_url":"https://api.github.com/users/grigi/gists{/gist_id}","starred_url":"https://api.github.com/users/grigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grigi/subscriptions","organizations_url":"https://api.github.com/users/grigi/orgs","repos_url":"https://api.github.com/users/grigi/repos","events_url":"https://api.github.com/users/grigi/events{/privacy}","received_events_url":"https://api.github.com/users/grigi/received_events","type":"User","site_admin":false},"repo":{"id":138854344,"node_id":"MDEwOlJlcG9zaXRvcnkxMzg4NTQzNDQ=","name":"tortoise-orm","full_name":"grigi/tortoise-orm","owner":{"login":"grigi","id":1309160,"node_id":"MDQ6VXNlcjEzMDkxNjA=","avatar_url":"https://avatars2.githubusercontent.com/u/1309160?v=4","gravatar_id":"","url":"https://api.github.com/users/grigi","html_url":"https://github.com/grigi","followers_url":"https://api.github.com/users/grigi/followers","following_url":"https://api.github.com/users/grigi/following{/other_user}","gists_url":"https://api.github.com/users/grigi/gists{/gist_id}","starred_url":"https://api.github.com/users/grigi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grigi/subscriptions","organizations_url":"https://api.github.com/users/grigi/orgs","repos_url":"https://api.github.com/users/grigi/repos","events_url":"https://api.github.com/users/grigi/events{/privacy}","received_events_url":"https://api.github.com/users/grigi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/grigi/tortoise-orm","description":"Easy async ORM for python, build with relations in mind","fork":true,"url":"https://api.github.com/repos/grigi/tortoise-orm","forks_url":"https://api.github.com/repos/grigi/tortoise-orm/forks","keys_url":"https://api.github.com/repos/grigi/tortoise-orm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/grigi/tortoise-orm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/grigi/tortoise-orm/teams","hooks_url":"https://api.github.com/repos/grigi/tortoise-orm/hooks","issue_events_url":"https://api.github.com/repos/grigi/tortoise-orm/issues/events{/number}","events_url":"https://api.github.com/repos/grigi/tortoise-orm/events","assignees_url":"https://api.github.com/repos/grigi/tortoise-orm/assignees{/user}","branches_url":"https://api.github.com/repos/grigi/tortoise-orm/branches{/branch}","tags_url":"https://api.github.com/repos/grigi/tortoise-orm/tags","blobs_url":"https://api.github.com/repos/grigi/tortoise-orm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/grigi/tortoise-orm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/grigi/tortoise-orm/git/refs{/sha}","trees_url":"https://api.github.com/repos/grigi/tortoise-orm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/grigi/tortoise-orm/statuses/{sha}","languages_url":"https://api.github.com/repos/grigi/tortoise-orm/languages","stargazers_url":"https://api.github.com/repos/grigi/tortoise-orm/stargazers","contributors_url":"https://api.github.com/repos/grigi/tortoise-orm/contributors","subscribers_url":"https://api.github.com/repos/grigi/tortoise-orm/subscribers","subscription_url":"https://api.github.com/repos/grigi/tortoise-orm/subscription","commits_url":"https://api.github.com/repos/grigi/tortoise-orm/commits{/sha}","git_commits_url":"https://api.github.com/repos/grigi/tortoise-orm/git/commits{/sha}","comments_url":"https://api.github.com/repos/grigi/tortoise-orm/comments{/number}","issue_comment_url":"https://api.github.com/repos/grigi/tortoise-orm/issues/comments{/number}","contents_url":"https://api.github.com/repos/grigi/tortoise-orm/contents/{+path}","compare_url":"https://api.github.com/repos/grigi/tortoise-orm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/grigi/tortoise-orm/merges","archive_url":"https://api.github.com/repos/grigi/tortoise-orm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/grigi/tortoise-orm/downloads","issues_url":"https://api.github.com/repos/grigi/tortoise-orm/issues{/number}","pulls_url":"https://api.github.com/repos/grigi/tortoise-orm/pulls{/number}","milestones_url":"https://api.github.com/repos/grigi/tortoise-orm/milestones{/number}","notifications_url":"https://api.github.com/repos/grigi/tortoise-orm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/grigi/tortoise-orm/labels{/name}","releases_url":"https://api.github.com/repos/grigi/tortoise-orm/releases{/id}","deployments_url":"https://api.github.com/repos/grigi/tortoise-orm/deployments","created_at":"2018-06-27T08:45:11Z","updated_at":"2018-06-28T20:48:57Z","pushed_at":"2018-07-04T23:30:25Z","git_url":"git://github.com/grigi/tortoise-orm.git","ssh_url":"git@github.com:grigi/tortoise-orm.git","clone_url":"https://github.com/grigi/tortoise-orm.git","svn_url":"https://github.com/grigi/tortoise-orm","homepage":"","size":215,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Zeliboba5:master","ref":"master","sha":"99f74312ff74265cc31e79f1cc0d096d47fc8d6a","user":{"login":"Zeliboba5","id":10978839,"node_id":"MDQ6VXNlcjEwOTc4ODM5","avatar_url":"https://avatars1.githubusercontent.com/u/10978839?v=4","gravatar_id":"","url":"https://api.github.com/users/Zeliboba5","html_url":"https://github.com/Zeliboba5","followers_url":"https://api.github.com/users/Zeliboba5/followers","following_url":"https://api.github.com/users/Zeliboba5/following{/other_user}","gists_url":"https://api.github.com/users/Zeliboba5/gists{/gist_id}","starred_url":"https://api.github.com/users/Zeliboba5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zeliboba5/subscriptions","organizations_url":"https://api.github.com/users/Zeliboba5/orgs","repos_url":"https://api.github.com/users/Zeliboba5/repos","events_url":"https://api.github.com/users/Zeliboba5/events{/privacy}","received_events_url":"https://api.github.com/users/Zeliboba5/received_events","type":"User","site_admin":false},"repo":{"id":127320882,"node_id":"MDEwOlJlcG9zaXRvcnkxMjczMjA4ODI=","name":"tortoise-orm","full_name":"Zeliboba5/tortoise-orm","owner":{"login":"Zeliboba5","id":10978839,"node_id":"MDQ6VXNlcjEwOTc4ODM5","avatar_url":"https://avatars1.githubusercontent.com/u/10978839?v=4","gravatar_id":"","url":"https://api.github.com/users/Zeliboba5","html_url":"https://github.com/Zeliboba5","followers_url":"https://api.github.com/users/Zeliboba5/followers","following_url":"https://api.github.com/users/Zeliboba5/following{/other_user}","gists_url":"https://api.github.com/users/Zeliboba5/gists{/gist_id}","starred_url":"https://api.github.com/users/Zeliboba5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zeliboba5/subscriptions","organizations_url":"https://api.github.com/users/Zeliboba5/orgs","repos_url":"https://api.github.com/users/Zeliboba5/repos","events_url":"https://api.github.com/users/Zeliboba5/events{/privacy}","received_events_url":"https://api.github.com/users/Zeliboba5/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Zeliboba5/tortoise-orm","description":"Easy async ORM for python, build with relations in mind","fork":false,"url":"https://api.github.com/repos/Zeliboba5/tortoise-orm","forks_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/forks","keys_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/teams","hooks_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/hooks","issue_events_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/events{/number}","events_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/events","assignees_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/assignees{/user}","branches_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/branches{/branch}","tags_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/tags","blobs_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/git/refs{/sha}","trees_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/statuses/{sha}","languages_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/languages","stargazers_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/stargazers","contributors_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/contributors","subscribers_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/subscribers","subscription_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/subscription","commits_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/commits{/sha}","git_commits_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/git/commits{/sha}","comments_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/comments{/number}","issue_comment_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/comments{/number}","contents_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/contents/{+path}","compare_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/merges","archive_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/downloads","issues_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues{/number}","pulls_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls{/number}","milestones_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/milestones{/number}","notifications_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/labels{/name}","releases_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/releases{/id}","deployments_url":"https://api.github.com/repos/Zeliboba5/tortoise-orm/deployments","created_at":"2018-03-29T16:52:10Z","updated_at":"2018-07-04T08:16:49Z","pushed_at":"2018-07-04T22:13:57Z","git_url":"git://github.com/Zeliboba5/tortoise-orm.git","ssh_url":"git@github.com:Zeliboba5/tortoise-orm.git","clone_url":"https://github.com/Zeliboba5/tortoise-orm.git","svn_url":"https://github.com/Zeliboba5/tortoise-orm","homepage":"","size":172,"stargazers_count":23,"watchers_count":23,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":11,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":1,"open_issues":11,"watchers":23,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20"},"html":{"href":"https://github.com/Zeliboba5/tortoise-orm/pull/20"},"issue":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/20"},"comments":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/issues/20/comments"},"review_comments":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20/comments"},"review_comment":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/pulls/20/commits"},"statuses":{"href":"https://api.github.com/repos/Zeliboba5/tortoise-orm/statuses/8c4d373c6cb7f6409c59cfa1dde2b06fabf83ee6"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"Zeliboba5"}}