Added support for Timescale and Timescale (GIS)

Timescale is a Postgres based database for time series data and it's
supported via the django-timescaledb package.

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
Lino Helms 2022-07-10 11:16:06 +02:00 committed by Matt Seymour
parent 88b991f60d
commit 91bb95360e
3 changed files with 170 additions and 28 deletions

View file

@ -26,7 +26,7 @@ Supported Databases
-------------------
Support currently exists for PostgreSQL, PostGIS, MySQL, MySQL (GIS),
Oracle, Oracle (GIS), Redshift, CockroachDB, and SQLite.
Oracle, Oracle (GIS), Redshift, CockroachDB, Timescale, Timescale (GIS) and SQLite.
Installation
------------
@ -88,33 +88,37 @@ and should instead be passed as::
URL schema
----------
+-------------+-----------------------------------------------+--------------------------------------------------+
| Engine | Django Backend | URL |
+=============+===============================================+==================================================+
| PostgreSQL | ``django.db.backends.postgresql`` [1]_ | ``postgres://USER:PASSWORD@HOST:PORT/NAME`` [2]_ |
+-------------+-----------------------------------------------+--------------------------------------------------+
| PostGIS | ``django.contrib.gis.db.backends.postgis`` | ``postgis://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| MSSQL | ``sql_server.pyodbc`` | ``mssql://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| MSSQL [5]_ | ``mssql`` | ``mssqlms://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| MySQL | ``django.db.backends.mysql`` | ``mysql://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| MySQL (GIS) | ``django.contrib.gis.db.backends.mysql`` | ``mysqlgis://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| SQLite | ``django.db.backends.sqlite3`` | ``sqlite:///PATH`` [3]_ |
+-------------+-----------------------------------------------+--------------------------------------------------+
| SpatiaLite | ``django.contrib.gis.db.backends.spatialite`` | ``spatialite:///PATH`` [3]_ |
+-------------+-----------------------------------------------+--------------------------------------------------+
| Oracle | ``django.db.backends.oracle`` | ``oracle://USER:PASSWORD@HOST:PORT/NAME`` [4]_ |
+-------------+-----------------------------------------------+--------------------------------------------------+
| Oracle (GIS)| ``django.contrib.gis.db.backends.oracle`` | ``oraclegis://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| Redshift | ``django_redshift_backend`` | ``redshift://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
| CockroachDB | ``django_cockroachdb`` | ``cockroach://USER:PASSWORD@HOST:PORT/NAME`` |
+-------------+-----------------------------------------------+--------------------------------------------------+
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Engine | Django Backend | URL |
+======================+===============================================+==================================================+
| PostgreSQL | ``django.db.backends.postgresql`` [1]_ | ``postgres://USER:PASSWORD@HOST:PORT/NAME`` [2]_ |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| PostGIS | ``django.contrib.gis.db.backends.postgis`` | ``postgis://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| MSSQL | ``sql_server.pyodbc`` | ``mssql://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| MSSQL [5]_ | ``mssql`` | ``mssqlms://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| MySQL | ``django.db.backends.mysql`` | ``mysql://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| MySQL (GIS) | ``django.contrib.gis.db.backends.mysql`` | ``mysqlgis://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| SQLite | ``django.db.backends.sqlite3`` | ``sqlite:///PATH`` [3]_ |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| SpatiaLite | ``django.contrib.gis.db.backends.spatialite`` | ``spatialite:///PATH`` [3]_ |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Oracle | ``django.db.backends.oracle`` | ``oracle://USER:PASSWORD@HOST:PORT/NAME`` [4]_ |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Oracle (GIS) | ``django.contrib.gis.db.backends.oracle`` | ``oraclegis://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Redshift | ``django_redshift_backend`` | ``redshift://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| CockroachDB | ``django_cockroachdb`` | ``cockroach://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Timescale [6]_ | ``timescale.db.backends.postgresql`` | ``timescale://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
| Timescale (GIS) [6]_ | ``timescale.db.backend.postgis`` | ``timescalegis://USER:PASSWORD@HOST:PORT/NAME`` |
+----------------------+-----------------------------------------------+--------------------------------------------------+
.. [1] The django.db.backends.postgresql backend is named django.db.backends.postgresql_psycopg2 in older releases. For
backwards compatibility, the old name still works in newer versions. (The new name does not work in older versions).
@ -130,6 +134,8 @@ URL schema
by ``:`` not by ``/``. Also you can omit ``HOST`` and ``PORT``
and provide a full DSN string or TNS name in ``NAME`` part.
.. [5] Microsoft official `mssql-django <https://github.com/microsoft/mssql-django>`_ adapter.
.. [6] Using the django-timescaledb Package which must be installed.
Contributing
------------

View file

@ -26,6 +26,8 @@ urlparse.uses_netloc.append("oracle")
urlparse.uses_netloc.append("oraclegis")
urlparse.uses_netloc.append("redshift")
urlparse.uses_netloc.append("cockroach")
urlparse.uses_netloc.append("timescale")
urlparse.uses_netloc.append("timescalegis")
DEFAULT_ENV = "DATABASE_URL"
@ -43,6 +45,8 @@ SCHEMES = {
"oraclegis": "django.contrib.gis.db.backends.oracle",
"redshift": "django_redshift_backend",
"cockroach": "django_cockroachdb",
"timescale": "timescale.db.backends.postgresql",
"timescalegis": "timescale.db.backends.postgis",
}
# https://docs.djangoproject.com/en/2.0/releases/2.0/#id1
@ -147,6 +151,8 @@ def parse(url, engine=None, conn_max_age=0, ssl_require=False):
"django.db.backends.postgresql_psycopg2",
"django.db.backends.postgresql",
"django_redshift_backend",
"timescale.db.backends.postgresql",
"timescale.db.backends.postgis",
):
options["options"] = "-c search_path={0}".format(options.pop("currentSchema"))

View file

@ -371,6 +371,136 @@ class DatabaseTestSuite(unittest.TestCase):
assert url["OPTIONS"]["driver"] == "ODBC Driver 13 for SQL Server"
assert "currentSchema" not in url["OPTIONS"]
def test_timescale_parsing(self):
url = "timescale://uf07k1i6d8ia0v:wegauwhgeuioweg@ec2-107-21-253-135.compute-1.amazonaws.com:5431/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "uf07k1i6d8ia0v"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
def test_timescale_unix_socket_parsing(self):
url = "timescale://%2Fvar%2Frun%2Fpostgresql/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "/var/run/postgresql"
assert url["USER"] == ""
assert url["PASSWORD"] == ""
assert url["PORT"] == ""
url = "timescale://%2FUsers%2Fpostgres%2FRuN/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["HOST"] == "/Users/postgres/RuN"
assert url["USER"] == ""
assert url["PASSWORD"] == ""
assert url["PORT"] == ""
def test_timescale_ipv6_parsing(self):
url = "timescale://ieRaekei9wilaim7:wegauwhgeuioweg@[2001:db8:1234::1234:5678:90af]:5431/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "2001:db8:1234::1234:5678:90af"
assert url["USER"] == "ieRaekei9wilaim7"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
def test_timescale_search_path_parsing(self):
url = "timescale://uf07k1i6d8ia0v:wegauwhgeuioweg@ec2-107-21-253-135.compute-1.amazonaws.com:5431/d8r82722r2kuvn?currentSchema=otherschema"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "uf07k1i6d8ia0v"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
assert url["OPTIONS"]["options"] == "-c search_path=otherschema"
assert "currentSchema" not in url["OPTIONS"]
def test_timescale_parsing_with_special_characters(self):
url = "timescale://%23user:%23password@ec2-107-21-253-135.compute-1.amazonaws.com:5431/%23database"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgresql"
assert url["NAME"] == "#database"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "#user"
assert url["PASSWORD"] == "#password"
assert url["PORT"] == 5431
def test_timescalegis_parsing(self):
url = "timescalegis://uf07k1i6d8ia0v:wegauwhgeuioweg@ec2-107-21-253-135.compute-1.amazonaws.com:5431/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "uf07k1i6d8ia0v"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
def test_timescalegis_unix_socket_parsing(self):
url = "timescalegis://%2Fvar%2Frun%2Fpostgresql/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "/var/run/postgresql"
assert url["USER"] == ""
assert url["PASSWORD"] == ""
assert url["PORT"] == ""
url = "timescalegis://%2FUsers%2Fpostgres%2FRuN/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["HOST"] == "/Users/postgres/RuN"
assert url["USER"] == ""
assert url["PASSWORD"] == ""
assert url["PORT"] == ""
def test_timescalegis_ipv6_parsing(self):
url = "timescalegis://ieRaekei9wilaim7:wegauwhgeuioweg@[2001:db8:1234::1234:5678:90af]:5431/d8r82722r2kuvn"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "2001:db8:1234::1234:5678:90af"
assert url["USER"] == "ieRaekei9wilaim7"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
def test_timescalegis_search_path_parsing(self):
url = "timescalegis://uf07k1i6d8ia0v:wegauwhgeuioweg@ec2-107-21-253-135.compute-1.amazonaws.com:5431/d8r82722r2kuvn?currentSchema=otherschema"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["NAME"] == "d8r82722r2kuvn"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "uf07k1i6d8ia0v"
assert url["PASSWORD"] == "wegauwhgeuioweg"
assert url["PORT"] == 5431
assert url["OPTIONS"]["options"] == "-c search_path=otherschema"
assert "currentSchema" not in url["OPTIONS"]
def test_timescalegis_parsing_with_special_characters(self):
url = "timescalegis://%23user:%23password@ec2-107-21-253-135.compute-1.amazonaws.com:5431/%23database"
url = dj_database_url.parse(url)
assert url["ENGINE"] == "timescale.db.backends.postgis"
assert url["NAME"] == "#database"
assert url["HOST"] == "ec2-107-21-253-135.compute-1.amazonaws.com"
assert url["USER"] == "#user"
assert url["PASSWORD"] == "#password"
assert url["PORT"] == 5431
if __name__ == "__main__":
unittest.main()