Skip to content

Commit 06deb36

Browse files
committed
add tests for migrations.
1 parent 871526e commit 06deb36

File tree

245 files changed

+22322
-199
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

245 files changed

+22322
-199
lines changed

README.md

+6-36
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ clickhouse.
1010
Thanks to [clickhouse driver](https://github.com/mymarilyn/clickhouse-driver), django clickhouse backend use it as [DBAPI](https://peps.python.org/pep-0249/).
1111
Thanks to [clickhouse pool](https://github.com/ericmccarthy7/clickhouse-pool), it makes clickhouse connection pool.
1212

13+
[Documentation](https://github.com/jayvynl/django-clickhouse-backend/blob/main/docs/README.md)
1314

1415
**features:**
1516

@@ -162,62 +163,31 @@ Topics
162163
Django ORM depends heavily on single column primary key, this primary key is a unique identifier of an ORM object.
163164
All `get` `save` `delete` actions depend on primary key.
164165

165-
But in ClickHouse [primary key](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#primary-keys-and-indexes-in-queries) has different meaning with django primary key. ClickHouse does not require a unique primary key. You can insert multiple rows with the same primary key.
166+
But in ClickHouse [primary key](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#primary-keys-and-indexes-in-queries) has different meaning from django primary key. ClickHouse does not require a unique primary key. You can insert multiple rows with the same primary key.
166167

167168
There is [no unique constraint](https://github.com/ClickHouse/ClickHouse/issues/3386#issuecomment-429874647) or auto increasing column in clickhouse.
168169

169170
By default, django will add a field named `id` as auto increasing primary key.
170171

171172
- AutoField
172173

173-
Mapped to clickhouse Int32 data type. You should generate this unique id yourself
174+
Mapped to clickhouse Int32 data type. You should generate this unique id yourself.
174175

175176
- BigAutoField
176177

177-
Mapped to clickhouse Int64 data type. If primary key is not specified when insert data, then `clickhouse_driver.idworker.id_worker` is used to generate this unique key.
178+
Mapped to clickhouse Int64 data type. If primary key is not specified when insert data, then `clickhouse_driver.idworker.id_worker` is used to generate this unique id.
178179

179180
Default id_worker is an instance of `clickhouse.idworker.snowflake.SnowflakeIDWorker` which implement [twitter snowflake id](https://en.wikipedia.org/wiki/Snowflake_ID).
180181
If data insertions happen on multiple datacenter, server, process or thread, you should ensure uniqueness of (CLICKHOUSE_WORKER_ID, CLICKHOUSE_DATACENTER_ID) environment variable.
181182
Because work_id and datacenter_id are 5 bits, they should be an integer between 0 and 31. CLICKHOUSE_WORKER_ID default to 0, CLICKHOUSE_DATACENTER_ID will be generated randomly if not provided.
182183

183-
`clickhouse.idworker.snowflake.SnowflakeIDWorker` is not thread safe. You could inherit `clickhouse.idworker.base.BaseIDWorker` and implement one, and set `CLICKHOUSE_ID_WORKER` to doted import path of your IDWorker instance.
184+
`clickhouse.idworker.snowflake.SnowflakeIDWorker` is not thread safe. You could inherit `clickhouse.idworker.base.BaseIDWorker` and implement one, then set `CLICKHOUSE_ID_WORKER` in `settings.py` to doted import path of your IDWorker instance.
184185

185186
Django use a table named `django_migrations` to track migration files. ID field should be BigAutoField, so that IDWorker can generate unique id for you.
186187
After Django 3.2,a new [config `DEFAULT_AUTO_FIELD`](https://docs.djangoproject.com/en/4.1/releases/3.2/#customizing-type-of-auto-created-primary-keys) is introduced to control field type of default primary key.
187188
So `DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'` is required if you want to use migrations with django clickhouse backend.
188189

189190

190-
### Fields
191-
192-
#### Nullable
193-
194-
`null=True` will make [Nullable](https://clickhouse.com/docs/en/sql-reference/data-types/nullable/) type in clickhouse database.
195-
196-
**Note** Using Nullable almost always negatively affects performance, keep this in mind when designing your databases.
197-
198-
#### GenericIPAddressField
199-
200-
Clickhouse backend has its own implementation in `clickhouse_backend.models.fields.GenericIPAddressField`.
201-
If `protocol='ipv4'`, a column of [IPv4](https://clickhouse.com/docs/en/sql-reference/data-types/domains/ipv4) is generated, else [IPv6](https://clickhouse.com/docs/en/sql-reference/data-types/domains/ipv6) is generated.
202-
203-
#### PositiveSmallIntegerField
204-
#### PositiveIntegerField
205-
#### PositiveBigIntegerField
206-
207-
`clickhouse_backend.models.fields.PositiveSmallIntegerField` maps to [UInt16](https://clickhouse.com/docs/en/sql-reference/data-types/int-uint).
208-
`clickhouse_backend.models.fields.PositiveIntegerField` maps to [UInt32](https://clickhouse.com/docs/en/sql-reference/data-types/int-uint).
209-
`clickhouse_backend.models.fields.PositiveBigIntegerField` maps to [UInt64](https://clickhouse.com/docs/en/sql-reference/data-types/int-uint).
210-
Clickhouse have unsigned integer type, these fields will have right integer range validators.
211-
212-
213-
### Engines
214-
215-
Lays in `clickhouse_backend.models.engines`.
216-
217-
### Indexes
218-
219-
Lays in `clickouse_backend.models.indexes`.
220-
221191
Test
222192
---
223193

@@ -231,7 +201,7 @@ docker-compose up -d
231201
python tests/runtests.py
232202
```
233203

234-
**Note** This project is not fully tested yet and should be used with caution in production.
204+
**Note:** This project is not fully tested yet and should be used with caution in production.
235205

236206
License
237207
---

clickhouse_backend/backend/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
2525
# be interpolated against the values of Field.__dict__ before being output.
2626
# If a column type is set to None, it won't be included in the output.
2727
data_types = {
28+
'SmallAutoField': 'Int16',
2829
'AutoField': 'Int32',
2930
'BigAutoField': 'Int64',
3031
'IPAddressField': 'IPv4',
@@ -37,13 +38,13 @@ class DatabaseWrapper(BaseDatabaseWrapper):
3738
'FileField': 'String',
3839
'FilePathField': 'String',
3940
'FloatField': 'Float64',
41+
'SmallIntegerField': 'Int16',
4042
'IntegerField': 'Int32',
4143
'BigIntegerField': 'Int64',
4244
'PositiveBigIntegerField': 'UInt64',
4345
'PositiveIntegerField': 'UInt32',
4446
'PositiveSmallIntegerField': 'UInt16',
4547
'SlugField': 'String',
46-
'SmallIntegerField': 'Int16',
4748
'TextField': 'String',
4849
'UUIDField': 'UUID',
4950
'BooleanField': 'Int8',
@@ -71,7 +72,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
7172
#
7273
# Note: we use str.format() here for readability as '%' is used as a wildcard for
7374
# the LIKE operator.
74-
pattern_esc = r"replaceAll(replaceAll(replaceAll({}, '\\', '\\\\'), '%', '\\%'), '_', '\\_')"
75+
pattern_esc = r"replaceRegexpAll({}, '\\\\|%%|_', '\\\\\\0')"
7576
pattern_ops = {
7677
'contains': "LIKE '%%' || {} || '%%'",
7778
'icontains': "ILIKE '%%' || {} || '%%'",

clickhouse_backend/backend/operations.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.db.backends.base.operations import BaseDatabaseOperations
55

66
from clickhouse_backend import compat
7+
from clickhouse_backend.driver.client import insert_pattern
78

89

910
class DatabaseOperations(BaseDatabaseOperations):
@@ -350,10 +351,11 @@ def savepoint_rollback_sql(self, sid):
350351
return super().savepoint_rollback_sql(sid)
351352

352353
def last_executed_query(self, cursor, sql, params):
353-
if sql.startswith("INSERT INTO"):
354-
return "%s %s" % (sql, ", ".join(map(str, params)))
355354
if params:
356-
return sql % params
355+
if insert_pattern.match(sql):
356+
return "%s %s" % (sql, str(tuple(tuple(param) for param in params)))
357+
else:
358+
return sql % tuple(params)
357359
return sql
358360

359361
def settings_sql(self, **settings):

0 commit comments

Comments
 (0)