Skip to content

Commit b44a5c8

Browse files
authored
Merge pull request #9 from Geode-solutions/fix/database
Fix/database
2 parents 2ee394e + f9cc61a commit b44a5c8

File tree

9 files changed

+76
-109
lines changed

9 files changed

+76
-109
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1 align="center">OpenGeodeWeb-Back<sup><i>by Geode-solutions</i></sup></h1>
1+
<h1 align="center">OpenGeodeWeb-Microservice<sup><i>by Geode-solutions</i></sup></h1>
22
<h3 align="center">OpenSource Python framework based on OpenGeode</h3>
33

44
<p align="center">

requirements.in

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
sqlalchemy==2.0.43
2-
flask-sqlalchemy==3.1.1
1+
SQLAlchemy==2.0.43
32
fastjsonschema==2.21.1

requirements.txt

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,12 @@
44
#
55
# pip-compile --output-file=./requirements.txt ./requirements.in
66
#
7-
blinker>=1
8-
# via flask
9-
click>=8
10-
# via flask
117
fastjsonschema==2.21.1
128
# via -r requirements.in
13-
flask>=3
14-
# via flask-sqlalchemy
15-
flask-sqlalchemy==3.1.1
16-
# via -r requirements.in
179
greenlet>=3
1810
# via sqlalchemy
19-
itsdangerous>=2
20-
# via flask
21-
jinja2>=3
22-
# via flask
23-
markupsafe>=3
24-
# via
25-
# flask
26-
# jinja2
27-
# werkzeug
28-
sqlalchemy==2.0.43
29-
# via
30-
# -r requirements.in
31-
# flask-sqlalchemy
11+
sqlalchemy>=2
12+
# via -r requirements.in
3213
typing-extensions>=4
3314
# via sqlalchemy
34-
werkzeug>=3
35-
# via flask
3615

src/opengeodeweb_microservice/database/base.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from flask import Flask
2-
from flask_sqlalchemy import SQLAlchemy
31
from sqlalchemy.orm import DeclarativeBase
42

53

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
"""Database connection management"""
22

3-
from typing import Optional
4-
from sqlalchemy.orm import scoped_session
5-
from flask import Flask
6-
from flask_sqlalchemy import SQLAlchemy
7-
from flask_sqlalchemy.session import Session
3+
from sqlalchemy import create_engine
4+
from sqlalchemy.orm import sessionmaker, scoped_session, Session
85
from .base import Base
96

107
DATABASE_FILENAME = "project.db"
11-
db: Optional[SQLAlchemy] = None
128

13-
14-
def init_database(app: Flask, db_filename: str = DATABASE_FILENAME) -> SQLAlchemy:
15-
global db
16-
if db is None:
17-
db = SQLAlchemy(model_class=Base)
18-
db.init_app(app)
19-
with app.app_context():
20-
db.create_all()
21-
return db
22-
23-
24-
def get_database() -> Optional[SQLAlchemy]:
25-
return db
26-
27-
28-
def get_session() -> Optional[scoped_session[Session]]:
29-
return db.session if db else None
9+
engine = None
10+
session_factory = None
11+
scoped_session_registry = None
12+
13+
14+
def init_database(db_path: str = DATABASE_FILENAME, create_tables: bool = True) -> None:
15+
global engine, session_factory, scoped_session_registry
16+
17+
if engine is None:
18+
engine = create_engine(
19+
f"sqlite:///{db_path}",
20+
connect_args={"check_same_thread": False},
21+
)
22+
print(f"Database engine created for {db_path}", flush=True)
23+
session_factory = sessionmaker(bind=engine)
24+
scoped_session_registry = scoped_session(session_factory)
25+
if create_tables:
26+
Base.metadata.create_all(engine)
27+
print(f"Database tables created for {db_path}", flush=True)
28+
else:
29+
print(f"Database connected (tables not created) for {db_path}", flush=True)
30+
else:
31+
print(f"Database engine already exists for {db_path}, reusing", flush=True)
32+
33+
34+
def get_session() -> Session:
35+
if scoped_session_registry is None:
36+
raise RuntimeError()
37+
return scoped_session_registry()

src/opengeodeweb_microservice/database/data.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from sqlalchemy import String, JSON
1+
from sqlalchemy import String, JSON, select
22
from sqlalchemy.orm import Mapped, mapped_column
33
from .connection import get_session
44
from .base import Base
@@ -25,8 +25,8 @@ def create(
2525
input_file: str | None = None,
2626
additional_files: list[str] | None = None,
2727
) -> "Data":
28-
input_file = input_file if input_file is not None else ""
29-
additional_files = additional_files if additional_files is not None else []
28+
input_file = input_file or ""
29+
additional_files = additional_files or []
3030

3131
data_entry = Data(
3232
geode_object=geode_object,
@@ -38,15 +38,13 @@ def create(
3838
)
3939

4040
session = get_session()
41-
if session:
42-
session.add(data_entry)
43-
session.flush()
44-
session.commit()
41+
session.add(data_entry)
42+
session.flush()
43+
session.commit()
4544
return data_entry
4645

4746
@staticmethod
4847
def get(data_id: str) -> "Data | None":
4948
session = get_session()
50-
if session:
51-
return session.get(Data, data_id)
52-
return None
49+
data_query = select(Data).where(Data.id == data_id)
50+
return session.scalars(data_query).first()

tests/conftest.py

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,40 @@
11
import os
22
import pytest
3-
from flask import Flask
43
from src.opengeodeweb_microservice.database.connection import init_database, get_session
54
from src.opengeodeweb_microservice.database.data import Data
65

76

8-
@pytest.fixture(scope="session")
9-
def app():
10-
app = Flask(__name__)
11-
app.config.update(
12-
{
13-
"TESTING": True,
14-
"SQLALCHEMY_DATABASE_URI": f"sqlite:///{os.path.join(os.path.dirname(__file__), 'test_project.db')}",
15-
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
16-
}
17-
)
18-
with app.app_context():
19-
init_database(app, "test_project.db")
20-
yield app
21-
_cleanup_database()
7+
DB_PATH = os.path.join(os.path.dirname(__file__), "test_project.db")
228

239

24-
def _cleanup_database():
10+
@pytest.fixture(scope="session", autouse=True)
11+
def setup_database():
12+
init_database(DB_PATH)
13+
yield
14+
_cleanup_database(DB_PATH)
15+
16+
17+
def _cleanup_database(db_path: str):
2518
try:
2619
session = get_session()
27-
if session:
28-
session.close()
20+
session.close()
2921
except Exception:
3022
pass
31-
db_path = os.path.join(os.path.dirname(__file__), "test_project.db")
23+
3224
if os.path.exists(db_path):
3325
try:
3426
os.remove(db_path)
3527
except PermissionError:
3628
pass
3729

3830

39-
@pytest.fixture
40-
def app_context(app):
41-
with app.app_context():
42-
yield
43-
44-
45-
@pytest.fixture
46-
def clean_database(app_context):
47-
session = get_session()
48-
if session:
31+
@pytest.fixture(autouse=True)
32+
def clean_database():
33+
with get_session() as session:
34+
session = get_session()
4935
session.query(Data).delete()
5036
session.commit()
51-
yield
52-
if session:
37+
yield
5338
try:
5439
session.rollback()
5540
except Exception:

tests/test_connection.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/test_database.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
1-
from src.opengeodeweb_microservice.database.connection import get_session
21
from src.opengeodeweb_microservice.database.data import Data
32

43

5-
def test_data_crud_operations():
6-
data = Data.create(geode_object="test_object", input_file="test.txt")
4+
def test_data_crud_operations(clean_database):
5+
data = Data.create(
6+
geode_object="test_object", input_file="test.txt", additional_files=[]
7+
)
8+
print("id", data.id, flush=True)
79
assert data.id is not None
8-
session = get_session()
9-
session.commit()
10+
assert isinstance(data.id, str)
11+
1012
retrieved = Data.get(data.id)
1113
assert retrieved is not None
14+
assert isinstance(retrieved, Data)
1215
assert retrieved.geode_object == "test_object"
16+
assert retrieved.input_file == "test.txt"
17+
assert retrieved.id == data.id
1318
non_existent = Data.get("fake_id")
1419
assert non_existent is None
1520

1621

17-
def test_data_with_additional_files():
22+
def test_data_with_additional_files(clean_database):
1823
files = ["file1.txt", "file2.txt"]
1924
data = Data.create(geode_object="test_files", additional_files=files)
20-
session = get_session()
21-
session.commit()
25+
assert data.id is not None
26+
assert isinstance(data.id, str)
27+
2228
retrieved = Data.get(data.id)
29+
assert retrieved is not None
30+
assert isinstance(retrieved, Data)
2331
assert retrieved.additional_files == files
32+
assert retrieved.geode_object == "test_files"

0 commit comments

Comments
 (0)