156 lines
7.2 KiB
Python
156 lines
7.2 KiB
Python
import functools
|
|
import json
|
|
from flask import Blueprint, jsonify
|
|
import jsonpickle
|
|
from sqlalchemy import create_engine, select
|
|
from sqlalchemy.orm import Session
|
|
from .database import get_database, get_jiten_db
|
|
|
|
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
|
|
|
@blueprint.route("/")
|
|
def logout():
|
|
# db = get_database()
|
|
return {
|
|
"endpoints": ["id", "kanji", "kotoba (not implemented)"]
|
|
}
|
|
|
|
import random
|
|
import sqlalchemy
|
|
from typing import List, Optional, Iterable
|
|
from sqlalchemy import URL, ForeignKey, String, Boolean, Text, Integer
|
|
from sqlalchemy.types import CHAR
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship
|
|
|
|
class Base(DeclarativeBase):
|
|
pass
|
|
|
|
# class Reading(Base):
|
|
# __tablename__ = "reading"
|
|
# id: Mapped[int] = mapped_column(primary_key=True)
|
|
# reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
# kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
# kanji: Mapped["Kanji"] = relationship(back_populates="readings")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Goon(Base):
|
|
__tablename__ = "goon"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="goon")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Kanon(Base):
|
|
__tablename__ = "kanon"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="kanon")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Kanyoon(Base):
|
|
__tablename__ = "kanyoon"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="kanyoon")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Soon(Base):
|
|
__tablename__ = "soon"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="soon")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Toon(Base):
|
|
__tablename__ = "toon"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="toon")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Kun(Base):
|
|
__tablename__ = "kun"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="kun")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class UnclassifiedOn(Base):
|
|
__tablename__ = "unclassified_on"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
reading: Mapped[str] = mapped_column(String(length=10)) # Assume no reading can be over 10 characters long, a sound assumption overall
|
|
kanji_id: Mapped[int] = mapped_column(ForeignKey("kanji.id"))
|
|
kanji: Mapped["Kanji"] = relationship(back_populates="unclassified_on")
|
|
# reading_type: Mapped[str] = mapped_column(CHAR(1), primary_key=True) # One of: 音漢呉慣唐宋訓
|
|
|
|
class Kanji(Base):
|
|
__tablename__ = "kanji"
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
character: Mapped[str] = mapped_column(CHAR(length=1), unique=True)
|
|
level: Mapped[str] = mapped_column(String(length=2)) # Either 1, 2, etc. or 準2 etc.
|
|
is_kokuji: Mapped[bool] = mapped_column(Boolean())
|
|
meanings: Mapped[str] = mapped_column(Text()) # FIXME: make this a list
|
|
# readings: Mapped[List[Reading]] = relationship(back_populates="kanji")
|
|
goon: Mapped[List[Goon]] = relationship(back_populates="kanji")
|
|
kanon: Mapped[List[Kanon]] = relationship(back_populates="kanji")
|
|
kanyoon: Mapped[List[Kanyoon]] = relationship(back_populates="kanji")
|
|
toon: Mapped[List[Toon]] = relationship(back_populates="kanji")
|
|
soon: Mapped[List[Soon]] = relationship(back_populates="kanji")
|
|
kun: Mapped[List[Kun]] = relationship(back_populates="kanji")
|
|
unclassified_on: Mapped[List[UnclassifiedOn]] = relationship(back_populates="kanji")
|
|
radical: Mapped[str] = mapped_column(CHAR(length=1)) # FIXME: normalize?
|
|
stroke_count: Mapped[int] = mapped_column(Integer())
|
|
radical_added_stroke_count: Mapped[int] = mapped_column(Integer()) # FIXME: normalize? this may theoretically be calculated based on the radical stroke count, but I need to validate that this always works
|
|
glyph_origin: Mapped[str] = mapped_column(Text()) # FIXME: make this a list of possible explanations, possibly, but unsure
|
|
# diagram: Mapped[str] = ... could be calculated from the kanji name
|
|
|
|
def to_json(self):
|
|
out = {}
|
|
for attr, value in self.__dict__.items():
|
|
if not isinstance(value, (bool, int, str)):
|
|
continue
|
|
else:
|
|
out[attr] = value
|
|
|
|
for attr in ("goon", "kanon", "kanyoon", "toon", "soon", "kun", "unclassified_on"):
|
|
out[attr] = [reading_obj.reading for reading_obj in getattr(self, attr)]
|
|
|
|
return out
|
|
|
|
def render(self):
|
|
return self.character
|
|
|
|
@blueprint.route("/id/<int:kanji_id>")
|
|
def kanji_by_id(kanji_id: int):
|
|
session = get_jiten_db()
|
|
query = select(Kanji).where(Kanji.id == kanji_id)
|
|
item = session.execute(query).first()
|
|
if item is None:
|
|
return "Invalid ID", 404
|
|
|
|
kanji = item[0]
|
|
return kanji.to_json()
|
|
|
|
def get_kanji_by_character(kanji: str) -> Kanji:
|
|
session = get_jiten_db()
|
|
query = select(Kanji).where(Kanji.character == kanji)
|
|
item = session.execute(query).first()
|
|
if item is None:
|
|
return "Invalid kanji", 404
|
|
|
|
kanji_obj: Kanji = item[0]
|
|
return kanji_obj
|
|
|
|
@blueprint.route("/kanji/<kanji>")
|
|
def kanji_by_character(kanji: str):
|
|
kanji_obj = get_kanji_by_character(kanji)
|
|
return kanji_obj.to_json()
|
|
|
|
def get_kanji_generic():
|
|
pass |