init server

This commit is contained in:
Robin COuret
2026-02-10 17:36:30 +01:00
parent c9cb257afc
commit 83b5da1716
32 changed files with 238 additions and 0 deletions

1
server/.env.example Normal file
View File

@@ -0,0 +1 @@
DATABASE_URI="sqlite:///database.db"

3
server/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.venv/
.env
database.db

14
server/README.md Normal file
View File

@@ -0,0 +1,14 @@
# Run
```
fastapi dev main.py
```
# Best Practice
## Simple Boilerplate
https://github.com/anthonycepeda/fastapi-sqlmodel/tree/main
## Global Boilerplate
https://github.com/zhanymkanov/fastapi-best-practices?tab=readme-ov-file#excessively-use-pydantic
## SQLEModel-boilerplate
https://github.com/benavlabs/SQLModel-boilerplate/tree/main

3
server/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
fastapi==0.128.6
sqlmodel==0.0.32
python-dotenv==1.2.1

0
server/src/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

27
server/src/app.py Normal file
View File

@@ -0,0 +1,27 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI
from src.database import create_db_and_tables
#TODO : best practice to manage models import
from src.questions.models import Question
from src.knowledges.models import Knowledge
from src.metrics.models import Metric
#Test
from src.questions.controller import create_question, read_question
from src.knowledges.controller import create_knowledge, read_knowledges, delete_knowledge
#TODO : alternative @app.on_event("startup") ?
@asynccontextmanager
async def lifespan(app: FastAPI):
#startup
create_db_and_tables()
delete_knowledge()
yield
#shutdown
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
return {"message": "Hello World"}

17
server/src/database.py Normal file
View File

@@ -0,0 +1,17 @@
from dotenv import load_dotenv
import os
#import secrets
from sqlmodel import Session, SQLModel, create_engine
load_dotenv()
database_uri=os.environ.get("DATABASE_URI")
connect_args = {"check_same_thread": False}
engine = create_engine(database_uri, echo=True, connect_args=connect_args)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
def get_session():
with Session(engine) as session:
yield session

Binary file not shown.

View File

@@ -0,0 +1,19 @@
from src.knowledges.models import Knowledge
from src.knowledges.crud import create_knowledge as create_knowledge_model, read_knowledges as read_knowledges_model, read_knowledge as read_knowledge_model, update_knowledge as update_knowledge_model, delete_knowledge as delete_knowledge_model
def create_knowledge():
connaissance = Knowledge(content="La connaissance n'est pas.", uri="https://perdu.fr")
create_knowledge_model(connaissance)
return read_knowledges()[-1]
def read_knowledges():
return read_knowledges_model()
def read_knowledge(knowledge_id):
return read_knowledge_model(knowledge_id)
def update_knowledge():
return update_knowledge_model(2, "faculté mentale produisant une assimilation par l'esprit d'un contenu objectif préalablement traduit en signes et en idées ;", "https://fr.wikipedia.org/wiki/Connaissance#D%C3%A9finition")
def delete_knowledge():
return delete_knowledge_model(7)

View File

@@ -0,0 +1,42 @@
from sqlmodel import Session, select
from src.knowledges.models import Knowledge
from src.database import engine
def create_knowledge(knowledge: Knowledge):
with Session(engine) as session:
session.add(knowledge)
session.commit()
def read_knowledges():
with Session(engine) as session:
statement = select(Knowledge)
results = session.exec(statement)
knowledges = results.all()
return knowledges
def read_knowledge(knowledge_id: int):
with Session(engine) as session:
#statement = select(Knowledge).where(Knowledge.id == knowledge_id)
#results = session.exec(statement)
#knowledge = results.first()
knowledge = session.get(Knowledge, knowledge_id)
return knowledge
#TODO adapt logic with args
def update_knowledge(knowledge_id: int, content: str, uri: str):
with Session(engine) as session:
knowledge = session.get(Knowledge, knowledge_id)
knowledge.content = content if content else knowledge.content
knowledge.uri = uri if uri else knowledge.uri
session.add(knowledge)
session.commit()
session.refresh(knowledge)
def delete_knowledge(knowledge_id: int):
with Session(engine) as session:
knowledge = session.get(Knowledge, knowledge_id)
session.delete(knowledge)
session.commit()
#TODO : delete join questions

View File

@@ -0,0 +1,9 @@
from sqlmodel import Field, SQLModel, Relationship
#TODO : add pydantic validation
class Knowledge(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
content: str = Field(index=True)
uri: str = Field(index=True)
questions: list["Question"] = Relationship(back_populates="knowledge", cascade_delete=True) # type: ignore

View File

Binary file not shown.

View File

@@ -0,0 +1,29 @@
from sqlmodel import Session, select
from src.metrics.models import Metric
from src.questions.models import Question
from src.database import engine
def create_metric(Metric: Metric):
with Session(engine) as session:
session.add(Metric)
session.commit()
def read_metrics(question):
with Session(engine) as session:
statement = select(Metric).where(Metric.question_id == question.id)
results = session.exec(statement)
metrics = results.all()
return metrics
def read_metric(metric_id: int):
with Session(engine) as session:
metric = session.get(Metric, metric_id)
return metric
def delete_metric(metric_id: int):
with Session(engine) as session:
metric = session.get(Metric, metric_id)
session.delete(metric)
session.commit()

View File

@@ -0,0 +1,7 @@
from sqlmodel import Field, SQLModel
#TODO : add pydantic validation
class Metric(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
question_id: int | None = Field(default=None, foreign_key="question.id", ondelete="CASCADE")
need_index: int

View File

Binary file not shown.

View File

@@ -0,0 +1,13 @@
from src.questions.models import Question
from src.questions.crud import create_question as create_question_model, read_questions as read_questions_model, read_question as read_question_model
from src.knowledges.models import Knowledge
def create_question(knowledge: Knowledge):
question = Question(knowledge = knowledge, question = "Quel est le sens du mot connaissance ?")
create_question_model(question)
def read_questions(knowledge):
return read_questions_model(knowledge)
def read_question(question_id):
return read_question_model(question_id)

View File

@@ -0,0 +1,42 @@
from sqlmodel import Session, select
from src.questions.models import Question
from src.knowledges.models import Knowledge
from src.database import engine
def create_question(Question: Question):
with Session(engine) as session:
session.add(Question)
session.commit()
def read_questions(knowledge):
with Session(engine) as session:
statement = select(Question).where(Question.knowledge_id == knowledge.id)
results = session.exec(statement)
questions = results.all()
return questions
def read_question(question_id: int):
with Session(engine) as session:
question = session.get(Question, question_id)
return question
# #TODO adapt logic with args
# def update_question(question_id: int, content: str, uri: str):
# with Session(engine) as session:
# question = session.get(Question, question_id)
# question.content = content if content else question.content
# question.uri = uri if uri else question.uri
# session.add(question)
# session.commit()
# session.refresh(question)
#TODO : test
def delete_question(question_id: int):
with Session(engine) as session:
question = session.get(Question, question_id)
session.delete(question)
session.commit()

View File

@@ -0,0 +1,12 @@
from sqlmodel import Field, SQLModel, Relationship
from src.knowledges.models import Knowledge
#TODO : add pydantic validation
class Question(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
question:str
knowledge_id: int | None = Field(default=None, foreign_key="knowledge.id", ondelete="CASCADE")
knowledge: Knowledge | None = Relationship(back_populates="questions")
metrics: list["Metrics"] = Relationship(back_populates="question", cascade_delete=True) # type: ignore

View File

View File

View File