From d51fcb604f9e4a0f9b7d4178d4c85209594afbde Mon Sep 17 00:00:00 2001 From: Ben Fasoli Date: Wed, 25 Mar 2020 18:51:56 -0700 Subject: [PATCH 1/3] Replace `cls` argument with `self` Not sure if this was originally intended to be a `@classmethod` but it's now written and called as a method bound to an instance of the class. --- dataset/types.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dataset/types.py b/dataset/types.py index 46f5550..320bc48 100644 --- a/dataset/types.py +++ b/dataset/types.py @@ -16,7 +16,7 @@ class Types(object): date = Date datetime = DateTime - def guess(cls, sample): + def guess(self, sample): """Given a single sample, guess the column type for the field. If the sample is an instance of an SQLAlchemy type, the type will be @@ -25,13 +25,13 @@ class Types(object): if isinstance(sample, TypeEngine): return sample if isinstance(sample, bool): - return cls.boolean + return self.boolean elif isinstance(sample, int): - return cls.bigint + return self.bigint elif isinstance(sample, float): - return cls.float + return self.float elif isinstance(sample, datetime): - return cls.datetime + return self.datetime elif isinstance(sample, date): - return cls.date - return cls.text + return self.date + return self.text From aeaab500433e1d9698959394982974d5f55c9b71 Mon Sep 17 00:00:00 2001 From: Ben Fasoli Date: Wed, 25 Mar 2020 19:35:36 -0700 Subject: [PATCH 2/3] Adds support to serialize `dict` as JSON There are likely some vendor-specific enhancements (such as `JSONB` in PostgreSQL) but the current method of type guessing doesn't know anything about the underlying database. --- dataset/types.py | 5 ++++- test/test_dataset.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dataset/types.py b/dataset/types.py index 320bc48..97c5b18 100644 --- a/dataset/types.py +++ b/dataset/types.py @@ -1,7 +1,7 @@ from datetime import datetime, date from sqlalchemy import Integer, UnicodeText, Float, BigInteger -from sqlalchemy import Boolean, Date, DateTime, Unicode +from sqlalchemy import Boolean, Date, DateTime, Unicode, JSON from sqlalchemy.types import TypeEngine @@ -15,6 +15,7 @@ class Types(object): boolean = Boolean date = Date datetime = DateTime + json = JSON def guess(self, sample): """Given a single sample, guess the column type for the field. @@ -34,4 +35,6 @@ class Types(object): return self.datetime elif isinstance(sample, date): return self.date + elif isinstance(sample, dict): + return self.json return self.text diff --git a/test/test_dataset.py b/test/test_dataset.py index e5cecd6..fb21952 100644 --- a/test/test_dataset.py +++ b/test/test_dataset.py @@ -192,6 +192,20 @@ class TableTestCase(unittest.TestCase): ) assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl) + def test_insert_json(self): + last_id = self.tbl.insert({ + 'date': datetime(2011, 1, 2), + 'temperature': -10, + 'place': 'Berlin', + 'info': { + 'currency': 'EUR', + 'language': 'German', + 'population': 3292365 + } + }) + assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl) + assert self.tbl.find_one(id=last_id)['place'] == 'Berlin' + def test_upsert(self): self.tbl.upsert({ 'date': datetime(2011, 1, 2), From 7fee6da44dd506bdfd03aaf672ec90c885fb8520 Mon Sep 17 00:00:00 2001 From: Ben Fasoli Date: Wed, 25 Mar 2020 20:29:58 -0700 Subject: [PATCH 3/3] Adds support for `JSONB` in PostgresQL Passes dialect to instances of `Types` for vendor-specific type mappings. --- dataset/database.py | 2 +- dataset/types.py | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dataset/database.py b/dataset/database.py index 3155b5a..87d85be 100644 --- a/dataset/database.py +++ b/dataset/database.py @@ -45,9 +45,9 @@ class Database(object): if len(schema_qs): schema = schema_qs.pop() - self.types = Types() self.schema = schema self.engine = create_engine(url, **engine_kwargs) + self.types = Types(self.engine.dialect.name) self.url = url self.row_type = row_type self.ensure_schema = ensure_schema diff --git a/dataset/types.py b/dataset/types.py index 97c5b18..904ffa9 100644 --- a/dataset/types.py +++ b/dataset/types.py @@ -15,14 +15,26 @@ class Types(object): boolean = Boolean date = Date datetime = DateTime - json = JSON - def guess(self, sample): + def __init__(self, dialect = None): + self._dialect = dialect + + @property + def json(self): + if self._dialect is not None and self._dialect == 'postgresql': + from sqlalchemy.dialects.postgresql import JSONB + return JSONB + return JSON + + def guess(self, sample, dialect = None): """Given a single sample, guess the column type for the field. If the sample is an instance of an SQLAlchemy type, the type will be used instead. """ + if dialect is not None: + self._dialect = dialect + if isinstance(sample, TypeEngine): return sample if isinstance(sample, bool):