Skip to content

Commit 0796fde

Browse files
perf: Terminology module
1 parent becde51 commit 0796fde

File tree

13 files changed

+355
-34
lines changed

13 files changed

+355
-34
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""003_Upgrade_Term_Table
2+
3+
Revision ID: dd9d72cfd3c4
4+
Revises: 1c8bcc7e25c8
5+
Create Date: 2025-04-27 14:56:29.185812
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlmodel.sql.sqltypes
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = 'dd9d72cfd3c4'
15+
down_revision = '1c8bcc7e25c8'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.alter_column('terms', 'id',
23+
existing_type=sa.INTEGER(),
24+
type_=sa.BigInteger(),
25+
existing_nullable=False)
26+
# ### end Alembic commands ###
27+
28+
29+
def downgrade():
30+
# ### commands auto generated by Alembic - please adjust! ###
31+
op.alter_column('terms', 'id',
32+
existing_type=sa.BigInteger(),
33+
type_=sa.INTEGER(),
34+
existing_nullable=False)
35+
# ### end Alembic commands ###

backend/apps/settings/api/terminology.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
from fastapi import APIRouter
1+
from fastapi import APIRouter
2+
from sqlmodel import select
23
from apps.settings.models.setting_models import term_model
4+
from apps.settings.schemas.setting_schemas import term_schema_creator
35
from common.core.deps import SessionDep
46
from common.core.pagination import Paginator
57
from common.core.schemas import PaginatedResponse, PaginationParams
@@ -18,4 +20,49 @@ async def pager(
1820
return await paginator.get_paginated_response(
1921
model=term_model,
2022
pagination=pagination,
21-
**filters)
23+
**filters)
24+
25+
26+
@router.get("/{id}", response_model=term_model)
27+
async def get_terminology_by_id(
28+
session: SessionDep,
29+
id: int
30+
):
31+
term = session.get(term_model, id)
32+
return term
33+
34+
@router.post("", response_model=term_model)
35+
async def add_terminology(
36+
session: SessionDep,
37+
creator: term_schema_creator
38+
):
39+
terminology = term_model(**creator.model_dump())
40+
session.add(terminology)
41+
session.commit()
42+
return terminology
43+
44+
@router.put("", response_model=term_model)
45+
async def update_terminology(
46+
session: SessionDep,
47+
terminology: term_model
48+
):
49+
terminology.id = int(terminology.id)
50+
term = session.exec(select(term_model).where(term_model.id == terminology.id)).first()
51+
update_data = terminology.model_dump(exclude_unset=True)
52+
for field, value in update_data.items():
53+
setattr(term, field, value)
54+
session.add(term)
55+
session.commit()
56+
return terminology
57+
58+
@router.delete("/{id}", response_model=term_model)
59+
async def delete_terminology(
60+
session: SessionDep,
61+
id: int
62+
):
63+
term = session.exec(select(term_model).where(term_model.id == id)).first()
64+
session.delete(term)
65+
session.commit()
66+
return {
67+
"message": f"Terminology with ID {id} deleted successfully."
68+
}

backend/apps/settings/models/setting_models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from sqlmodel import Field, SQLModel
22

3+
from common.core.models import SnowflakeBase
34

4-
class term_model(SQLModel, table=True):
5-
__tablename__ = "terms"
65

7-
id: int = Field(primary_key=True, index=True)
6+
class term_model(SnowflakeBase, table=True):
7+
__tablename__ = "terms"
88
term: str = Field(max_length=255)
99
definition: str = Field(max_length=255)
1010
domain: str = Field(max_length=255)

backend/apps/settings/schemas/setting_schemas.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from pydantic import BaseModel
22

3-
class term_schema(BaseModel):
4-
id: int
3+
class term_schema_creator(BaseModel):
54
term: str
65
definition: str
76
domain: str

backend/common/core/models.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from pydantic import field_validator
2+
from sqlmodel import BigInteger, SQLModel, Field
3+
from typing import Optional
4+
5+
from common.utils.snowflake import snowflake
6+
7+
class SnowflakeBase(SQLModel):
8+
id: Optional[int] = Field(
9+
default_factory=snowflake.generate_id,
10+
primary_key=True,
11+
sa_type=BigInteger(),
12+
index=True,
13+
nullable=False
14+
)
15+
16+
@field_validator("id", mode="before")
17+
def validate_id(cls, v):
18+
if isinstance(v, str):
19+
if not v:
20+
return None
21+
try:
22+
return int(v)
23+
except ValueError:
24+
raise ValueError("Invalid bigint string")
25+
elif isinstance(v, int):
26+
return v
27+
raise TypeError("BigInt must be int or string")
28+
29+
30+
class Config:
31+
json_encoders = {
32+
int: lambda v: str(v) if v > 2**53-1 else v
33+
}

backend/common/utils/snowflake.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import time
2+
import threading
3+
class SnowflakeGenerator:
4+
def __init__(self, worker_id=0, datacenter_id=0):
5+
self.worker_id = worker_id
6+
self.datacenter_id = datacenter_id
7+
self.sequence = 0
8+
self.last_timestamp = -1
9+
self.lock = threading.Lock()
10+
11+
self.worker_id_bits = 5
12+
self.datacenter_id_bits = 5
13+
self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
14+
self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
15+
self.sequence_bits = 12
16+
17+
self.worker_id_shift = self.sequence_bits
18+
self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
19+
self.timestamp_left_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
20+
self.sequence_mask = -1 ^ (-1 << self.sequence_bits)
21+
22+
if self.worker_id > self.max_worker_id or self.worker_id < 0:
23+
raise ValueError(f"worker ID can't be greater than {self.max_worker_id} or less than 0")
24+
if self.datacenter_id > self.max_datacenter_id or self.datacenter_id < 0:
25+
raise ValueError(f"datacenter ID can't be greater than {self.max_datacenter_id} or less than 0")
26+
27+
def _current_time(self):
28+
return int(time.time() * 1000)
29+
30+
def _wait_next_millis(self, last_timestamp):
31+
timestamp = self._current_time()
32+
while timestamp <= last_timestamp:
33+
timestamp = self._current_time()
34+
return timestamp
35+
36+
def generate_id(self):
37+
with self.lock:
38+
timestamp = self._current_time()
39+
40+
if timestamp < self.last_timestamp:
41+
raise ValueError("Clock moved backwards. Refusing to generate ID")
42+
43+
if timestamp == self.last_timestamp:
44+
self.sequence = (self.sequence + 1) & self.sequence_mask
45+
if self.sequence == 0:
46+
timestamp = self._wait_next_millis(self.last_timestamp)
47+
else:
48+
self.sequence = 0
49+
50+
self.last_timestamp = timestamp
51+
52+
return ((timestamp << self.timestamp_left_shift) |
53+
(self.datacenter_id << self.datacenter_id_shift) |
54+
(self.worker_id << self.worker_id_shift) |
55+
self.sequence)
56+
57+
snowflake = SnowflakeGenerator(worker_id=1)

backend/scripts/alembic/exec.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
alembic upgrade head

backend/scripts/prestart.sh

100644100755
File mode changed.

backend/scripts/tests-start.sh

100644100755
File mode changed.

frontend/auto-imports.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
export {}
88
declare global {
99
const ElMessage: typeof import('element-plus/es')['ElMessage']
10+
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
1011
}

0 commit comments

Comments
 (0)