diff --git a/cookiecutter.json b/cookiecutter.json index c1e99d6d8e3385788e8114d90dba8e83d0fb7056..d56cffbf41cbbbb57f4c8a0285829c76df897890 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -3,6 +3,7 @@ "full_name": "Pavel Kirilin", "email": "win10@list.ru", "project_description": "", + "default_port": 8401, "add_redis": [ true, false @@ -15,6 +16,10 @@ true, false ], + "add_elastic": [ + true, + false + ], "add_scheduler": [ true, false diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 50362903dda46f834c7ab0cfe6dfba323e82eb57..2715205b7d8e4fff6868e5c2877b71a95848fbd7 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -24,7 +24,7 @@ def delete_resources_for_disabled_features(): with open(MANIFEST) as manifest_file: manifest = json.load(manifest_file) for feature in manifest['features']: - if not feature['enabled']: + if not feature['enabled'] == "true": print("removing resources for disabled feature {}...".format(feature['name'])) for resource in feature['resources']: delete_resource(resource) diff --git a/{{cookiecutter.project_name}}/conditional_files.json b/{{cookiecutter.project_name}}/conditional_files.json index 0186768f3c1465c506931b942b693e4de3e2cb5a..d755a9d7738adb9215c7766ce08d50b98149d8fc 100644 --- a/{{cookiecutter.project_name}}/conditional_files.json +++ b/{{cookiecutter.project_name}}/conditional_files.json @@ -2,7 +2,7 @@ "features": [ { "name": "Redis support", - "enabled": {{cookiecutter.add_redis|lower}}, + "enabled": "{{cookiecutter.add_redis|lower}}", "resources": [ "src/services/redis.py", "src/api/redis_api" @@ -10,7 +10,7 @@ }, { "name": "Task scheduler", - "enabled": {{cookiecutter.add_scheduler|lower}}, + "enabled": "{{cookiecutter.add_scheduler|lower}}", "resources": [ "scheduler.py", "systemd/{{ cookiecutter.project_name }}_scheduler.service" @@ -18,20 +18,27 @@ }, { "name": "Systemd support", - "enabled": {{cookiecutter.add_systemd|lower}}, + "enabled": "{{cookiecutter.add_systemd|lower}}", "resources": [ "systemd" ] }, { "name": "Dummy DB model", - "enabled": {{cookiecutter.add_dummy_model|lower}}, + "enabled": "{{cookiecutter.add_dummy_model|lower}}", "resources": [ "src/models/dummy_db_model.py", "migrations/versions/7ae297ab5ac1_created_dummy_model.py", "tests/dummy_db_test.py", "src/api/dummy_db" ] + }, + { + "name": "Elastic search", + "enabled": "{{cookiecutter.add_elastic|lower}}", + "resources": [ + "src/services/elastic" + ] } ] } \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/docker-compose.prod.yml b/{{cookiecutter.project_name}}/docker-compose.prod.yml index 39cefc8d0a73ec4ad41a358a65db04db969e4114..1ed7b83a7ca9f5c96e3a451f10b5fe59d845d50c 100644 --- a/{{cookiecutter.project_name}}/docker-compose.prod.yml +++ b/{{cookiecutter.project_name}}/docker-compose.prod.yml @@ -12,8 +12,6 @@ services: {{ cookiecutter.project_name }}.description: {{ cookiecutter.project_description }} env_file: - envs/.env - ports: - - 8402:8000 depends_on: - db networks: @@ -59,9 +57,25 @@ services: - {{ cookiecutter.project_name }}_network {% endif %} + {% if cookiecutter.add_elastic == "True" -%} + es: + restart: always + container_name: {{ cookiecutter.project_name }}_es_dev + image: elasticsearch:7.3.0 + volumes: + - {{ cookiecutter.project_name }}_es_data_dev:/usr/share/elasticsearch/data + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + networks: + - {{ cookiecutter.project_name }}_network_dev + {% endif %} + volumes: {{ cookiecutter.project_name }}_db_data: {{ cookiecutter.project_name }}_redis_data: + {{ cookiecutter.project_name }}_es_data_dev: networks: {{ cookiecutter.project_name }}_network: diff --git a/{{cookiecutter.project_name}}/docker-compose.yml b/{{cookiecutter.project_name}}/docker-compose.yml index c9821bf56c30a54a78f26f21c65f7e54a4f96d74..8888331c425edb42ef3642366f6a2ecdafc360b8 100644 --- a/{{cookiecutter.project_name}}/docker-compose.yml +++ b/{{cookiecutter.project_name}}/docker-compose.yml @@ -13,7 +13,7 @@ services: env_file: - envs/.env ports: - - 8401:8000 + - {{ cookiecutter.default_port }}:8000 volumes: - ./:/app depends_on: @@ -65,9 +65,25 @@ services: - {{ cookiecutter.project_name }}_network_dev {% endif %} + {% if cookiecutter.add_elastic == "True" -%} + es: + restart: always + container_name: {{ cookiecutter.project_name }}_es_dev + image: elasticsearch:7.3.0 + volumes: + - {{ cookiecutter.project_name }}_es_data_dev:/usr/share/elasticsearch/data + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + networks: + - {{ cookiecutter.project_name }}_network_dev + {% endif %} + volumes: {{ cookiecutter.project_name }}_db_data_dev: {{ cookiecutter.project_name }}_redis_data_dev: + {{ cookiecutter.project_name }}_es_data_dev: networks: {{ cookiecutter.project_name }}_network_dev: diff --git a/{{cookiecutter.project_name}}/envs/.env b/{{cookiecutter.project_name}}/envs/.env index 16929a750f9c46b49cf5e68503c27ce413051c27..9a9fab0189aff9b4165ebaac3ff9d792c30fed92 100644 --- a/{{cookiecutter.project_name}}/envs/.env +++ b/{{cookiecutter.project_name}}/envs/.env @@ -11,4 +11,7 @@ REDIS_PORT=6379 {% endif %} {% if cookiecutter.add_scheduler == "True" -%} SCHEDULE_TIMER=20 +{% endif %} +{% if cookiecutter.add_elastic == "True" -%} +ELASTIC_HOST=http://es:9200 {% endif %} \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/envs/example.env b/{{cookiecutter.project_name}}/envs/example.env index 187bc79d5d8a10494775a3f1888a7ce717a922f5..469d2c6bf3f0b94c4849e25a8ce4d18aacfc6cf3 100644 --- a/{{cookiecutter.project_name}}/envs/example.env +++ b/{{cookiecutter.project_name}}/envs/example.env @@ -12,4 +12,7 @@ REDIS_PORT=6379 HTTPBIN_HOST=https://httpbin.org/ {% if cookiecutter.add_scheduler == "True" -%} SCHEDULE_TIMER=20 +{% endif %} +{% if cookiecutter.add_elastic == "True" -%} +ELASTIC_HOST=http://es:9200 {% endif %} \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/envs/test.env b/{{cookiecutter.project_name}}/envs/test.env index 649a738c7c00c73f2df94deeaa5b46bc14aabc64..8cc07f19ea2126a89ec1b9a0313b1500a8803142 100644 --- a/{{cookiecutter.project_name}}/envs/test.env +++ b/{{cookiecutter.project_name}}/envs/test.env @@ -9,4 +9,10 @@ REDIS_PASSWORD={{cookiecutter.redis_password}} REDIS_HOST=localhost REDIS_PORT=6379 {% endif %} -HTTPBIN_HOST=https://httpbin.org/ \ No newline at end of file +HTTPBIN_HOST=https://httpbin.org/ +{% if cookiecutter.add_scheduler == "True" -%} +SCHEDULE_TIMER=20 +{% endif %} +{% if cookiecutter.add_elastic == "True" -%} +ELASTIC_HOST=http://es:9200 +{% endif %} \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/migrations/versions/7ae297ab5ac1_created_dummy_model.py b/{{cookiecutter.project_name}}/migrations/versions/7ae297ab5ac1_created_dummy_model.py index 00a6d9fa4415c8add74b9055344313440c7de372..d55c3718394ba65a61224bfaa882dcf96e47b96f 100644 --- a/{{cookiecutter.project_name}}/migrations/versions/7ae297ab5ac1_created_dummy_model.py +++ b/{{cookiecutter.project_name}}/migrations/versions/7ae297ab5ac1_created_dummy_model.py @@ -5,8 +5,8 @@ Revises: Create Date: 2020-10-05 23:56:58.658606 """ -from alembic import op import sqlalchemy as sa +from alembic import op from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. @@ -19,13 +19,16 @@ depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.create_table('dummydbmodel', - sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('surname', sa.String(), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('clock_timestamp()'), nullable=False), - sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('clock_timestamp()'), nullable=False), - sa.PrimaryKeyConstraint('id') - ) + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('surname', sa.String(), nullable=False), + {% if cookiecutter.add_elastic == "True" -%}sa.Column('tags', sa.String(), nullable=False, default=""),{% endif %} + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('clock_timestamp()'), + nullable=False), + sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('clock_timestamp()'), + nullable=False), + sa.PrimaryKeyConstraint('id') + ) op.create_index(op.f('ix_dummydbmodel_name'), 'dummydbmodel', ['name'], unique=False) op.create_index(op.f('ix_dummydbmodel_surname'), 'dummydbmodel', ['surname'], unique=False) # ### end Alembic commands ### diff --git a/{{cookiecutter.project_name}}/pyproject.toml b/{{cookiecutter.project_name}}/pyproject.toml index dfc579c2123a9867eae42e4e27cdc70e1d297b85..d4bcc2dc8718c030338811164d9d04885e8b78af 100644 --- a/{{cookiecutter.project_name}}/pyproject.toml +++ b/{{cookiecutter.project_name}}/pyproject.toml @@ -19,6 +19,10 @@ aiopg = "^1.0.0" {% if cookiecutter.add_redis == "True" -%} aioredis = "^1.3.1" {% endif %} +{% if cookiecutter.add_elastic == "True" -%} +elasticsearch-dsl = "^7.3.0" +elasticsearch = {extras = ["async"], version = "^7.9.1"} +{% endif %} {% if cookiecutter.add_scheduler == "True" -%} aioschedule = "^0.5.2" {% endif %} diff --git a/{{cookiecutter.project_name}}/src/api/dummy_db/routes.py b/{{cookiecutter.project_name}}/src/api/dummy_db/routes.py index 0efaf8c36bf826e72a87625b60d5ed800c18fd8d..12f7adcb99513874c1bf7ccb7d5a48f7a871b1d4 100644 --- a/{{cookiecutter.project_name}}/src/api/dummy_db/routes.py +++ b/{{cookiecutter.project_name}}/src/api/dummy_db/routes.py @@ -4,10 +4,16 @@ from typing import Optional from fastapi import APIRouter, Depends from src.api.dummy_db.schema import ( - BaseDummyModel, UpdateDummyModel, - GetDummyResponse + GetDummyResponse, ) +{% if cookiecutter.add_elastic == "True" -%} +from src.api.dummy_db.schema import DummyElasticResponse, ElasticAdd +from src.services.elastic.schema import ElasticFilterModel +{%else%} +from src.api.dummy_db.schema import BaseDummyModel +{% endif %} + from src.models import DummyDBModel from src.services.db.session import Session, db_session @@ -16,9 +22,17 @@ URL_PREFIX = "/dummy_db_obj" @router.put("/") -async def create_dummy(dummy_obj: BaseDummyModel, session: Session = Depends(db_session)) -> None: +async def create_dummy(dummy_obj: {% if cookiecutter.add_elastic == "True" -%}ElasticAdd{% else %}BaseDummyModel{% endif %}, session: Session = Depends(db_session)) -> None: + {% if cookiecutter.add_elastic == "True" -%} + insert_query = DummyDBModel.create(**dummy_obj.dict()).returning(DummyDBModel.id) + model_id = await session.scalar(insert_query) + await DummyDBModel.elastic_add( + model_id=model_id, + **dummy_obj.dict() + ) + {% else %} await session.execute(DummyDBModel.create(**dummy_obj.dict())) - + {% endif %} @router.post("/{dummy_id}") async def update_dummy_model( @@ -27,11 +41,20 @@ async def update_dummy_model( session: Session = Depends(db_session) ) -> None: await session.execute(DummyDBModel.update(dummy_id, **new_values.dict())) + {% if cookiecutter.add_elastic == "True" -%} + await DummyDBModel.elastic_update( + model_id=dummy_id, + **new_values.dict(exclude_unset=True) + ) + {% endif %} @router.delete("/{dummy_id}") async def delete_dummy_model(dummy_id: uuid.UUID, session: Session = Depends(db_session)) -> None: await session.execute(DummyDBModel.delete(dummy_id)) + {% if cookiecutter.add_elastic == "True" -%} + await DummyDBModel.elastic_delete(model_id=dummy_id) + {% endif %} @router.get("/", response_model=GetDummyResponse) @@ -50,3 +73,12 @@ async def filter_dummy_models( return GetDummyResponse( results=results ) + +{% if cookiecutter.add_elastic == "True" -%} +@router.get("/elastic", response_model=DummyElasticResponse) +async def dummy_elastic_filter(query: ElasticFilterModel = Depends(ElasticFilterModel)) -> DummyElasticResponse: + results = await DummyDBModel.elastic_filter(**query.dict()) + return DummyElasticResponse( + results=results + ) +{% endif %} diff --git a/{{cookiecutter.project_name}}/src/api/dummy_db/schema.py b/{{cookiecutter.project_name}}/src/api/dummy_db/schema.py index 08778b64e84ef8c1580f3818cb49f1358988894c..d367ecb64611c13f190f66ecfd0d4b60c1ce71d2 100644 --- a/{{cookiecutter.project_name}}/src/api/dummy_db/schema.py +++ b/{{cookiecutter.project_name}}/src/api/dummy_db/schema.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime from typing import Optional, List - +from src.models.dummy_db_model import DummyElasticFilter from pydantic import Field, BaseConfig from pydantic.main import BaseModel @@ -23,11 +23,20 @@ class ReturnDummyModel(BaseDummyModel): class GetDummyResponse(BaseModel): results: List[ReturnDummyModel] +{% if cookiecutter.add_elastic == "True" -%} +class DummyElasticResponse(BaseModel): + results: List[DummyElasticFilter] + +class ElasticAdd(BaseDummyModel): + tags: str = Field(default="") +{% endif %} class UpdateDummyModel(BaseModel): name: Optional[str] = Field(default=None, example="New name") surname: Optional[str] = Field(default=None, example="New surname") - + {% if cookiecutter.add_elastic == "True" -%} + tags: Optional[str] = Field(default=None, example="tag1,tag2") + {% endif %} class DummyFiltersModel(BaseModel): dummy_id: Optional[uuid.UUID] = Field(default=None) diff --git a/{{cookiecutter.project_name}}/src/models/dummy_db_model.py b/{{cookiecutter.project_name}}/src/models/dummy_db_model.py index 2e188cf270118ffac94cf2b12143d23913ab2055..90215f455ecc5b1c1379b31eab55017d08008d2b 100644 --- a/{{cookiecutter.project_name}}/src/models/dummy_db_model.py +++ b/{{cookiecutter.project_name}}/src/models/dummy_db_model.py @@ -2,15 +2,28 @@ import uuid from typing import Optional from sqlalchemy import Column, String, sql -from sqlalchemy.dialects.postgresql import UUID - +{% if cookiecutter.add_elastic == "True" -%} +from src.services.elastic import ElasticModelMixin +from src.services.elastic.schema import ESReturnModel +{% endif %} from src.services.db import Base +{% if cookiecutter.add_elastic == "True" -%} +class DummyElasticFilter(ESReturnModel): + name: str + surname: str +{% endif %} -class DummyDBModel(Base): - id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) +class DummyDBModel(Base{% if cookiecutter.add_elastic == "True" -%}, ElasticModelMixin[DummyElasticFilter]{% endif %}): name = Column(String, nullable=False, index=True) surname = Column(String, nullable=False, index=True) + {% if cookiecutter.add_elastic == "True" -%} + tags = Column(String, nullable=False, default="") + + __es_index_name = "dummy_elastic_index" + __es_search_fields = ["name", "surname"] + __es_search_type = DummyElasticFilter + {% endif %} @classmethod def create( @@ -18,10 +31,12 @@ class DummyDBModel(Base): *, name: str, surname: str, + {% if cookiecutter.add_elastic == "True" -%}tags: str = "",{% endif %} ) -> sql.Insert: return cls.insert_query( name=name, surname=surname, + {% if cookiecutter.add_elastic == "True" -%}tags=tags,{% endif %} ) @classmethod @@ -33,13 +48,16 @@ class DummyDBModel(Base): dummy_id: uuid.UUID, *, name: Optional[str] = None, - surname: Optional[str] = None + surname: Optional[str] = None, + {% if cookiecutter.add_elastic == "True" -%}tags: Optional[str] = None,{% endif %} ) -> sql.Update: new_values = {} if name: new_values[cls.name] = name if surname: new_values[cls.surname] = surname + if tags is not None: + new_values[cls.tags] = tags return cls.update_query().where(cls.id == dummy_id).values(new_values) @classmethod diff --git a/{{cookiecutter.project_name}}/src/server.py b/{{cookiecutter.project_name}}/src/server.py index f451117314cf4ebd220adef39f6efbec8f7bd007..6dd3c515b460a5f5b1431e1b4bc5c227533fbedb 100644 --- a/{{cookiecutter.project_name}}/src/server.py +++ b/{{cookiecutter.project_name}}/src/server.py @@ -68,11 +68,3 @@ if settings.is_dev: "head", ] ) - - @app.get("/conf") - def reveal_current_configuration() -> Settings: - """ - Show current application settings - ## Available only under development - """ - return settings \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/src/services/db/session.py b/{{cookiecutter.project_name}}/src/services/db/session.py index 34d15ab4faa4457d0c2fb29ff9d1ed98d0aa96a3..cfb036efaa71409fe4edff2e52d658b669c79f42 100644 --- a/{{cookiecutter.project_name}}/src/services/db/session.py +++ b/{{cookiecutter.project_name}}/src/services/db/session.py @@ -14,7 +14,7 @@ class Session: async def fetchone(self, query: Any) -> Any: cursor = await self.connection.execute(query) - return cursor.fetchone() + return await cursor.fetchone() async def scalar(self, query: Any) -> Any: result = await self.fetchone(query) diff --git a/{{cookiecutter.project_name}}/src/services/elastic/__init__.py b/{{cookiecutter.project_name}}/src/services/elastic/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c2b1be98396cb6da554ba0c3da6fa401d268773 100644 --- a/{{cookiecutter.project_name}}/src/services/elastic/__init__.py +++ b/{{cookiecutter.project_name}}/src/services/elastic/__init__.py @@ -0,0 +1,6 @@ +from src.services.elastic.mixin import ElasticModelMixin + +__all__ = [ + 'ElasticModelMixin', + 'schema' +] diff --git a/{{cookiecutter.project_name}}/src/services/elastic/client.py b/{{cookiecutter.project_name}}/src/services/elastic/client.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8f8960214e35356ac42d493c65ef7fb3895b52e3 100644 --- a/{{cookiecutter.project_name}}/src/services/elastic/client.py +++ b/{{cookiecutter.project_name}}/src/services/elastic/client.py @@ -0,0 +1,4 @@ +from elasticsearch import AsyncElasticsearch +from src.settings import settings + +elastic_client = AsyncElasticsearch(hosts=[settings.elastic_host]) diff --git a/{{cookiecutter.project_name}}/src/services/elastic/mixin.py b/{{cookiecutter.project_name}}/src/services/elastic/mixin.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ec33a446686d97c7a7e2c7e746162550d0bcaac6 100644 --- a/{{cookiecutter.project_name}}/src/services/elastic/mixin.py +++ b/{{cookiecutter.project_name}}/src/services/elastic/mixin.py @@ -0,0 +1,84 @@ +import uuid +from typing import TypeVar, List, Optional, Any, Generic, Union, Dict + +from elasticsearch import NotFoundError +from elasticsearch_dsl import Search +from elasticsearch_dsl.query import MultiMatch +from loguru import logger + +from src.services.elastic.client import elastic_client +from src.services.elastic.schema import ESReturnModel + +SearchModel = TypeVar("SearchModel", covariant=True, bound=ESReturnModel) + + +class ElasticModelMixin(Generic[SearchModel]): + __es_index_name: str = "default_index" + __es_search_fields: List[str] = [] + __es_search_type: Optional[SearchModel] = None + + @classmethod + async def elastic_add( + cls, model_id: uuid.UUID, *, tags: Optional[str] = "", **kwargs: Any + ) -> None: + ret = await elastic_client.index( + index=cls.__es_index_name, + body={"tags": tags.split(",") if tags else [], **kwargs}, + id=str(model_id), + ) + result = ret["result"] + logger.debug(f"{result} '{cls.__name__}:{model_id}' in elastic") + + @classmethod + async def elastic_filter( + cls, *, query: str, offset: int, limit: int + ) -> List[Union[SearchModel, Dict[str, Any]]]: + elastic_query = Search() + if query: + elastic_query = elastic_query.query( + MultiMatch( + type="phrase_prefix", query=query, fields=cls.__es_search_fields + ) + ) + elastic_query = elastic_query[offset : offset + limit] + search_res = await elastic_client.search(elastic_query.to_dict()) + hits = search_res.get("hits", {}).get("hits", []) + results = [] + constructor = cls.__es_search_type or dict + for hit in hits: + logger.debug(hit) + results.append(constructor(id=hit.get("_id"), **hit.get("_source", {}))) + return results + + @classmethod + async def elastic_update( + cls, + model_id: uuid.UUID, + **body: Any, + ) -> None: + tags = body.get("tags", None) + if tags is not None: + body["tags"] = tags.split(",") if tags else [] + logger.debug(f"Updating '{cls.__name__}:{model_id}' in ES") + try: + await elastic_client.update( + index=cls.__es_index_name, + id=str(model_id), + body={"doc": body}, + refresh=True, + ) + except NotFoundError: + logger.debug(f"Can't update unknown {cls.__name__} in es") + + @classmethod + async def elastic_delete(cls, model_id: uuid.UUID) -> None: + try: + await elastic_client.delete(index=cls.__es_index_name, id=str(model_id)) + except NotFoundError: + logger.debug(f"'{cls.__name__}:{model_id}' was not found in ES") + + @classmethod + async def elastic_create_index(cls) -> None: + if not await elastic_client.indices.exists(cls.__es_index_name): + logger.debug(f"Creating elastic index {cls.__es_index_name}") + await elastic_client.indices.create(cls.__es_index_name) diff --git a/{{cookiecutter.project_name}}/src/services/elastic/schema.py b/{{cookiecutter.project_name}}/src/services/elastic/schema.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1b70c8dbcb81808de92641edd412a925d9279ef8 100644 --- a/{{cookiecutter.project_name}}/src/services/elastic/schema.py +++ b/{{cookiecutter.project_name}}/src/services/elastic/schema.py @@ -0,0 +1,15 @@ +import uuid +from typing import Optional, List + +from pydantic import Field, BaseModel + + +class ESReturnModel(BaseModel): + id: uuid.UUID + tags: Optional[List[str]] + + +class ElasticFilterModel(BaseModel): + query: str = Field(default="") + limit: int = Field(default=100, lt=400) + offset: int = Field(default=0) diff --git a/{{cookiecutter.project_name}}/src/settings.py b/{{cookiecutter.project_name}}/src/settings.py index 438f704c79efd01f991695358c3a94305b343d02..8b66172436fbfba5bfc66d5ad778d0686eb838ff 100644 --- a/{{cookiecutter.project_name}}/src/settings.py +++ b/{{cookiecutter.project_name}}/src/settings.py @@ -32,6 +32,9 @@ class Settings(BaseSettings): {% endif %} # httpbin client settings httpbin_host: str = Field(default="https://httpbin.org/") + {% if cookiecutter.add_elastic == "True" -%} + elastic_host: str = Field(...) + {% endif %} @property def is_dev(self) -> bool: