18
18
19
19
20
20
class DatabaseWrapper (BaseDatabaseWrapper ):
21
- vendor = ' spanner'
22
- display_name = ' Cloud Spanner'
21
+ vendor = " spanner"
22
+ display_name = " Cloud Spanner"
23
23
24
24
# Mapping of Field objects to their column types.
25
25
# https://cloud.google.com/spanner/docs/data-types#date-type
26
26
data_types = {
27
- ' AutoField' : ' INT64' ,
28
- ' BigAutoField' : ' INT64' ,
29
- ' BinaryField' : ' BYTES(MAX)' ,
30
- ' BooleanField' : ' BOOL' ,
31
- ' CharField' : ' STRING(%(max_length)s)' ,
32
- ' DateField' : ' DATE' ,
33
- ' DateTimeField' : ' TIMESTAMP' ,
34
- ' DecimalField' : ' FLOAT64' ,
35
- ' DurationField' : ' INT64' ,
36
- ' EmailField' : ' STRING(%(max_length)s)' ,
37
- ' FileField' : ' STRING(%(max_length)s)' ,
38
- ' FilePathField' : ' STRING(%(max_length)s)' ,
39
- ' FloatField' : ' FLOAT64' ,
40
- ' IntegerField' : ' INT64' ,
41
- ' BigIntegerField' : ' INT64' ,
42
- ' IPAddressField' : ' STRING(15)' ,
43
- ' GenericIPAddressField' : ' STRING(39)' ,
44
- ' NullBooleanField' : ' BOOL' ,
45
- ' OneToOneField' : ' INT64' ,
46
- ' PositiveIntegerField' : ' INT64' ,
47
- ' PositiveSmallIntegerField' : ' INT64' ,
48
- ' SlugField' : ' STRING(%(max_length)s)' ,
49
- ' SmallAutoField' : ' INT64' ,
50
- ' SmallIntegerField' : ' INT64' ,
51
- ' TextField' : ' STRING(MAX)' ,
52
- ' TimeField' : ' TIMESTAMP' ,
53
- ' UUIDField' : ' STRING(32)' ,
27
+ " AutoField" : " INT64" ,
28
+ " BigAutoField" : " INT64" ,
29
+ " BinaryField" : " BYTES(MAX)" ,
30
+ " BooleanField" : " BOOL" ,
31
+ " CharField" : " STRING(%(max_length)s)" ,
32
+ " DateField" : " DATE" ,
33
+ " DateTimeField" : " TIMESTAMP" ,
34
+ " DecimalField" : " FLOAT64" ,
35
+ " DurationField" : " INT64" ,
36
+ " EmailField" : " STRING(%(max_length)s)" ,
37
+ " FileField" : " STRING(%(max_length)s)" ,
38
+ " FilePathField" : " STRING(%(max_length)s)" ,
39
+ " FloatField" : " FLOAT64" ,
40
+ " IntegerField" : " INT64" ,
41
+ " BigIntegerField" : " INT64" ,
42
+ " IPAddressField" : " STRING(15)" ,
43
+ " GenericIPAddressField" : " STRING(39)" ,
44
+ " NullBooleanField" : " BOOL" ,
45
+ " OneToOneField" : " INT64" ,
46
+ " PositiveIntegerField" : " INT64" ,
47
+ " PositiveSmallIntegerField" : " INT64" ,
48
+ " SlugField" : " STRING(%(max_length)s)" ,
49
+ " SmallAutoField" : " INT64" ,
50
+ " SmallIntegerField" : " INT64" ,
51
+ " TextField" : " STRING(MAX)" ,
52
+ " TimeField" : " TIMESTAMP" ,
53
+ " UUIDField" : " STRING(32)" ,
54
54
}
55
55
operators = {
56
- ' exact' : ' = %s' ,
57
- ' iexact' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
56
+ " exact" : " = %s" ,
57
+ " iexact" : " REGEXP_CONTAINS(%s, %%%%s)" ,
58
58
# contains uses REGEXP_CONTAINS instead of LIKE to allow
59
59
# DatabaseOperations.prep_for_like_query() to do regular expression
60
60
# escaping. prep_for_like_query() is called for all the lookups that
61
61
# use REGEXP_CONTAINS except regex/iregex (see
62
62
# django.db.models.lookups.PatternLookup).
63
- ' contains' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
64
- ' icontains' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
65
- 'gt' : ' > %s' ,
66
- ' gte' : ' >= %s' ,
67
- 'lt' : ' < %s' ,
68
- ' lte' : ' <= %s' ,
63
+ " contains" : " REGEXP_CONTAINS(%s, %%%%s)" ,
64
+ " icontains" : " REGEXP_CONTAINS(%s, %%%%s)" ,
65
+ "gt" : " > %s" ,
66
+ " gte" : " >= %s" ,
67
+ "lt" : " < %s" ,
68
+ " lte" : " <= %s" ,
69
69
# Using REGEXP_CONTAINS instead of STARTS_WITH and ENDS_WITH for the
70
70
# same reasoning as described above for 'contains'.
71
- ' startswith' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
72
- ' endswith' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
73
- ' istartswith' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
74
- ' iendswith' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
75
- ' regex' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
76
- ' iregex' : ' REGEXP_CONTAINS(%s, %%%%s)' ,
71
+ " startswith" : " REGEXP_CONTAINS(%s, %%%%s)" ,
72
+ " endswith" : " REGEXP_CONTAINS(%s, %%%%s)" ,
73
+ " istartswith" : " REGEXP_CONTAINS(%s, %%%%s)" ,
74
+ " iendswith" : " REGEXP_CONTAINS(%s, %%%%s)" ,
75
+ " regex" : " REGEXP_CONTAINS(%s, %%%%s)" ,
76
+ " iregex" : " REGEXP_CONTAINS(%s, %%%%s)" ,
77
77
}
78
78
79
79
# pattern_esc is used to generate SQL pattern lookup clauses when the
80
80
# right-hand side of the lookup isn't a raw string (it might be an
81
81
# expression or the result of a bilateral transformation). In those cases,
82
82
# special characters for REGEXP_CONTAINS operators (e.g. \, *, _) must be
83
83
# escaped on database side.
84
- pattern_esc = r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
84
+ pattern_esc = (
85
+ r'REPLACE(REPLACE(REPLACE({}, "\\", "\\\\"), "%%", r"\%%"), "_", r"\_")'
86
+ )
85
87
# These are all no-ops in favor of using REGEXP_CONTAINS in the customized
86
88
# lookups.
87
89
pattern_ops = {
88
- ' contains' : '' ,
89
- ' icontains' : '' ,
90
- ' startswith' : '' ,
91
- ' istartswith' : '' ,
92
- ' endswith' : '' ,
93
- ' iendswith' : '' ,
90
+ " contains" : "" ,
91
+ " icontains" : "" ,
92
+ " startswith" : "" ,
93
+ " istartswith" : "" ,
94
+ " endswith" : "" ,
95
+ " iendswith" : "" ,
94
96
}
95
97
96
98
Database = Database
@@ -104,19 +106,19 @@ class DatabaseWrapper(BaseDatabaseWrapper):
104
106
105
107
@property
106
108
def instance (self ):
107
- return spanner .Client ().instance (self .settings_dict [' INSTANCE' ])
109
+ return spanner .Client ().instance (self .settings_dict [" INSTANCE" ])
108
110
109
111
@property
110
112
def _nodb_connection (self ):
111
113
raise NotImplementedError ('Spanner does not have a "no db" connection.' )
112
114
113
115
def get_connection_params (self ):
114
116
return {
115
- ' project' : self .settings_dict [' PROJECT' ],
116
- 'instance' : self .settings_dict [' INSTANCE' ],
117
- 'database' : self .settings_dict [' NAME' ],
118
- ' user_agent' : ' django_spanner/0.0.1' ,
119
- ** self .settings_dict [' OPTIONS' ],
117
+ " project" : self .settings_dict [" PROJECT" ],
118
+ "instance_id" : self .settings_dict [" INSTANCE" ],
119
+ "database_id" : self .settings_dict [" NAME" ],
120
+ " user_agent" : " django_spanner/0.0.1" ,
121
+ ** self .settings_dict [" OPTIONS" ],
120
122
}
121
123
122
124
def get_new_connection (self , conn_params ):
@@ -137,7 +139,7 @@ def is_usable(self):
137
139
return False
138
140
try :
139
141
# Use a cursor directly, bypassing Django's utilities.
140
- self .connection .cursor ().execute (' SELECT 1' )
142
+ self .connection .cursor ().execute (" SELECT 1" )
141
143
except Database .Error :
142
144
return False
143
145
else :
0 commit comments