Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions app/api/routers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,6 @@ async def list_all_admin_tokens(async_session: DBAsyncSession):
if TYPE_CHECKING:
admin_tokens_for_type_check: list[RetrieveAdminTokenResponse] = []
for token in listed_tokens:
# TODO: Migrate listing.token_address to NOT NULL and update ORM typing.
assert token.token_address is not None
# TODO: Migrate listing.is_public to NOT NULL and update ORM typing.
assert token.is_public is not None
# TODO: Migrate listing.owner_address to NOT NULL and update ORM typing.
assert token.owner_address is not None
# TODO: Migrate listing.created to NOT NULL and update ORM typing.
assert token.created is not None
admin_tokens_for_type_check.append(
RetrieveAdminTokenResponse(
id=token.id,
Expand Down Expand Up @@ -325,14 +317,6 @@ async def retrieve_admin_token(
if token is not None:
listed_token_payload = token.json()
if TYPE_CHECKING:
# TODO: Migrate listing.token_address to NOT NULL and update ORM typing.
assert token.token_address is not None
# TODO: Migrate listing.is_public to NOT NULL and update ORM typing.
assert token.is_public is not None
# TODO: Migrate listing.owner_address to NOT NULL and update ORM typing.
assert token.owner_address is not None
# TODO: Migrate listing.created to NOT NULL and update ORM typing.
assert token.created is not None
_ = GenericSuccessResponse[RetrieveAdminTokenResponse](
meta=Success200MetaModel(code=200, message="OK"),
data=RetrieveAdminTokenResponse(
Expand Down
4 changes: 0 additions & 4 deletions app/api/routers/company_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,6 @@ async def list_all_companies(
listing_owner_set.add(owner_address_is_cached[0])
continue

# TODO: Migrate listing.token_address to NOT NULL and update ORM typing
assert token[0].token_address is not None
token_address = to_checksum_address(token[0].token_address)
token_contract = AsyncContract.get_contract(
contract_name="Ownable", address=token_address
Expand Down Expand Up @@ -353,8 +351,6 @@ async def list_all_company_tokens(
token_list: list[TokenDetailDict] = []
token_instance_list: list[TokenInstanceTypes] = []
for available_token in available_list:
# TODO: Migrate listing.token_address to NOT NULL and update ORM typing
assert available_token.token_address is not None
token_address = to_checksum_address(available_token.token_address)
token_info = await AsyncContract.call_function(
contract=list_contract,
Expand Down
6 changes: 2 additions & 4 deletions app/api/routers/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,10 +850,8 @@ async def get_list_from_index(
if offset is not None:
stmt = stmt.offset(offset)

# TODO: Migrate listing.token_address to NOT NULL and update ORM typing.
_token_position_list = cast(
Sequence[tuple[str, IDXPosition, IDXTokenInstance]],
(await async_session.execute(stmt)).tuples().all(),
_token_position_list: Sequence[tuple[str, IDXPosition, IDXTokenInstance]] = (
(await async_session.execute(stmt)).tuples().all()
)

position_list: list[PositionDataDict] = []
Expand Down
1 change: 0 additions & 1 deletion app/model/blockchain/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ async def wrapper(
now = datetime.now(UTC).replace(tzinfo=None)
if (
cached_token
and cached_token.created is not None
and cached_token.created + timedelta(seconds=TOKEN_CACHE_TTL) >= now
):
# If cached data exists and doesn't expire, use cached data
Expand Down
8 changes: 4 additions & 4 deletions app/model/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ def naive_utcnow():
class Base(DeclarativeBase):
if engine.name == "mysql":
# NOTE:MySQLではDatetime型で小数秒桁を指定しない場合、整数秒しか保存されない
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
MySQLDATETIME(fsp=6), default=naive_utcnow
)
modified: Mapped[datetime | None] = mapped_column(
modified: Mapped[datetime] = mapped_column(
MySQLDATETIME(fsp=6), default=naive_utcnow, onupdate=naive_utcnow
)
else:
created: Mapped[datetime | None] = mapped_column(DateTime, default=naive_utcnow)
modified: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(DateTime, default=naive_utcnow)
modified: Mapped[datetime] = mapped_column(
DateTime, default=naive_utcnow, onupdate=naive_utcnow
)

Expand Down
4 changes: 2 additions & 2 deletions app/model/db/company.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ class Company(Base):

if engine.name == "mysql":
# NOTE:MySQLではDatetime型で小数秒桁を指定しない場合、整数秒しか保存されない
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
MySQLDATETIME(fsp=6), default=naive_utcnow, index=True
)
else:
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
DateTime, default=naive_utcnow, index=True
)
__table_args__ = (
Expand Down
11 changes: 5 additions & 6 deletions app/model/db/listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,28 @@ class Listing(Base):

__tablename__ = "listing"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
token_address: Mapped[str | None] = mapped_column(
token_address: Mapped[str] = mapped_column(
String(256), index=True
) # トークンアドレス
is_public: Mapped[bool | None] = mapped_column(Boolean)
is_public: Mapped[bool] = mapped_column(Boolean)
max_holding_quantity: Mapped[int | None] = mapped_column(BigInteger) # 最大保有数量
max_sell_amount: Mapped[int | None] = mapped_column(BigInteger) # 売却価格上限
owner_address: Mapped[str | None] = mapped_column(String(256)) # 発行体アドレス
owner_address: Mapped[str] = mapped_column(String(256)) # 発行体アドレス

if engine.name == "mysql":
# NOTE:MySQLではDatetime型で小数秒桁を指定しない場合、整数秒しか保存されない
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
MySQLDATETIME(fsp=6), default=naive_utcnow, index=True
)
else:
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
DateTime, default=naive_utcnow, index=True
)

def __repr__(self):
return "<Listing id='%d'>" % self.id

def json(self):
assert self.created is not None
return {
"id": self.id,
"token_address": self.token_address,
Expand Down
4 changes: 2 additions & 2 deletions app/model/db/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ class Notification(Base):

if engine.name == "mysql":
# NOTE:MySQLではDatetime型で小数秒桁を指定しない場合、整数秒しか保存されない
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
MySQLDATETIME(fsp=6), default=naive_utcnow, index=True
)
else:
created: Mapped[datetime | None] = mapped_column(
created: Mapped[datetime] = mapped_column(
DateTime, default=naive_utcnow, index=True
)

Expand Down
215 changes: 215 additions & 0 deletions migrations/versions/4df7e2c1b8a3_v26_6_0_feature_1792.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
"""v26_6_0_feature_1792

Revision ID: 4df7e2c1b8a3
Revises: d7de2d20be69
Create Date: 2026-04-02 20:04:29.343543

"""

from datetime import UTC, datetime

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql


from app.database import engine, get_db_schema

# revision identifiers, used by Alembic.
revision = "4df7e2c1b8a3"
down_revision = "d7de2d20be69"
branch_labels = None
depends_on = None


AUDIT_TABLE_NAMES = [
"account_tag",
"bond_token",
"chat_webhook",
"company",
"consume_coupon",
"coupon_token",
"executable_contract",
"idx_position_bond_block_number",
"idx_position_coupon_block_number",
"idx_position_membership_block_number",
"idx_position_share_block_number",
"idx_token_list_block_number",
"idx_transfer_approval_block_number",
"idx_transfer_block_number",
"listing",
"lock",
"locked_position",
"mail",
"membership_token",
"node",
"notification",
"notification_attribute_value",
"notification_block_number",
"position",
"public_account_list",
"share_token",
"token_holder",
"token_holders_list",
"token_list",
"token_list_register",
"transfer",
"transfer_approval",
"unlock",
]


def _get_audit_datetime_type():
if engine.name == "mysql":
return mysql.DATETIME(fsp=6)
else:
return sa.DateTime()


def _get_audit_table(table_name: str):
datetime_type = _get_audit_datetime_type()
return sa.Table(
table_name,
sa.MetaData(),
sa.Column("created", datetime_type),
sa.Column("modified", datetime_type),
schema=get_db_schema(),
)


def _backfill_audit_columns(table_name: str, current_dt: datetime):
table = _get_audit_table(table_name)

op.get_bind().execute(
table.update().where(table.c.created.is_(None)).values(created=current_dt)
)
op.get_bind().execute(
table.update().where(table.c.modified.is_(None)).values(modified=current_dt)
)


def _alter_audit_columns(table_name: str, nullable: bool):
datetime_type = _get_audit_datetime_type()
op.alter_column(
table_name,
"created",
existing_type=datetime_type,
nullable=nullable,
schema=get_db_schema(),
)
op.alter_column(
table_name,
"modified",
existing_type=datetime_type,
nullable=nullable,
schema=get_db_schema(),
)


def upgrade():
current_dt = datetime.now(UTC).replace(tzinfo=None)
datetime_type = _get_audit_datetime_type()

############################
# Migration for listing
############################
listing = sa.Table(
"listing",
sa.MetaData(),
sa.Column("token_address", sa.String(length=256)),
sa.Column("is_public", sa.Boolean()),
sa.Column("owner_address", sa.String(length=256)),
sa.Column("created", datetime_type),
sa.Column("modified", datetime_type),
schema=get_db_schema(),
)
executable_contract = sa.Table(
"executable_contract",
sa.MetaData(),
sa.Column("contract_address", sa.String(length=256)),
schema=get_db_schema(),
)
listing_invalid_condition = sa.or_(
listing.c.token_address.is_(None),
listing.c.owner_address.is_(None),
)

op.get_bind().execute(
listing.update().where(listing.c.is_public.is_(None)).values(is_public=True)
)
op.get_bind().execute(listing.delete().where(listing_invalid_condition))
op.get_bind().execute(
executable_contract.delete().where(
sa.not_(
sa.exists(
sa.select(1)
.select_from(listing)
.where(
listing.c.token_address
== executable_contract.c.contract_address
)
)
)
)
)

############################
# Migration for created/modified columns
############################
for table_name in AUDIT_TABLE_NAMES:
_backfill_audit_columns(table_name, current_dt)

############################
# Migration for listing not null columns
############################
op.alter_column(
"listing",
"token_address",
existing_type=sa.String(length=256),
nullable=False,
schema=get_db_schema(),
)
op.alter_column(
"listing",
"is_public",
existing_type=sa.Boolean(),
nullable=False,
schema=get_db_schema(),
)
op.alter_column(
"listing",
"owner_address",
existing_type=sa.String(length=256),
nullable=False,
schema=get_db_schema(),
)

for table_name in AUDIT_TABLE_NAMES:
_alter_audit_columns(table_name, nullable=False)


def downgrade():
op.alter_column(
"listing",
"token_address",
existing_type=sa.String(length=256),
nullable=True,
schema=get_db_schema(),
)
op.alter_column(
"listing",
"is_public",
existing_type=sa.Boolean(),
nullable=True,
schema=get_db_schema(),
)
op.alter_column(
"listing",
"owner_address",
existing_type=sa.String(length=256),
nullable=True,
schema=get_db_schema(),
)

for table_name in AUDIT_TABLE_NAMES:
_alter_audit_columns(table_name, nullable=True)
1 change: 1 addition & 0 deletions tests/app/company_info_ListAllCompanies_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def list_token(
listed_token.is_public = is_public
listed_token.max_holding_quantity = 1
listed_token.max_sell_amount = 1000
listed_token.owner_address = "0x0000000000000000000000000000000000000000"
session.add(listed_token)

@staticmethod
Expand Down
1 change: 1 addition & 0 deletions tests/app/eth_SendRawTransactionNowait_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def listing_token(session: Session, token_address: str) -> None:
listing.is_public = True
listing.max_holding_quantity = 1
listing.max_sell_amount = 1000
listing.owner_address = "0x0000000000000000000000000000000000000000"
session.add(listing)


Expand Down
1 change: 1 addition & 0 deletions tests/app/eth_SendRawTransaction_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def listing_token(session: Session, token_address: str) -> None:
listing.is_public = True
listing.max_holding_quantity = 1
listing.max_sell_amount = 1000
listing.owner_address = "0x0000000000000000000000000000000000000000"
session.add(listing)


Expand Down
1 change: 1 addition & 0 deletions tests/app/eth_WaitForTransactionReceipt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def listing_token(session: Session, token_address: str) -> None:
listing.is_public = True
listing.max_holding_quantity = 1
listing.max_sell_amount = 1000
listing.owner_address = "0x0000000000000000000000000000000000000000"
session.add(listing)


Expand Down
Loading
Loading