mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
feat: other databases support
This commit is contained in:
parent
1b2f7f2675
commit
7559c66127
20 changed files with 39 additions and 67 deletions
|
@ -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
|
||||
|
|
|
@ -9,4 +9,4 @@ services:
|
|||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
db_type: sqlite
|
||||
DB_URL: sqlite:///mealie.db
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue