Skip to content

Commit

Permalink
update for version 5
Browse files Browse the repository at this point in the history
  • Loading branch information
daimor committed May 20, 2024
1 parent fb50a35 commit aad8add
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 177 deletions.
44 changes: 32 additions & 12 deletions django_iris/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.db.models.functions.text import Chr, ConcatPair, StrIndex
from django.db.models.fields import TextField, CharField

from django_iris.compiler import SQLCompiler

fn_template = "{fn %(function)s(%(expressions)s)}"

as_fn = [
Expand All @@ -22,16 +24,20 @@
"TAN",
]


def as_intersystems(cls):
def inner(func):
cls.as_intersystems = func

return inner


class Log10(Func):
function = "LOG10"
arity = 1
lookup_name = "log10"


class Convert(Func):
function = "CONVERT"
lookup_name = "convert"
Expand All @@ -45,36 +51,45 @@ def as_sql(self, compiler, connection, **extra_context):
extra_context["db_type"] = self.output_field.cast_db_type(connection)
return super().as_sql(compiler, connection, **extra_context)


def convert_streams(expressions):
return [
Convert(expression, CharField()) if isinstance(expression, Col) and isinstance(expression.target, TextField) else expression
(
Convert(expression, CharField())
if isinstance(expression, Col) and isinstance(expression.target, TextField)
else expression
)
for expression in expressions
]


@as_intersystems(Exists)
def exists_as_intersystems(self, compiler, connection, template=None, **extra_context):
template = "(SELECT COUNT(*) FROM (%(subquery)s))"
return self.as_sql(compiler, connection, template, **extra_context)


@as_intersystems(Chr)
def chr_as_intersystems(self, compiler, connection, **extra_context):
return self.as_sql(compiler, connection, function="CHAR", **extra_context)


@as_intersystems(ConcatPair)
def concat_as_intersystems(self, compiler, connection, **extra_context):
copy = self.copy()
expressions = convert_streams(copy.get_source_expressions())
"""
STRING in IRIS retuns NULL if all NULL arguments, so, just add empty string, to make it always non NULL
"""
copy.set_source_expressions([Value("")]+ expressions)
copy.set_source_expressions([Value("")] + expressions)
return super(ConcatPair, copy).as_sql(
compiler,
connection,
function="STRING",
**extra_context,
)


@as_intersystems(StrIndex)
def instr_as_intersystems(self, compiler, connection, **extra_context):
copy = self.copy()
Expand All @@ -86,23 +101,26 @@ def instr_as_intersystems(self, compiler, connection, **extra_context):
**extra_context,
)


@as_intersystems(Random)
def random_as_intersystems(self, compiler, connection, **extra_context):
return self.as_sql(compiler, connection, template="%%TSQL.ZRAND(1e10)", **extra_context)
return self.as_sql(
compiler, connection, template="%%TSQL.ZRAND(1e10)", **extra_context
)


@as_intersystems(Ln)
def ln_as_intersystems(self, compiler, connection, **extra_context):
return self.as_sql(compiler, connection, function="LOG", template=fn_template, **extra_context)
return self.as_sql(
compiler, connection, function="LOG", template=fn_template, **extra_context
)


@as_intersystems(Log)
def log_as_intersystems(self, compiler, connection, **extra_context):
copy = self.copy()
copy.set_source_expressions(
[
Log10(expression)
for expression in copy.get_source_expressions()[::-1]
]
[Log10(expression) for expression in copy.get_source_expressions()[::-1]]
)
return super(Log, copy).as_sql(
compiler,
Expand All @@ -112,22 +130,24 @@ def log_as_intersystems(self, compiler, connection, **extra_context):
**extra_context,
)


@as_intersystems(Func)
def func_as_intersystems(self, compiler, connection, **extra_context):
if self.function in as_fn:
def func_as_intersystems(self, compiler: SQLCompiler, connection, **extra_context):
if self.function in as_fn:
return self.as_sql(compiler, connection, template=fn_template, **extra_context)
return self.as_sql(compiler, connection, **extra_context)


@as_intersystems(Now)
def now_as_intersystems(self, compiler, connection, **extra_context):
return self.as_sql(
compiler, connection, template="CURRENT_TIMESTAMP(6)", **extra_context
)


@as_intersystems(OrderBy)
def orderby_as_intersystems(self, compiler, connection, **extra_context):
copy = self.copy()
# IRIS does not support order NULL
copy.nulls_first = copy.nulls_last = False
copy.nulls_first = copy.nulls_last = False
return copy.as_sql(compiler, connection, **extra_context)

149 changes: 73 additions & 76 deletions django_iris/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,55 +24,56 @@ def ignore(*args, **kwargs):
class DatabaseClient(BaseDatabaseClient):
runshell = ignore


class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'intersystems'
display_name = 'InterSystems IRIS'
vendor = "intersystems"
display_name = "InterSystems IRIS"

data_types = {
'AutoField': 'IDENTITY',
'BigAutoField': 'IDENTITY',
'BinaryField': 'LONG BINARY',
'BooleanField': 'BIT',
'CharField': 'VARCHAR(%(max_length)s)',
'DateField': 'DATE',
'DateTimeField': 'TIMESTAMP',
'DecimalField': 'NUMERIC(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'BIGINT',
'FileField': 'VARCHAR(%(max_length)s)',
'FilePathField': 'VARCHAR(%(max_length)s)',
'FloatField': 'DOUBLE PRECISION',
'IntegerField': 'INTEGER',
'BigIntegerField': 'BIGINT',
'IPAddressField': 'CHAR(15)',
'GenericIPAddressField': 'CHAR(39)',
'JSONField': 'VARCHAR(32768)',
'OneToOneField': 'INTEGER',
'PositiveBigIntegerField': 'BIGINT',
'PositiveIntegerField': 'INTEGER',
'PositiveSmallIntegerField': 'SMALLINT',
'SlugField': 'VARCHAR(%(max_length)s)',
'SmallAutoField': 'IDENTITY',
'SmallIntegerField': 'SMALLINT',
'TextField': 'TEXT',
'TimeField': 'TIME(6)',
'UUIDField': 'CHAR(32)',
"AutoField": "IDENTITY",
"BigAutoField": "IDENTITY",
"BinaryField": "LONG BINARY",
"BooleanField": "BIT",
"CharField": "VARCHAR(%(max_length)s)",
"DateField": "DATE",
"DateTimeField": "TIMESTAMP",
"DecimalField": "NUMERIC(%(max_digits)s, %(decimal_places)s)",
"DurationField": "BIGINT",
"FileField": "VARCHAR(%(max_length)s)",
"FilePathField": "VARCHAR(%(max_length)s)",
"FloatField": "DOUBLE PRECISION",
"IntegerField": "INTEGER",
"BigIntegerField": "BIGINT",
"IPAddressField": "CHAR(15)",
"GenericIPAddressField": "CHAR(39)",
"JSONField": "VARCHAR(32768)",
"OneToOneField": "INTEGER",
"PositiveBigIntegerField": "BIGINT",
"PositiveIntegerField": "INTEGER",
"PositiveSmallIntegerField": "SMALLINT",
"SlugField": "VARCHAR(%(max_length)s)",
"SmallAutoField": "IDENTITY",
"SmallIntegerField": "SMALLINT",
"TextField": "TEXT",
"TimeField": "TIME(6)",
"UUIDField": "UNIQUEIDENTIFIER",
}

operators = {
'exact': '= %s',
'iexact': "LIKE %s ESCAPE '\\'",
'contains': "LIKE %s ESCAPE '\\'",
'icontains': "LIKE %s ESCAPE '\\'",
"exact": "= %s",
"iexact": "LIKE %s ESCAPE '\\'",
"contains": "LIKE %s ESCAPE '\\'",
"icontains": "LIKE %s ESCAPE '\\'",
# 'regex': "%%%%MATCHES %s ESCAPE '\\'",
# 'iregex': "%%%%MATCHES %s ESCAPE '\\'",
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',
'lte': '<= %s',
'startswith': "LIKE %s ESCAPE '\\'",
'endswith': "LIKE %s ESCAPE '\\'",
'istartswith': "LIKE %s ESCAPE '\\'",
'iendswith': "LIKE %s ESCAPE '\\'",
"gt": "> %s",
"gte": ">= %s",
"lt": "< %s",
"lte": "<= %s",
"startswith": "LIKE %s ESCAPE '\\'",
"endswith": "LIKE %s ESCAPE '\\'",
"istartswith": "LIKE %s ESCAPE '\\'",
"iendswith": "LIKE %s ESCAPE '\\'",
}

pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')"
Expand All @@ -83,7 +84,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
"istartswith": "LIKE UPPER({}) || '%%'",
"endswith": "LIKE '%%' || {}",
"iendswith": "LIKE '%%' || UPPER({})",

}

Database = Database
Expand All @@ -110,62 +110,59 @@ def get_connection_params(self):
settings_dict = self.settings_dict

conn_params = {
'username': None,
'password': None,
'timeout': 30,
"username": None,
"password": None,
"timeout": 30,
}
if settings_dict['USER']:
conn_params['username'] = settings_dict['USER']
if settings_dict['PASSWORD']:
conn_params['password'] = settings_dict['PASSWORD']
if 'TIMEOUT' in settings_dict:
conn_params['timeout'] = settings_dict['TIMEOUT']
if 'EMBEDDED' in settings_dict:
conn_params['embedded'] = settings_dict['EMBEDDED']
if 'CONNECTION_STRING' in settings_dict:
conn_params['connectionstr'] = settings_dict['CONNECTION_STRING']
if settings_dict["USER"]:
conn_params["username"] = settings_dict["USER"]
if settings_dict["PASSWORD"]:
conn_params["password"] = settings_dict["PASSWORD"]
if "TIMEOUT" in settings_dict:
conn_params["timeout"] = settings_dict["TIMEOUT"]
if "EMBEDDED" in settings_dict:
conn_params["embedded"] = settings_dict["EMBEDDED"]
if "CONNECTION_STRING" in settings_dict:
conn_params["connectionstr"] = settings_dict["CONNECTION_STRING"]
else:
conn_params = {
'hostname': 'localhost',
'port': 1972,
'namespace': 'USER',
"hostname": "localhost",
"port": 1972,
"namespace": "USER",
**conn_params,
}
if settings_dict['HOST']:
conn_params['hostname'] = settings_dict['HOST']
if settings_dict['PORT']:
conn_params['port'] = settings_dict['PORT']
if 'NAMESPACE' in settings_dict:
conn_params['namespace'] = settings_dict['NAMESPACE']
if settings_dict['NAME']:
conn_params['namespace'] = settings_dict['NAME']
if settings_dict["HOST"]:
conn_params["hostname"] = settings_dict["HOST"]
if settings_dict["PORT"]:
conn_params["port"] = settings_dict["PORT"]
if "NAMESPACE" in settings_dict:
conn_params["namespace"] = settings_dict["NAMESPACE"]
if settings_dict["NAME"]:
conn_params["namespace"] = settings_dict["NAME"]

if (
not conn_params['hostname'] or
not conn_params['port'] or
not conn_params['namespace']
not conn_params["hostname"]
or not conn_params["port"]
or not conn_params["namespace"]
):
raise ImproperlyConfigured(
"settings.DATABASES is improperly configured. "
"Please supply the HOST, PORT and NAME"
)

if (
not conn_params['username'] or
not conn_params['password']
):
if not conn_params["username"] or not conn_params["password"]:
raise ImproperlyConfigured(
"settings.DATABASES is improperly configured. "
"Please supply the USER and PASSWORD"
)

conn_params['application_name'] = 'django'
conn_params["application_name"] = "django"
conn_params["autoCommit"] = self.autocommit
return conn_params

def init_connection_state(self):
pass

@async_unsafe
def get_new_connection(self, conn_params):
return Database.connect(**conn_params)
Expand All @@ -186,7 +183,7 @@ def create_cursor(self, name=None):
def is_usable(self):
try:
with self.connection.cursor() as cursor:
cursor.execute('SELECT 1')
cursor.execute("SELECT 1")
except:
return False
else:
Expand Down
Loading

0 comments on commit aad8add

Please sign in to comment.