Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
54d1c97
renamed var database & cleaned imports and README
MaxNumerique Sep 15, 2025
827284c
sql alchemy replacing flask sql alchemy
MaxNumerique Sep 18, 2025
167d5de
pyproject version 0.0.0
MaxNumerique Sep 19, 2025
b66eb63
fix(database): using SQL Alchemy instead of Flask-SQLAlchemy
MaxNumerique Sep 19, 2025
9ee333b
test to insure that we do have the required paramaters to add dataa …
MaxNumerique Sep 30, 2025
d1d541d
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 1, 2025
fdd2dd7
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 1, 2025
90a7d36
Apply prepare changes
MaxNumerique Oct 1, 2025
920cdfa
mypy type
MaxNumerique Oct 1, 2025
631f9d8
Session type
MaxNumerique Oct 1, 2025
72c2f15
update requirements.in
MaxNumerique Oct 1, 2025
f8c5bd1
Apply prepare changes
MaxNumerique Oct 1, 2025
d9f9d7a
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 2, 2025
d02aa19
Apply prepare changes
MaxNumerique Oct 2, 2025
a16c26d
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 3, 2025
77257f1
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 3, 2025
8c4a3ec
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 3, 2025
4aaca60
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 6, 2025
89a9350
Apply prepare changes
MaxNumerique Oct 6, 2025
f823e41
added logs + get_session as session
MaxNumerique Oct 7, 2025
0cbdf4b
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 9, 2025
d1047b4
Apply prepare changes
MaxNumerique Oct 9, 2025
8cd055c
mypy
MaxNumerique Oct 9, 2025
52405f5
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 9, 2025
f535b04
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 9, 2025
c801bdb
Apply prepare changes
MaxNumerique Oct 9, 2025
3cba6eb
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 13, 2025
834ccae
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 13, 2025
dee349c
Apply prepare changes
MaxNumerique Oct 13, 2025
15a768e
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique Oct 14, 2025
05e206b
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 14, 2025
844d53f
Apply prepare changes
MaxNumerique Oct 14, 2025
f44c1aa
adding bool for init_database function to know if tables have already…
MaxNumerique Oct 14, 2025
c32cf09
Merge branch 'fix/database' of https://github.com/Geode-solutions/Ope…
MaxNumerique Oct 14, 2025
f9cc61a
typed get()
MaxNumerique Oct 14, 2025
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1 align="center">OpenGeodeWeb-Back<sup><i>by Geode-solutions</i></sup></h1>
<h1 align="center">OpenGeodeWeb-Microservice<sup><i>by Geode-solutions</i></sup></h1>
<h3 align="center">OpenSource Python framework based on OpenGeode</h3>

<p align="center">
Expand Down
3 changes: 1 addition & 2 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
sqlalchemy==2.0.43
flask-sqlalchemy==3.1.1
SQLAlchemy==2.0.43
fastjsonschema==2.21.1
25 changes: 2 additions & 23 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,12 @@
#
# pip-compile --output-file=./requirements.txt ./requirements.in
#
blinker>=1
# via flask
click>=8
# via flask
fastjsonschema==2.21.1
# via -r requirements.in
flask>=3
# via flask-sqlalchemy
flask-sqlalchemy==3.1.1
# via -r requirements.in
greenlet>=3
# via sqlalchemy
itsdangerous>=2
# via flask
jinja2>=3
# via flask
markupsafe>=3
# via
# flask
# jinja2
# werkzeug
sqlalchemy==2.0.43
# via
# -r requirements.in
# flask-sqlalchemy
sqlalchemy>=2
# via -r requirements.in
typing-extensions>=4
# via sqlalchemy
werkzeug>=3
# via flask

2 changes: 0 additions & 2 deletions src/opengeodeweb_microservice/database/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase


Expand Down
54 changes: 31 additions & 23 deletions src/opengeodeweb_microservice/database/connection.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
"""Database connection management"""

from typing import Optional
from sqlalchemy.orm import scoped_session
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy.session import Session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session, Session
from .base import Base

DATABASE_FILENAME = "project.db"
db: Optional[SQLAlchemy] = None


def init_database(app: Flask, db_filename: str = DATABASE_FILENAME) -> SQLAlchemy:
global db
if db is None:
db = SQLAlchemy(model_class=Base)
db.init_app(app)
with app.app_context():
db.create_all()
return db


def get_database() -> Optional[SQLAlchemy]:
return db


def get_session() -> Optional[scoped_session[Session]]:
return db.session if db else None
engine = None
session_factory = None
scoped_session_registry = None


def init_database(db_path: str = DATABASE_FILENAME, create_tables: bool = True) -> None:
global engine, session_factory, scoped_session_registry

if engine is None:
engine = create_engine(
f"sqlite:///{db_path}",
connect_args={"check_same_thread": False},
)
print(f"Database engine created for {db_path}", flush=True)
session_factory = sessionmaker(bind=engine)
scoped_session_registry = scoped_session(session_factory)
if create_tables:
Base.metadata.create_all(engine)
print(f"Database tables created for {db_path}", flush=True)
else:
print(f"Database connected (tables not created) for {db_path}", flush=True)
else:
print(f"Database engine already exists for {db_path}, reusing", flush=True)


def get_session() -> Session:
if scoped_session_registry is None:
raise RuntimeError()
return scoped_session_registry()
18 changes: 8 additions & 10 deletions src/opengeodeweb_microservice/database/data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlalchemy import String, JSON
from sqlalchemy import String, JSON, select
from sqlalchemy.orm import Mapped, mapped_column
from .connection import get_session
from .base import Base
Expand All @@ -25,8 +25,8 @@ def create(
input_file: str | None = None,
additional_files: list[str] | None = None,
) -> "Data":
input_file = input_file if input_file is not None else ""
additional_files = additional_files if additional_files is not None else []
input_file = input_file or ""
additional_files = additional_files or []

data_entry = Data(
geode_object=geode_object,
Expand All @@ -38,15 +38,13 @@ def create(
)

session = get_session()
if session:
session.add(data_entry)
session.flush()
session.commit()
session.add(data_entry)
session.flush()
session.commit()
return data_entry

@staticmethod
def get(data_id: str) -> "Data | None":
session = get_session()
if session:
return session.get(Data, data_id)
return None
data_query = select(Data).where(Data.id == data_id)
return session.scalars(data_query).first()
47 changes: 16 additions & 31 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,40 @@
import os
import pytest
from flask import Flask
from src.opengeodeweb_microservice.database.connection import init_database, get_session
from src.opengeodeweb_microservice.database.data import Data


@pytest.fixture(scope="session")
def app():
app = Flask(__name__)
app.config.update(
{
"TESTING": True,
"SQLALCHEMY_DATABASE_URI": f"sqlite:///{os.path.join(os.path.dirname(__file__), 'test_project.db')}",
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
}
)
with app.app_context():
init_database(app, "test_project.db")
yield app
_cleanup_database()
DB_PATH = os.path.join(os.path.dirname(__file__), "test_project.db")


def _cleanup_database():
@pytest.fixture(scope="session", autouse=True)
def setup_database():
init_database(DB_PATH)
yield
_cleanup_database(DB_PATH)


def _cleanup_database(db_path: str):
try:
session = get_session()
if session:
session.close()
session.close()
except Exception:
pass
db_path = os.path.join(os.path.dirname(__file__), "test_project.db")

if os.path.exists(db_path):
try:
os.remove(db_path)
except PermissionError:
pass


@pytest.fixture
def app_context(app):
with app.app_context():
yield


@pytest.fixture
def clean_database(app_context):
session = get_session()
if session:
@pytest.fixture(autouse=True)
def clean_database():
with get_session() as session:
session = get_session()
session.query(Data).delete()
session.commit()
yield
if session:
yield
try:
session.rollback()
except Exception:
Expand Down
9 changes: 0 additions & 9 deletions tests/test_connection.py

This file was deleted.

25 changes: 17 additions & 8 deletions tests/test_database.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
from src.opengeodeweb_microservice.database.connection import get_session
from src.opengeodeweb_microservice.database.data import Data


def test_data_crud_operations():
data = Data.create(geode_object="test_object", input_file="test.txt")
def test_data_crud_operations(clean_database):
data = Data.create(
geode_object="test_object", input_file="test.txt", additional_files=[]
)
print("id", data.id, flush=True)
assert data.id is not None
session = get_session()
session.commit()
assert isinstance(data.id, str)

retrieved = Data.get(data.id)
assert retrieved is not None
assert isinstance(retrieved, Data)
assert retrieved.geode_object == "test_object"
assert retrieved.input_file == "test.txt"
assert retrieved.id == data.id
non_existent = Data.get("fake_id")
assert non_existent is None


def test_data_with_additional_files():
def test_data_with_additional_files(clean_database):
files = ["file1.txt", "file2.txt"]
data = Data.create(geode_object="test_files", additional_files=files)
session = get_session()
session.commit()
assert data.id is not None
assert isinstance(data.id, str)

retrieved = Data.get(data.id)
assert retrieved is not None
assert isinstance(retrieved, Data)
assert retrieved.additional_files == files
assert retrieved.geode_object == "test_files"