Skip to content

Commit

Permalink
Add exists() (#56)
Browse files Browse the repository at this point in the history
* Add extra test
* Add exists
  • Loading branch information
tarsil authored Jul 29, 2024
1 parent 6ea0141 commit 8f39368
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 83 deletions.
12 changes: 11 additions & 1 deletion docs/en/docs/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,6 @@ The `values_list()` can also be combined with `filter`, `only` as per usual.
* **exclude_none** - Boolean flag indicating if the fields with `None` should be excluded.
* **flat** - Boolean flag indicating the results should be flattened.


### Only

Returns the results containing **only** the fields in the query and nothing else.
Expand Down Expand Up @@ -893,6 +892,17 @@ Get a document by the `_id`. This functionality accepts the parameter `id` as st
user = await User.query().get_document_by_id(user.id)
```

### Exists

The `exists()` is used when you want to check if a record exists in the DB or not.

=== "Manager"

```python
await User.objects.exists(email="[email protected]", is_active=False)
await User.objects.filter(email="[email protected]", is_active=False).exists()
```

## Useful methods

### Get or create
Expand Down
164 changes: 82 additions & 82 deletions docs/en/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,96 +6,96 @@ theme:
custom_dir: ../en/overrides
language: en
palette:
- scheme: default
primary: blue grey
accent: red
media: "(prefers-color-scheme: light)"
toggle:
icon: material/lightbulb
name: Switch to dark mode
- scheme: slate
media: "(prefers-color-scheme: dark)"
primary: blue grey
accent: red
toggle:
icon: material/lightbulb-outline
name: Switch to light mode
- scheme: default
primary: blue grey
accent: red
media: '(prefers-color-scheme: light)'
toggle:
icon: material/lightbulb
name: Switch to dark mode
- scheme: slate
media: '(prefers-color-scheme: dark)'
primary: blue grey
accent: red
toggle:
icon: material/lightbulb-outline
name: Switch to light mode
favicon: statics/images/favicon.ico
logo: statics/images/white.png
features:
- search.suggest
- search.highlight
- content.tabs.link
- content.code.copy
- search.suggest
- search.highlight
- content.tabs.link
- content.code.copy
repo_name: dymmond/mongoz
repo_url: https://github.com/dymmond/mongoz
edit_uri: ""
edit_uri: ''
plugins:
- search
- meta-descriptions:
export_csv: false
quiet: false
enable_checks: false
min_length: 50
max_length: 160
trim: false
- mkdocstrings:
handlers:
python:
options:
extensions:
- griffe_typingdoc
show_root_heading: true
show_if_no_docstring: true
preload_modules:
- httpx
- a2wsgi
inherited_members: true
members_order: source
separate_signature: true
unwrap_annotated: true
filters:
- "!^_"
merge_init_into_class: true
docstring_section_style: spacy
signature_crossrefs: true
show_symbol_type_heading: true
show_symbol_type_toc: true
- search
- meta-descriptions:
export_csv: false
quiet: false
enable_checks: false
min_length: 50
max_length: 160
trim: false
- mkdocstrings:
handlers:
python:
options:
extensions:
- griffe_typingdoc
show_root_heading: true
show_if_no_docstring: true
preload_modules:
- httpx
- a2wsgi
inherited_members: true
members_order: source
separate_signature: true
unwrap_annotated: true
filters:
- '!^_'
merge_init_into_class: true
docstring_section_style: spacy
signature_crossrefs: true
show_symbol_type_heading: true
show_symbol_type_toc: true
nav:
- index.md
- documents.md
- embedded-documents.md
- fields.md
- queries.md
- managers.md
- signals.md
- settings.md
- registry.md
- exceptions.md
- tips-and-tricks.md
- contributing.md
- sponsorship.md
- release-notes.md
- index.md
- documents.md
- embedded-documents.md
- fields.md
- queries.md
- managers.md
- signals.md
- settings.md
- registry.md
- exceptions.md
- tips-and-tricks.md
- contributing.md
- sponsorship.md
- release-notes.md
markdown_extensions:
- attr_list
- toc:
permalink: true
- markdown.extensions.codehilite:
guess_lang: false
- mdx_include:
base_path: docs
- admonition
- codehilite
- extra
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- md_in_html
- attr_list
- toc:
permalink: true
- markdown.extensions.codehilite:
guess_lang: false
- mdx_include:
base_path: docs
- admonition
- codehilite
- extra
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- md_in_html
extra:
alternate:
- link: /
name: en - English
- link: /pt/
name: pt - português
- link: /
name: en - English
- link: /pt/
name: pt - português
hooks:
- ../../scripts/hooks.py
- ../../scripts/hooks.py
11 changes: 11 additions & 0 deletions docs/pt/docs/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,17 @@ Obter um documento pelo `_id`. Esta funcionalidade aceita o parâmetro `id` como
user = await User.query().get_document_by_id(user.id)
```

### Exists

O `exists()` é utilizado quando deseja verificar se um registro existe na base de dados ou não.

=== "Manager"

```python
await User.objects.exists(email="[email protected]", is_active=False)
await User.objects.filter(email="[email protected]", is_active=False).exists()
```

## Métodos úteis

### Get or create
Expand Down
12 changes: 12 additions & 0 deletions mongoz/core/db/querysets/core/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,18 @@ async def values_list(
__as_tuple__=True,
)

async def exists(self, **kwargs: Any) -> bool:
"""
Returns a boolean checking if the record exists.
"""
manager: "Manager" = self.clone()
if kwargs:
result = await manager.filter(**kwargs)
return bool(len(result) > 0)

objects = await manager.limit(2).all()
return bool(len(objects) > 0)

async def exclude(self, **kwargs: Any) -> List["Document"]:
"""
Filters everything and excludes based on a specific condition.
Expand Down
53 changes: 53 additions & 0 deletions tests/models/manager/test_decimal_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from decimal import Decimal
from typing import AsyncGenerator, List

import pydantic
import pytest

import mongoz
from tests.conftest import client

pytestmark = pytest.mark.anyio
pydantic_version = pydantic.__version__[:3]


class Badges(mongoz.EmbeddedDocument):
score: Decimal = mongoz.Decimal(max_digits=5, decimal_places=2, null=True)
name: str = mongoz.String()


class Achievement(mongoz.Document):
name: str = mongoz.String()
total_score: Decimal = mongoz.Decimal(max_digits=5, decimal_places=2, null=True) # noqa
badges: List[Badges] = mongoz.Array(Badges, null=True)

class Meta:
registry = client
database = "test_db"


@pytest.fixture(scope="function", autouse=True)
async def prepare_database() -> AsyncGenerator:
await Achievement.objects.delete()
yield
await Achievement.objects.delete()


async def test_decimal_on_update() -> None:
badges = [{"name": "badge1", "score": "32083.33"}]
await Achievement.objects.create(name="Batman", total_score="22.246")

arch = await Achievement.objects.last()

arch.total_score = Decimal("28")
await arch.save()

arch = await Achievement.objects.last()

await arch.update(total_score=Decimal("30"))

arch = await Achievement.objects.last()

await Achievement.objects.filter().update(total_score=Decimal("40"), badges=badges)

arch = await Achievement.objects.last()
55 changes: 55 additions & 0 deletions tests/models/manager/test_exists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import AsyncGenerator, List, Optional

import pydantic
import pytest

import mongoz
from mongoz import Document, Index, IndexType, ObjectId, Order
from tests.conftest import client

pytestmark = pytest.mark.anyio
pydantic_version = pydantic.__version__[:3]

indexes = [
Index("name", unique=True),
Index(keys=[("year", Order.DESCENDING), ("genre", IndexType.HASHED)]),
]


class Movie(Document):
name: str = mongoz.String()
year: int = mongoz.Integer()
tags: Optional[List[str]] = mongoz.Array(str, null=True)
uuid: Optional[ObjectId] = mongoz.ObjectId(null=True)
is_published: bool = mongoz.Boolean(default=False)

class Meta:
registry = client
database = "test_db"
indexes = indexes


@pytest.fixture(scope="function", autouse=True)
async def prepare_database() -> AsyncGenerator:
await Movie.drop_indexes(force=True)
await Movie.objects.delete()
await Movie.create_indexes()
yield
await Movie.drop_indexes(force=True)
await Movie.objects.delete()
await Movie.create_indexes()


async def test_exists_true() -> None:
movies = await Movie.objects.all()
assert len(movies) == 0

await Movie.objects.create(name="Forrest Gump", year=2003, is_published=True)

assert await Movie.objects.exists(name="Forrest Gump") is True
assert await Movie.objects.exists(name="Forrest Gump", year=2003) is True
assert await Movie.objects.exists(name="Forrest Gump", year=2004) is False

assert await Movie.objects.filter(name="Forrest Gump").exists() is True
assert await Movie.objects.filter(name="Forrest Gump", year=2003).exists() is True
assert await Movie.objects.filter(name="Forrest Gump", year=2004).exists() is False

0 comments on commit 8f39368

Please sign in to comment.