Skip to content

Commit 1921c02

Browse files
authored
Merge branch 'master' into bug/multiple-json-profiles
2 parents eebcedb + 804fdc8 commit 1921c02

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

src/gino/declarative.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,12 @@ def _init_table(cls, sub_cls):
289289
inspected_args = []
290290
updates = {}
291291
column_name_map = InvertDict()
292-
for each_cls in sub_cls.__mro__[::-1]:
292+
visited = set()
293+
for each_cls in sub_cls.__mro__:
293294
for k, v in getattr(each_cls, "__namespace__", each_cls.__dict__).items():
295+
if k in visited:
296+
continue
297+
visited.add(k)
294298
declared_callable_attr = callable(v) and getattr(
295299
v, "__declared_attr__", False
296300
)
@@ -311,6 +315,8 @@ def _init_table(cls, sub_cls):
311315
updates[k] = sub_cls.__attr_factory__(k, v)
312316
elif isinstance(v, (sa.Index, sa.Constraint)):
313317
inspected_args.append(v)
318+
elif isinstance(v, json_support.JSONProperty):
319+
updates[k] = v
314320
if table_name is None:
315321
return
316322
sub_cls._column_name_map = column_name_map
@@ -351,6 +357,8 @@ def _init_table(cls, sub_cls):
351357
if isinstance(v, json_support.JSONProperty):
352358
if v.prop_name not in prop_names:
353359
prop_names.append(v.prop_name)
360+
if not v.name:
361+
v.name = k
354362
json_col = getattr(
355363
sub_cls.__dict__.get(v.prop_name), "column", None
356364
)

tests/test_declarative.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,34 @@ class Another(Audit, db.Model):
179179
assert False, "Should not reach here"
180180

181181

182+
async def test_mixin_crud(engine):
183+
db = gino.Gino()
184+
db.bind = engine
185+
186+
class Mixin:
187+
id = db.Column(db.Integer, primary_key=True)
188+
name = db.Column(db.Text)
189+
190+
class MixinCrud(db.Model, Mixin):
191+
__tablename__ = "mixin_crud"
192+
193+
await db.gino.create_all()
194+
try:
195+
mc = await MixinCrud.create(name="mctest")
196+
assert mc.name == "mctest"
197+
198+
await mc.update(name="updated").apply()
199+
200+
mc = await MixinCrud.query.gino.first()
201+
assert mc.name == "updated"
202+
203+
await mc.delete()
204+
mc = await MixinCrud.query.gino.first()
205+
assert mc is None
206+
finally:
207+
await db.gino.drop_all()
208+
209+
182210
# noinspection PyUnusedLocal
183211
async def test_inherit_constraint():
184212
with pytest.raises(ValueError, match="already attached to another table"):
@@ -328,3 +356,20 @@ def table_name(cls):
328356
assert n_call == 1
329357
assert Model.table_name == "model6"
330358
assert n_call == 1
359+
360+
361+
async def test_override():
362+
class ModelMixin:
363+
field = db.Column(db.String)
364+
365+
class Model(db.Model, ModelMixin):
366+
__tablename__ = "model7"
367+
368+
normal = db.Column(db.Integer)
369+
370+
@property
371+
def field(self):
372+
return "field is a const value"
373+
374+
assert len(Model.__table__.columns) == 1
375+
assert Model().field == "field is a const value"

tests/test_json.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,27 @@ def age_idx(cls):
358358

359359
await IndexTest.gino.create()
360360
await IndexTest.gino.drop()
361+
362+
363+
async def test_mixin(bind):
364+
from gino.dialects.asyncpg import JSONB
365+
366+
class Base:
367+
id = db.Column(db.Integer(), primary_key=True)
368+
profile = db.Column(JSONB())
369+
370+
class Mixin(Base):
371+
age = db.IntegerProperty()
372+
373+
class MixinTest(db.Model, Mixin):
374+
__tablename__ = "mixin_test"
375+
376+
await MixinTest.gino.create()
377+
try:
378+
mt = await MixinTest.create(age=22)
379+
await mt.update(age=24).apply()
380+
assert (await MixinTest.query.gino.first()).age == 24
381+
await mt.update(age=MixinTest.age - 5).apply()
382+
assert (await MixinTest.query.gino.first()).age == 19
383+
finally:
384+
await MixinTest.gino.drop()

0 commit comments

Comments
 (0)