ydb-sqlalchemy 0.1.13__py2.py3-none-any.whl → 0.1.15__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
test/test_core.py CHANGED
@@ -228,6 +228,15 @@ class TestTypes(TablesTest):
228
228
  Column("float", sa.Float),
229
229
  Column("bool", sa.Boolean),
230
230
  )
231
+ Table(
232
+ "test_all_binary_types",
233
+ metadata,
234
+ Column("id", sa.Integer, primary_key=True),
235
+ Column("bin", sa.BINARY),
236
+ Column("large_bin", sa.LargeBinary),
237
+ Column("blob", sa.BLOB),
238
+ Column("custom_bin", types.Binary),
239
+ )
231
240
  Table(
232
241
  "test_datetime_types",
233
242
  metadata,
@@ -255,6 +264,21 @@ class TestTypes(TablesTest):
255
264
  row = connection.execute(sa.select(table)).fetchone()
256
265
  assert row == (42, "Hello World!", 3.5, True)
257
266
 
267
+ def test_all_binary_types(self, connection):
268
+ table = self.tables.test_all_binary_types
269
+ data = {
270
+ "id": 1,
271
+ "bin": b"binary",
272
+ "large_bin": b"large_binary",
273
+ "blob": b"blob",
274
+ "custom_bin": b"custom_binary",
275
+ }
276
+ statement = sa.insert(table).values(**data)
277
+ connection.execute(statement)
278
+
279
+ row = connection.execute(sa.select(table)).fetchone()
280
+ assert row == (1, b"binary", b"large_binary", b"blob", b"custom_binary")
281
+
258
282
  def test_integer_types(self, connection):
259
283
  stmt = sa.select(
260
284
  sa.func.FormatType(sa.func.TypeOf(sa.bindparam("p_uint8", 8, types.UInt8))),
@@ -1112,3 +1136,114 @@ class TestTablePathPrefix(TablesTest):
1112
1136
  metadata.reflect(reflection_engine)
1113
1137
 
1114
1138
  assert "nested_dir/table" in metadata.tables
1139
+
1140
+
1141
+ class TestAsTable(TablesTest):
1142
+ __backend__ = True
1143
+
1144
+ @classmethod
1145
+ def define_tables(cls, metadata):
1146
+ Table(
1147
+ "test_as_table",
1148
+ metadata,
1149
+ Column("id", Integer, primary_key=True),
1150
+ Column("val_int", Integer, nullable=True),
1151
+ Column("val_str", String, nullable=True),
1152
+ )
1153
+
1154
+ def test_upsert_as_table(self, connection):
1155
+ table = self.tables.test_as_table
1156
+
1157
+ input_data = [
1158
+ {"id": 1, "val_int": 10, "val_str": "a"},
1159
+ {"id": 2, "val_int": None, "val_str": "b"},
1160
+ {"id": 3, "val_int": 30, "val_str": None},
1161
+ ]
1162
+
1163
+ struct_type = types.StructType(
1164
+ {
1165
+ "id": Integer,
1166
+ "val_int": types.Optional(Integer),
1167
+ "val_str": types.Optional(String),
1168
+ }
1169
+ )
1170
+ list_type = types.ListType(struct_type)
1171
+
1172
+ bind_param = sa.bindparam("data", type_=list_type)
1173
+
1174
+ upsert_stm = ydb_sa.upsert(table).from_select(
1175
+ ["id", "val_int", "val_str"],
1176
+ sa.select(
1177
+ sa.column("id", type_=Integer), sa.column("val_int", type_=Integer), sa.column("val_str", type_=String)
1178
+ ).select_from(sa.func.AS_TABLE(bind_param)),
1179
+ )
1180
+
1181
+ connection.execute(upsert_stm, {"data": input_data})
1182
+
1183
+ rows = connection.execute(sa.select(table).order_by(table.c.id)).fetchall()
1184
+ assert rows == [
1185
+ (1, 10, "a"),
1186
+ (2, None, "b"),
1187
+ (3, 30, None),
1188
+ ]
1189
+
1190
+ def test_insert_as_table(self, connection):
1191
+ table = self.tables.test_as_table
1192
+
1193
+ input_data = [
1194
+ {"id": 4, "val_int": 40, "val_str": "d"},
1195
+ {"id": 5, "val_int": None, "val_str": "e"},
1196
+ ]
1197
+
1198
+ struct_type = types.StructType(
1199
+ {
1200
+ "id": Integer,
1201
+ "val_int": types.Optional(Integer),
1202
+ "val_str": types.Optional(String),
1203
+ }
1204
+ )
1205
+ list_type = types.ListType(struct_type)
1206
+
1207
+ bind_param = sa.bindparam("data", type_=list_type)
1208
+
1209
+ insert_stm = sa.insert(table).from_select(
1210
+ ["id", "val_int", "val_str"],
1211
+ sa.select(
1212
+ sa.column("id", type_=Integer), sa.column("val_int", type_=Integer), sa.column("val_str", type_=String)
1213
+ ).select_from(sa.func.AS_TABLE(bind_param)),
1214
+ )
1215
+
1216
+ connection.execute(insert_stm, {"data": input_data})
1217
+
1218
+ rows = connection.execute(sa.select(table).where(table.c.id >= 4).order_by(table.c.id)).fetchall()
1219
+ assert rows == [
1220
+ (4, 40, "d"),
1221
+ (5, None, "e"),
1222
+ ]
1223
+
1224
+ def test_upsert_from_table_reflection(self, connection):
1225
+ table = self.tables.test_as_table
1226
+
1227
+ input_data = [
1228
+ {"id": 1, "val_int": 10, "val_str": "a"},
1229
+ {"id": 2, "val_int": None, "val_str": "b"},
1230
+ ]
1231
+
1232
+ struct_type = types.StructType.from_table(table)
1233
+ list_type = types.ListType(struct_type)
1234
+
1235
+ bind_param = sa.bindparam("data", type_=list_type)
1236
+
1237
+ cols = [sa.column(c.name, type_=c.type) for c in table.columns]
1238
+ upsert_stm = ydb_sa.upsert(table).from_select(
1239
+ [c.name for c in table.columns],
1240
+ sa.select(*cols).select_from(sa.func.AS_TABLE(bind_param)),
1241
+ )
1242
+
1243
+ connection.execute(upsert_stm, {"data": input_data})
1244
+
1245
+ rows = connection.execute(sa.select(table).order_by(table.c.id)).fetchall()
1246
+ assert rows == [
1247
+ (1, 10, "a"),
1248
+ (2, None, "b"),
1249
+ ]
test/test_suite.py CHANGED
@@ -274,7 +274,6 @@ class NumericTest(_NumericTest):
274
274
  pass
275
275
 
276
276
 
277
- @pytest.mark.skip("TODO: see issue #13")
278
277
  class BinaryTest(_BinaryTest):
279
278
  pass
280
279
 
@@ -1 +1 @@
1
- VERSION = "0.1.13"
1
+ VERSION = "0.1.15"
@@ -99,6 +99,19 @@ class YdbRequestSettingsCharacteristic(characteristics.ConnectionCharacteristic)
99
99
  return dialect.get_ydb_request_settings(dbapi_connection)
100
100
 
101
101
 
102
+ class YdbRetrySettingsCharacteristic(characteristics.ConnectionCharacteristic):
103
+ def reset_characteristic(self, dialect: "YqlDialect", dbapi_connection: ydb_dbapi.Connection) -> None:
104
+ dialect.reset_ydb_retry_settings(dbapi_connection)
105
+
106
+ def set_characteristic(
107
+ self, dialect: "YqlDialect", dbapi_connection: ydb_dbapi.Connection, value: ydb.RetrySettings
108
+ ) -> None:
109
+ dialect.set_ydb_retry_settings(dbapi_connection, value)
110
+
111
+ def get_characteristic(self, dialect: "YqlDialect", dbapi_connection: ydb_dbapi.Connection) -> ydb.RetrySettings:
112
+ return dialect.get_ydb_retry_settings(dbapi_connection)
113
+
114
+
102
115
  class YqlDialect(StrCompileDialect):
103
116
  name = "yql"
104
117
  driver = "ydb"
@@ -144,12 +157,16 @@ class YqlDialect(StrCompileDialect):
144
157
  sa.types.DATETIME: types.YqlDateTime,
145
158
  sa.types.TIMESTAMP: types.YqlTimestamp,
146
159
  sa.types.DECIMAL: types.Decimal,
160
+ sa.types.BINARY: types.Binary,
161
+ sa.types.LargeBinary: types.Binary,
162
+ sa.types.BLOB: types.Binary,
147
163
  }
148
164
 
149
165
  connection_characteristics = util.immutabledict(
150
166
  {
151
167
  "isolation_level": characteristics.IsolationLevelCharacteristic(),
152
168
  "ydb_request_settings": YdbRequestSettingsCharacteristic(),
169
+ "ydb_retry_settings": YdbRetrySettingsCharacteristic(),
153
170
  }
154
171
  )
155
172
 
@@ -312,6 +329,19 @@ class YqlDialect(StrCompileDialect):
312
329
  def get_ydb_request_settings(self, dbapi_connection: ydb_dbapi.Connection) -> ydb.BaseRequestSettings:
313
330
  return dbapi_connection.get_ydb_request_settings()
314
331
 
332
+ def set_ydb_retry_settings(
333
+ self,
334
+ dbapi_connection: ydb_dbapi.Connection,
335
+ value: ydb.RetrySettings,
336
+ ) -> None:
337
+ dbapi_connection.set_ydb_retry_settings(value)
338
+
339
+ def reset_ydb_retry_settings(self, dbapi_connection: ydb_dbapi.Connection):
340
+ self.set_ydb_retry_settings(dbapi_connection, ydb.RetrySettings())
341
+
342
+ def get_ydb_retry_settings(self, dbapi_connection: ydb_dbapi.Connection) -> ydb.RetrySettings:
343
+ return dbapi_connection.get_ydb_retry_settings()
344
+
315
345
  def create_connect_args(self, url):
316
346
  args, kwargs = super().create_connect_args(url)
317
347
  # YDB database name should start with '/'
@@ -12,6 +12,7 @@ from sqlalchemy.sql.compiler import (
12
12
  StrSQLTypeCompiler,
13
13
  selectable,
14
14
  )
15
+ from sqlalchemy.sql.type_api import to_instance
15
16
  from typing import (
16
17
  Any,
17
18
  Dict,
@@ -24,6 +25,12 @@ from typing import (
24
25
  Union,
25
26
  )
26
27
 
28
+ try:
29
+ from sqlalchemy.types import _Binary as _BinaryType
30
+ except ImportError:
31
+ # For older sqlalchemy versions
32
+ from sqlalchemy.sql.sqltypes import _Binary as _BinaryType
33
+
27
34
 
28
35
  from .. import types
29
36
 
@@ -152,11 +159,17 @@ class BaseYqlTypeCompiler(StrSQLTypeCompiler):
152
159
  inner = self.process(type_.item_type, **kw)
153
160
  return f"List<{inner}>"
154
161
 
162
+ def visit_optional(self, type_: types.Optional, **kw):
163
+ el = to_instance(type_.element_type)
164
+ inner = self.process(el, **kw)
165
+ return f"Optional<{inner}>"
166
+
155
167
  def visit_struct_type(self, type_: types.StructType, **kw):
156
- text = "Struct<"
157
- for field, field_type in type_.fields_types:
158
- text += f"{field}:{self.process(field_type, **kw)}"
159
- return text + ">"
168
+ rendered_types = []
169
+ for field, field_type in type_.fields_types.items():
170
+ type_str = self.process(field_type, **kw)
171
+ rendered_types.append(f"{field}:{type_str}")
172
+ return f"Struct<{','.join(rendered_types)}>"
160
173
 
161
174
  def get_ydb_type(
162
175
  self, type_: sa.types.TypeEngine, is_optional: bool
@@ -167,6 +180,10 @@ class BaseYqlTypeCompiler(StrSQLTypeCompiler):
167
180
  if isinstance(type_, (sa.Text, sa.String)):
168
181
  ydb_type = ydb.PrimitiveType.Utf8
169
182
 
183
+ elif isinstance(type_, types.Optional):
184
+ inner = to_instance(type_.element_type)
185
+ return self.get_ydb_type(inner, is_optional=True)
186
+
170
187
  # Integers
171
188
  elif isinstance(type_, types.UInt64):
172
189
  ydb_type = ydb.PrimitiveType.Uint64
@@ -216,7 +233,7 @@ class BaseYqlTypeCompiler(StrSQLTypeCompiler):
216
233
  ydb_type = ydb.PrimitiveType.Timestamp
217
234
  elif isinstance(type_, sa.Date):
218
235
  ydb_type = ydb.PrimitiveType.Date
219
- elif isinstance(type_, sa.BINARY):
236
+ elif isinstance(type_, _BinaryType):
220
237
  ydb_type = ydb.PrimitiveType.String
221
238
  elif isinstance(type_, sa.Float):
222
239
  ydb_type = ydb.PrimitiveType.Float
@@ -235,7 +252,8 @@ class BaseYqlTypeCompiler(StrSQLTypeCompiler):
235
252
  elif isinstance(type_, types.StructType):
236
253
  ydb_type = ydb.StructType()
237
254
  for field, field_type in type_.fields_types.items():
238
- ydb_type.add_member(field, self.get_ydb_type(field_type(), is_optional=False))
255
+ inner_type = to_instance(field_type)
256
+ ydb_type.add_member(field, self.get_ydb_type(inner_type, is_optional=False))
239
257
  else:
240
258
  raise NotSupportedError(f"{type_} bind variables not supported")
241
259
 
@@ -56,6 +56,12 @@ class AdaptedAsyncConnection(AdaptedConnection):
56
56
  def get_ydb_request_settings(self) -> ydb.BaseRequestSettings:
57
57
  return self._connection.get_ydb_request_settings()
58
58
 
59
+ def set_ydb_retry_settings(self, value: ydb.RetrySettings) -> None:
60
+ self._connection.set_ydb_retry_settings(value)
61
+
62
+ def get_ydb_retry_settings(self) -> ydb.RetrySettings:
63
+ return self._connection.get_ydb_retry_settings()
64
+
59
65
  def describe(self, table_path: str):
60
66
  return await_only(self._connection.describe(table_path))
61
67
 
@@ -35,3 +35,111 @@ def test_ydb_types():
35
35
  compiled = query.compile(dialect=dialect, compile_kwargs={"literal_binds": True})
36
36
 
37
37
  assert str(compiled) == "Date('1996-11-19')"
38
+
39
+
40
+ def test_binary_type():
41
+ dialect = YqlDialect()
42
+ expr = sa.literal(b"some bytes")
43
+ compiled = expr.compile(dialect=dialect, compile_kwargs={"literal_binds": True})
44
+ assert str(compiled) == "'some bytes'"
45
+
46
+ expr_binary = sa.cast(expr, sa.BINARY)
47
+ compiled_binary = expr_binary.compile(dialect=dialect, compile_kwargs={"literal_binds": True})
48
+ assert str(compiled_binary) == "CAST('some bytes' AS String)"
49
+
50
+
51
+ def test_all_binary_types():
52
+ dialect = YqlDialect()
53
+ expr = sa.literal(b"some bytes")
54
+
55
+ binary_types = [
56
+ sa.BINARY,
57
+ sa.LargeBinary,
58
+ sa.BLOB,
59
+ types.Binary,
60
+ ]
61
+
62
+ for type_ in binary_types:
63
+ expr_binary = sa.cast(expr, type_)
64
+ compiled_binary = expr_binary.compile(dialect=dialect, compile_kwargs={"literal_binds": True})
65
+ assert str(compiled_binary) == "CAST('some bytes' AS String)"
66
+
67
+
68
+ def test_struct_type_generation():
69
+ dialect = YqlDialect()
70
+ type_compiler = dialect.type_compiler
71
+
72
+ # Test default (non-optional)
73
+ struct_type = types.StructType(
74
+ {
75
+ "id": sa.Integer,
76
+ "val_int": sa.Integer,
77
+ }
78
+ )
79
+ ydb_type = type_compiler.get_ydb_type(struct_type, is_optional=False)
80
+ # Keys are sorted
81
+ assert str(ydb_type) == "Struct<id:Int64,val_int:Int64>"
82
+
83
+ # Test optional
84
+ struct_type_opt = types.StructType(
85
+ {
86
+ "id": sa.Integer,
87
+ "val_int": types.Optional(sa.Integer),
88
+ }
89
+ )
90
+ ydb_type_opt = type_compiler.get_ydb_type(struct_type_opt, is_optional=False)
91
+ assert str(ydb_type_opt) == "Struct<id:Int64,val_int:Int64?>"
92
+
93
+
94
+ def test_types_compilation():
95
+ dialect = YqlDialect()
96
+
97
+ def compile_type(type_):
98
+ return dialect.type_compiler.process(type_)
99
+
100
+ assert compile_type(types.UInt64()) == "UInt64"
101
+ assert compile_type(types.UInt32()) == "UInt32"
102
+ assert compile_type(types.UInt16()) == "UInt16"
103
+ assert compile_type(types.UInt8()) == "UInt8"
104
+
105
+ assert compile_type(types.Int64()) == "Int64"
106
+ assert compile_type(types.Int32()) == "Int32"
107
+ assert compile_type(types.Int16()) == "Int32"
108
+ assert compile_type(types.Int8()) == "Int8"
109
+
110
+ assert compile_type(types.ListType(types.Int64())) == "List<Int64>"
111
+
112
+ struct = types.StructType({"a": types.Int32(), "b": types.ListType(types.Int32())})
113
+ # Ordered by key: a, b
114
+ assert compile_type(struct) == "Struct<a:Int32,b:List<Int32>>"
115
+
116
+
117
+ def test_optional_type_compilation():
118
+ dialect = YqlDialect()
119
+ type_compiler = dialect.type_compiler
120
+
121
+ def compile_type(type_):
122
+ return type_compiler.process(type_)
123
+
124
+ # Test Optional(Integer)
125
+ opt_int = types.Optional(sa.Integer)
126
+ assert compile_type(opt_int) == "Optional<Int64>"
127
+
128
+ # Test Optional(String)
129
+ opt_str = types.Optional(sa.String)
130
+ assert compile_type(opt_str) == "Optional<UTF8>"
131
+
132
+ # Test Nested Optional
133
+ opt_opt_int = types.Optional(types.Optional(sa.Integer))
134
+ assert compile_type(opt_opt_int) == "Optional<Optional<Int64>>"
135
+
136
+ # Test get_ydb_type
137
+ ydb_type = type_compiler.get_ydb_type(opt_int, is_optional=False)
138
+ import ydb
139
+
140
+ assert isinstance(ydb_type, ydb.OptionalType)
141
+ # Int64 corresponds to PrimitiveType.Int64
142
+ # Note: ydb.PrimitiveType.Int64 is an enum member, but ydb_type.item is also an instance/enum?
143
+ # get_ydb_type returns ydb.PrimitiveType.Int64 (enum) wrapped in OptionalType.
144
+ # OptionalType.item is the inner type.
145
+ assert ydb_type.item == ydb.PrimitiveType.Int64
@@ -8,7 +8,7 @@ if sa_version.startswith("2."):
8
8
  else:
9
9
  from sqlalchemy.sql.expression import ColumnElement
10
10
 
11
- from sqlalchemy import ARRAY, exc, types
11
+ from sqlalchemy import ARRAY, exc, Table, types
12
12
  from sqlalchemy.sql import type_api
13
13
 
14
14
  from .datetime_types import YqlDate, YqlDateTime, YqlTimestamp, YqlDate32, YqlTimestamp64, YqlDateTime64 # noqa: F401
@@ -116,12 +116,56 @@ class HashableDict(dict):
116
116
  return hash(tuple(self.items()))
117
117
 
118
118
 
119
+ class Optional(types.TypeEngine):
120
+ """
121
+ Wrapper for YDB Optional type.
122
+
123
+ Used primarily within StructType to denote nullable fields.
124
+ """
125
+
126
+ __visit_name__ = "optional"
127
+
128
+ def __init__(self, element_type: Union[Type[types.TypeEngine], types.TypeEngine]):
129
+ self.element_type = element_type
130
+
131
+
119
132
  class StructType(types.TypeEngine[Mapping[str, Any]]):
133
+ """
134
+ YDB Struct type.
135
+
136
+ Represents a structured data type with named fields, mapped to a Python dictionary.
137
+ """
138
+
120
139
  __visit_name__ = "struct_type"
121
140
 
122
- def __init__(self, fields_types: Mapping[str, Union[Type[types.TypeEngine], Type[types.TypeDecorator]]]):
141
+ def __init__(
142
+ self,
143
+ fields_types: Mapping[
144
+ str,
145
+ Union[Type[types.TypeEngine], types.TypeEngine, Optional],
146
+ ],
147
+ ):
123
148
  self.fields_types = HashableDict(dict(sorted(fields_types.items())))
124
149
 
150
+ @classmethod
151
+ def from_table(cls, table: Table) -> "StructType":
152
+ """
153
+ Create a StructType definition from a SQLAlchemy Table.
154
+
155
+ Automatically wraps nullable columns in Optional.
156
+
157
+ :param table: SQLAlchemy Table object
158
+ :return: StructType instance
159
+ """
160
+ fields = {}
161
+ for col in table.columns:
162
+ t = col.type
163
+ if col.nullable:
164
+ fields[col.name] = Optional(t)
165
+ else:
166
+ fields[col.name] = t
167
+ return cls(fields)
168
+
125
169
  @property
126
170
  def python_type(self):
127
171
  return dict
@@ -139,3 +183,10 @@ class Lambda(ColumnElement):
139
183
 
140
184
  self.type = type_api.NULLTYPE
141
185
  self.func = func
186
+
187
+
188
+ class Binary(types.LargeBinary):
189
+ __visit_name__ = "BINARY"
190
+
191
+ def bind_processor(self, dialect):
192
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ydb-sqlalchemy
3
- Version: 0.1.13
3
+ Version: 0.1.15
4
4
  Summary: YDB Dialect for SQLAlchemy
5
5
  Home-page: http://github.com/ydb-platform/ydb-sqlalchemy
6
6
  Author: Yandex LLC
@@ -14,7 +14,7 @@ Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: sqlalchemy <3.0.0,>=1.4.0
16
16
  Requires-Dist: ydb >=3.21.6
17
- Requires-Dist: ydb-dbapi >=0.1.10
17
+ Requires-Dist: ydb-dbapi >=0.1.16
18
18
  Provides-Extra: yc
19
19
  Requires-Dist: yandexcloud ; extra == 'yc'
20
20
 
@@ -1,26 +1,26 @@
1
1
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  test/conftest.py,sha256=rhWa0EQB9EwO_wAwxPdK17Qi582DdbBE8p5Gv4180Ds,570
3
- test/test_core.py,sha256=XvPJ0MtWK2gqGytps4YMUpHtJWKlEqN1rQBUpeeelAg,42859
3
+ test/test_core.py,sha256=5ijngbM6b_8avees4CqCv0FgzAza2RRPDwgT2saU99k,47254
4
4
  test/test_inspect.py,sha256=c4kc3jc48MCOfllO-ciiYf1vO-HOfuv0xVoXYT1Jxro,1106
5
5
  test/test_orm.py,sha256=jQVVld50zbUwxwgW9ySIWGaNDEOLzHKXjTkdpsG9TpA,1825
6
- test/test_suite.py,sha256=3Ht_mEG5zzYUA_7YH3Hax5EZgnGhnPrN0PBuJZvdR9I,31104
6
+ test/test_suite.py,sha256=JYBGZjaRbg_ZiAqTHeCfL7DLnB6N6xkXN82gnooCyd8,31063
7
7
  ydb_sqlalchemy/__init__.py,sha256=hX7Gy-KOiHk7B5-0wj3ZmLjk4YDJnSMHIAqxVGn_PJY,181
8
- ydb_sqlalchemy/_version.py,sha256=0BcN8aokkqZB9wuqna4wlHYj0D056RAOE21Mz-Y_m_E,19
9
- ydb_sqlalchemy/sqlalchemy/__init__.py,sha256=YAj29mdu0GEG0Udoo0p5ANmEyH6OsAKz5FZc0qn6FDY,16570
8
+ ydb_sqlalchemy/_version.py,sha256=f1tdrTNNxSCrK-kaNyZL5_MXChoOPzxvT7JLn3_KW6k,19
9
+ ydb_sqlalchemy/sqlalchemy/__init__.py,sha256=Z5aprCPByfUmH2DvybA0o7W0lQ8YDCR1XSyyfGmBdoE,17911
10
10
  ydb_sqlalchemy/sqlalchemy/datetime_types.py,sha256=wrI9kpsI_f7Jhbm7Fu0o_S1QoGCLIe6A9jfUwb41aMM,1929
11
- ydb_sqlalchemy/sqlalchemy/dbapi_adapter.py,sha256=AH-M0a3dI4A20xrkUMWeZ9QLKqa1GcEioclt9BDGNGI,3297
11
+ ydb_sqlalchemy/sqlalchemy/dbapi_adapter.py,sha256=7FDjganh9QStIkoXYPFfcRRhd07YCX63_8OmMnge1FI,3542
12
12
  ydb_sqlalchemy/sqlalchemy/dml.py,sha256=k_m6PLOAY7dVzG1gsyo2bB3Lp-o3rhzN0oSX_nfkbFU,310
13
13
  ydb_sqlalchemy/sqlalchemy/json.py,sha256=b4ydjlQjBhlhqGP_Sy2uZVKmt__D-9M7-YLGQMdYGME,1043
14
14
  ydb_sqlalchemy/sqlalchemy/requirements.py,sha256=zm6fcLormtk3KHnbtrBvxfkbG9ZyzNan38HrRB6vC3c,2505
15
- ydb_sqlalchemy/sqlalchemy/test_sqlalchemy.py,sha256=QPRgUPsTOqAf0gzWjidsIhTPVkfOILy4SCSgNb1GE7o,1039
16
- ydb_sqlalchemy/sqlalchemy/types.py,sha256=BVeC8RSa2nFnI3-Q7XZxCnAolHc_k_kMCfWhUmbi5wo,3823
15
+ ydb_sqlalchemy/sqlalchemy/test_sqlalchemy.py,sha256=4wyRHmE8YQaMElQPHX6ToEj7A9F8Mvv909aaz_0wRnA,4535
16
+ ydb_sqlalchemy/sqlalchemy/types.py,sha256=_PxK76x6BJZv-7gVdXL-XJtaOFjiYZY4f-_WBRWH8x0,4996
17
17
  ydb_sqlalchemy/sqlalchemy/compiler/__init__.py,sha256=QqA6r-_bw1R97nQZy5ZSJN724znXg88l4mi5PpqAOxI,492
18
- ydb_sqlalchemy/sqlalchemy/compiler/base.py,sha256=zbd9uhV0uxHfMkSTyi4eoZiaiS32yNid4IWfGUo82vA,19433
18
+ ydb_sqlalchemy/sqlalchemy/compiler/base.py,sha256=zKOf4SrcAjMKf1LjRvQA7IzMRic0EIznHuZTHySvc_k,20143
19
19
  ydb_sqlalchemy/sqlalchemy/compiler/sa14.py,sha256=LanxAnwOiMnsnrY05B0jpmvGn5NXuOKMcxi_6N3obVM,1186
20
20
  ydb_sqlalchemy/sqlalchemy/compiler/sa20.py,sha256=rvVhe-pq5bOyuW4KMMMAD7JIWMzy355eijymBvuPwKw,3421
21
- ydb_sqlalchemy-0.1.13.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
- ydb_sqlalchemy-0.1.13.dist-info/METADATA,sha256=Ci_vcXwlXZx21QzRfA1Q9DL8lVXRvf2ngd9l7IVdbWM,5395
23
- ydb_sqlalchemy-0.1.13.dist-info/WHEEL,sha256=Ll72iyqtt6Rbxp-Q7FSafYA1LeRv98X15xcZWRsFEmY,109
24
- ydb_sqlalchemy-0.1.13.dist-info/entry_points.txt,sha256=iJxbKYuliWNBmL0iIiw8MxvOXrSEz5xe5fuEBqMRwCE,267
25
- ydb_sqlalchemy-0.1.13.dist-info/top_level.txt,sha256=iS69Y1GTAcTok0u0oQdxP-Q5iVgUGI71XBsaEUrWhMg,20
26
- ydb_sqlalchemy-0.1.13.dist-info/RECORD,,
21
+ ydb_sqlalchemy-0.1.15.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
+ ydb_sqlalchemy-0.1.15.dist-info/METADATA,sha256=iOoVXzaJ3tJ7ct7jssAXLSUwptb9C4e7Yx3dPp8VzdA,5395
23
+ ydb_sqlalchemy-0.1.15.dist-info/WHEEL,sha256=Ll72iyqtt6Rbxp-Q7FSafYA1LeRv98X15xcZWRsFEmY,109
24
+ ydb_sqlalchemy-0.1.15.dist-info/entry_points.txt,sha256=iJxbKYuliWNBmL0iIiw8MxvOXrSEz5xe5fuEBqMRwCE,267
25
+ ydb_sqlalchemy-0.1.15.dist-info/top_level.txt,sha256=iS69Y1GTAcTok0u0oQdxP-Q5iVgUGI71XBsaEUrWhMg,20
26
+ ydb_sqlalchemy-0.1.15.dist-info/RECORD,,