feat: other databases support

This commit is contained in:
Antoine Bertin 2021-04-27 10:19:29 +02:00
commit 7559c66127
No known key found for this signature in database
GPG key ID: 09851B52754E2327
20 changed files with 39 additions and 67 deletions

View file

@ -26,8 +26,8 @@ services:
ports:
- 9921:9000
environment:
db_type: sqlite
TZ: America/Anchorage # Specify Correct Timezone for Date/Time to line up correctly.
DB_URL: sqlite:///mealie.db
volumes:
- ./dev/data:/app/dev/data
- ./mealie:/app/mealie

View file

@ -9,4 +9,4 @@ services:
ports:
- 9090:80
environment:
db_type: sqlite
DB_URL: sqlite:///mealie.db

View file

@ -25,7 +25,7 @@ Deployment with the Docker CLI can be done with `docker run` and specify the dat
```shell
docker run \
-e DB_TYPE='sqlite' \
-e DB_URL='sqlite:///mealie.db' \
-p 9925:80 \
-v `pwd`:'/app/data/' \
hkotel/mealie:latest
@ -50,7 +50,7 @@ services:
ports:
- 9925:80
environment:
DB_TYPE: sqlite
DB_URL: sqlite:///mealie.db
TZ: America/Anchorage
volumes:
- ./mealie/data/:/app/data
@ -59,19 +59,19 @@ services:
## Env Variables
| Variables | Default | Description |
| ---------------- | ------------------ | ----------------------------------------------------------------------------------- |
| DB_TYPE | sqlite | The database type to be used. Current Options 'sqlite' |
| DEFAULT_GROUP | Home | The default group for users |
| DEFAULT_EMAIL | changeme@email.com | The default username for the superuser |
| DEFAULT_PASSWORD | MyPassword | The default password for the superuser |
| TOKEN_TIME | 2 | The time in hours that a login/auth token is valid |
| API_PORT | 9000 | The port exposed by backend API. **do not change this if you're running in docker** |
| API_DOCS | True | Turns on/off access to the API documentation locally. |
| TZ | UTC | Must be set to get correct date/time on the server |
| Variables | Default | Description |
| ---------------- | ------------------- | ----------------------------------------------------------------------------------- |
| DB_URL | sqlite:///mealie.db | The database url to be used. See [SQLAlchemy documentation][1] for more options |
| DEFAULT_GROUP | Home | The default group for users |
| DEFAULT_EMAIL | changeme@email.com | The default username for the superuser |
| DEFAULT_PASSWORD | MyPassword | The default password for the superuser |
| TOKEN_TIME | 2 | The time in hours that a login/auth token is valid |
| API_PORT | 9000 | The port exposed by backend API. **do not change this if you're running in docker** |
| API_DOCS | True | Turns on/off access to the API documentation locally. |
| TZ | UTC | Must be set to get correct date/time on the server |
[1]: https://docs.sqlalchemy.org/en/14/core/engines.html#database-urls
## Advanced
!!! warning "Not Required"

View file

@ -57,7 +57,6 @@ class AppDirectories:
self.CHOWDOWN_DIR: Path = self.MIGRATION_DIR.joinpath("chowdown")
self.TEMPLATE_DIR: Path = data_dir.joinpath("templates")
self.USER_DIR: Path = data_dir.joinpath("users")
self.SQLITE_DIR: Path = data_dir.joinpath("db")
self.RECIPE_DATA_DIR: Path = data_dir.joinpath("recipes")
self.TEMP_DIR: Path = data_dir.joinpath(".temp")
@ -70,7 +69,6 @@ class AppDirectories:
self.DEBUG_DIR,
self.MIGRATION_DIR,
self.TEMPLATE_DIR,
self.SQLITE_DIR,
self.NEXTCLOUD_DIR,
self.CHOWDOWN_DIR,
self.RECIPE_DATA_DIR,
@ -100,21 +98,7 @@ class AppSettings(BaseSettings):
return "/redoc" if self.API_DOCS else None
SECRET: str = determine_secrets(DATA_DIR, PRODUCTION)
DATABASE_TYPE: str = Field("sqlite", env="DB_TYPE")
@validator("DATABASE_TYPE", pre=True)
def validate_db_type(cls, v: str) -> Optional[str]:
if v != "sqlite":
raise ValueError("Unable to determine database type. Acceptible options are 'sqlite'")
else:
return v
# Used to Set SQLite File Version
SQLITE_FILE: Optional[Union[str, Path]]
@validator("SQLITE_FILE", pre=True)
def identify_sqlite_file(cls, v: str) -> Optional[str]:
return app_dirs.SQLITE_DIR.joinpath(f"mealie_{DB_VERSION}.sqlite")
DB_URL: str = Field("sqlite:///mealie.db", env="DB_URL")
DEFAULT_GROUP: str = "Home"
DEFAULT_EMAIL: str = "changeme@email.com"

View file

@ -5,8 +5,7 @@ from mealie.db.models.db_session import sql_global_init
sql_exists = True
sql_exists = settings.SQLITE_FILE.is_file()
SessionLocal = sql_global_init(settings.SQLITE_FILE)
SessionLocal = sql_global_init(settings.DB_URL)
def create_session() -> Session:

View file

@ -5,15 +5,10 @@ from mealie.db.models.model_base import SqlAlchemyBase
from sqlalchemy.orm import sessionmaker
def sql_global_init(db_file: Path, check_thread=False):
SQLALCHEMY_DATABASE_URL = "sqlite:///" + str(db_file.absolute())
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
def sql_global_init(db_url: str):
engine = sa.create_engine(
SQLALCHEMY_DATABASE_URL,
db_url,
echo=False,
connect_args={"check_same_thread": check_thread},
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

View file

@ -9,7 +9,7 @@ from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
class Meal(SqlAlchemyBase):
__tablename__ = "meal"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("mealplan.uid"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("mealplan.uid"))
slug = sa.Column(sa.String)
name = sa.Column(sa.String)
date = sa.Column(sa.Date)
@ -30,7 +30,7 @@ class MealPlanModel(SqlAlchemyBase, BaseMixins):
startDate = sa.Column(sa.Date)
endDate = sa.Column(sa.Date)
meals: List[Meal] = orm.relationship(Meal, cascade="all, delete, delete-orphan")
group_id = sa.Column(sa.String, sa.ForeignKey("groups.id"))
group_id = sa.Column(sa.Integer, sa.ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="mealplans")
def __init__(self, startDate, endDate, meals, group: str, uid=None, session=None) -> None:

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class ApiExtras(SqlAlchemyBase):
__tablename__ = "api_extras"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
key_name = sa.Column(sa.String, unique=True)
value = sa.Column(sa.String)

View file

@ -6,7 +6,7 @@ class RecipeIngredient(SqlAlchemyBase):
__tablename__ = "recipes_ingredients"
id = sa.Column(sa.Integer, primary_key=True)
position = sa.Column(sa.Integer)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
ingredient = sa.Column(sa.String)
def update(self, ingredient):

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class RecipeInstruction(SqlAlchemyBase):
__tablename__ = "recipe_instructions"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
position = sa.Column(sa.Integer)
type = sa.Column(sa.String, default="")
text = sa.Column(sa.String)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Note(SqlAlchemyBase):
__tablename__ = "notes"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
title = sa.Column(sa.String)
text = sa.Column(sa.String)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Nutrition(SqlAlchemyBase):
__tablename__ = "recipe_nutrition"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
calories = sa.Column(sa.String)
fatContent = sa.Column(sa.String)
fiberContent = sa.Column(sa.String)

View file

@ -11,7 +11,11 @@ recipes2tags = sa.Table(
"recipes2tags",
SqlAlchemyBase.metadata,
sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")),
<<<<<<< HEAD
sa.Column("tag_id", sa.Integer, sa.ForeignKey("tags.id")),
=======
sa.Column("tag_slug", sa.String, sa.ForeignKey("tags.slug")),
>>>>>>> e2e2ad5 (feat: other databases support)
)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Tool(SqlAlchemyBase):
__tablename__ = "tools"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
tool = sa.Column(sa.String)
def __init__(self, tool) -> None:

View file

@ -16,7 +16,7 @@ class User(SqlAlchemyBase, BaseMixins):
full_name = Column(String, index=True)
email = Column(String, unique=True, index=True)
password = Column(String)
group_id = Column(String, ForeignKey("groups.id"))
group_id = Column(Integer, ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="users")
admin = Column(Boolean, default=False)

View file

@ -20,8 +20,7 @@ async def get_debug_info(current_user=Depends(get_current_user)):
demo_status=settings.IS_DEMO,
api_port=settings.API_PORT,
api_docs=settings.API_DOCS,
db_type=settings.DATABASE_TYPE,
sqlite_file=settings.SQLITE_FILE,
db_url=settings.DB_URL,
default_group=settings.DEFAULT_GROUP,
)

View file

@ -11,6 +11,5 @@ class AppInfo(CamelModel):
class DebugInfo(AppInfo):
api_port: int
api_docs: bool
db_type: str
sqlite_file: Path
db_url: str
default_group: str

View file

@ -14,13 +14,12 @@ API_PORT=9000
# Exposes /docs and /redoc on the server
API_DOCS=True
# Sets the Database type to use. Currently the only supported options is 'sqlite'
DB_TYPE=sqlite
# Sets the Database URL to use. See https://docs.sqlalchemy.org/en/14/core/engines.html for options.
DB_URL=sqlite:///mealie.db
# Sets the token expiration time in hours.
TOKEN_TIME=24
# NOT USED
SFTP_USERNAME=None
SFTP_PASSWORD=None

View file

@ -16,7 +16,7 @@ SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db")
SQLITE_FILE.unlink(missing_ok=True)
TestSessionLocal = sql_global_init(SQLITE_FILE, check_thread=False)
TestSessionLocal = sql_global_init(SQLITE_FILE)
init_db(TestSessionLocal())

View file

@ -9,14 +9,14 @@ def test_default_settings(monkeypatch):
monkeypatch.delenv("DEFAULT_PASSWORD", raising=False)
monkeypatch.delenv("API_PORT", raising=False)
monkeypatch.delenv("API_DOCS", raising=False)
monkeypatch.delenv("DB_TYPE", raising=False)
monkeypatch.delenv("DB_URL", raising=False)
monkeypatch.delenv("IS_DEMO", raising=False)
app_settings = AppSettings()
assert app_settings.DEFAULT_GROUP == "Home"
assert app_settings.DEFAULT_PASSWORD == "MyPassword"
assert app_settings.DATABASE_TYPE == "sqlite"
assert app_settings.DB_URL == "sqlite:///mealie.db"
assert app_settings.API_PORT == 9000
assert app_settings.API_DOCS is True
assert app_settings.IS_DEMO is False
@ -42,13 +42,6 @@ def test_non_default_settings(monkeypatch):
assert app_settings.DOCS_URL is None
def test_unknown_database(monkeypatch):
monkeypatch.setenv("DB_TYPE", "nonsense")
with pytest.raises(ValueError, match="Unable to determine database type. Acceptible options are 'sqlite'"):
AppSettings()
def test_secret_generation(tmp_path):
app_dirs = AppDirectories(CWD, DATA_DIR)
assert determine_secrets(app_dirs.DATA_DIR, False) == "shh-secret-test-key"