From 114191ac6b89d6ca9c3a76314703d3362253e6e8 Mon Sep 17 00:00:00 2001 From: ProdByGodfather Date: Mon, 30 Dec 2024 10:43:13 +0330 Subject: [PATCH] update queryset and add contains for searching in v5.0.2 --- README.md | 56 ++++++++++++++++++++------------------ abarorm/fields/__init__.py | 0 abarorm/psql.py | 36 ++++++++++++++++++++++++ abarorm/sqlite.py | 35 ++++++++++++++++++++++++ setup.py | 2 +- 5 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 abarorm/fields/__init__.py diff --git a/README.md b/README.md index 341eb8a..7be3e34 100644 --- a/README.md +++ b/README.md @@ -142,25 +142,26 @@ To delete a record from the database, use the `delete()` method: ```python Post.delete(1) # Delete the post with ID 1 ``` -### Converting to Dictionary and Counting Records -After performing operations on the model, you can convert records to dictionaries using the `to_dict()` method and count the number of records using the `count()` method. +## Converting to Dictionary, Counting Records, and Other Query Methods -#### `to_dict` Method -The `to_dict()` method converts a model instance into a dictionary, making it easier to manipulate and serialize the data. +This section covers how to convert records to dictionaries, count records, and use various query methods like `first()`, `last()`, `exists()`, `order_by()`, `paginate()`, and `contains()`. These methods are essential for data manipulation, debugging, and optimizing query performance. -**Example:** +### `to_dict()` Method +The `to_dict()` method converts a model instance (or a collection of instances) into a dictionary, which is particularly useful for data manipulation and serialization. It makes it easier to work with the data in Python or send it over an API. + +#### Example: ```python -# Retrieve a post by ID -post = Post.get(id=1) +# Retrieve all posts +posts = Post.all() -# Convert the post to a dictionary -post_dict = post.all().to_dict() -print(post_dict) -# Output: [{'id': 1, 'title': 'Godfather', 'create_time': '2024-01-01 12:00:00', ...}] +# Convert the collection of posts to a list of dictionaries +posts_dict = posts.to_dict() +print(posts_dict) +# Output: [{'id': 1, 'title': 'Godfather', 'create_time': '2024-01-01 12:00:00', ...}, {...}] ``` #### `count` Method -The `count()` method allows you to get the number of records in a model's table. +The `count()` method returns the number of records that match the query. It’s an efficient way to find the size of a dataset without retrieving the actual data. **Example:** ```python @@ -169,11 +170,21 @@ num_posts = Post.count() print(num_posts) # Output: 10 (if there are 10 posts in the database) ``` -#### `first()`, `last()`, `exists()`, `order_by()`, and `paginate()` -- `first():` Returns the first result or None if no results are present. -- `last():` Returns the last result or None if no results are present. -- `exists():` Checks if any records exist in the `QuerySet`. -- `paginate():` Handles pagination of results, allowing you to retrieve subsets of data based on page and page size. +The `count()` method can also be used after applying filters to count specific records: +```python +# Count the number of posts with a specific title +num_posts_with_title = Post.filter(title='Godfather').count() +print(num_posts_with_title) # Output: 3 (if there are 3 posts with the title 'Godfather') +``` + + + +#### `first()`, `last()`, `exists()`, `order_by()`, `paginate()` and `contains()` +- **`first()`**: Returns the first result or `None` if no results are present. +- **`last()`**: Returns the last result or `None` if no results are present. +- **`exists()`**: Checks if any records exist in the `QuerySet`. +- **`paginate()`**: Handles pagination of results, allowing you to retrieve subsets of data based on page and page size. +- **`contains()`**: Performs a case-insensitive search to check if a field contains a specific substring. **Example:** ```python @@ -190,20 +201,11 @@ last_post = Post.all().last() paginated_posts = Post.all().paginate(1, 5) # Page 1, 5 results per page # Using multiple querysets in one query -posts = Post.filter(title='Godfather').order_by('create_time').paginate(1, 4).to_dict() +posts = Post.all().contains(title='god').order_by('create_time').paginate(1, 4).to_dict() ``` These methods are particularly useful for data manipulation and debugging, as they provide a simple way to view and interact with your database records. -## Version 4.2.3 - -- `first():` Added to return the first result in a `QuerySet`. -- `last():` Added to return the last result in a `QuerySet`. -- `exists():` Added to check if any records exist. -- `paginate():` Added to handle pagination for large result sets. - - -**Important for Developers:** When adding new fields to models, they will default to `NULL`. It’s recommended to recreate the database schema after development is complete to ensure fields have appropriate constraints and default values. ## Contributing diff --git a/abarorm/fields/__init__.py b/abarorm/fields/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/abarorm/psql.py b/abarorm/psql.py index f0cd932..87979d0 100644 --- a/abarorm/psql.py +++ b/abarorm/psql.py @@ -73,6 +73,42 @@ def paginate(self, page: int, page_size: int): # Return a new QuerySet with paginated results return self.__class__(paginated_results, self.total_count, page, page_size) + def contains(self, field: str, value) -> 'QuerySet': + """ + Performs a case-insensitive 'contains' search for the given field and value. + Can handle various data types such as strings, numbers, and datetime. + + :param field: The field name (e.g. 'title'). + :param value: The value to search for (e.g. substring for strings or a number). + :return: A new QuerySet with the filtered results. + """ + filtered_results = [] + + for obj in self.results: + field_value = getattr(obj, field, None) + + # If the field's value is a string + if isinstance(field_value, str): + # Perform a case-insensitive substring search + if value.lower() in field_value.lower(): + filtered_results.append(obj) + # If the field's value is a number (int, float) + elif isinstance(field_value, (int, float)): + # Check if the number contains the value as a substring (as string) + if str(value) in str(field_value): + filtered_results.append(obj) + # If the field's value is a datetime or date + elif isinstance(field_value, (datetime, date)): + # Check if the value is a substring of the date (formatted as string) + if str(value) in field_value.strftime('%Y-%m-%d'): + filtered_results.append(obj) + # For other field types, apply an appropriate check (e.g., exact match) + elif field_value == value: + filtered_results.append(obj) + + return self.__class__(filtered_results, len(filtered_results), self.page, self.page_size) + + def __repr__(self): field_values = {attr: getattr(self, attr) for attr in self.__class__.__dict__ if isinstance(self.__class__.__dict__[attr], Field)} diff --git a/abarorm/sqlite.py b/abarorm/sqlite.py index 949f8ae..ef71412 100644 --- a/abarorm/sqlite.py +++ b/abarorm/sqlite.py @@ -72,6 +72,41 @@ def paginate(self, page: int, page_size: int): paginated_results = self.results[offset:offset + page_size] # Return a new QuerySet with paginated results return self.__class__(paginated_results, self.total_count, page, page_size) + + def contains(self, field: str, value) -> 'QuerySet': + """ + Performs a case-insensitive 'contains' search for the given field and value. + Can handle various data types such as strings, numbers, and datetime. + + :param field: The field name (e.g. 'title'). + :param value: The value to search for (e.g. substring for strings or a number). + :return: A new QuerySet with the filtered results. + """ + filtered_results = [] + + for obj in self.results: + field_value = getattr(obj, field, None) + + # If the field's value is a string + if isinstance(field_value, str): + # Perform a case-insensitive substring search + if value.lower() in field_value.lower(): + filtered_results.append(obj) + # If the field's value is a number (int, float) + elif isinstance(field_value, (int, float)): + # Check if the number contains the value as a substring (as string) + if str(value) in str(field_value): + filtered_results.append(obj) + # If the field's value is a datetime or date + elif isinstance(field_value, (datetime, date)): + # Check if the value is a substring of the date (formatted as string) + if str(value) in field_value.strftime('%Y-%m-%d'): + filtered_results.append(obj) + # For other field types, apply an appropriate check (e.g., exact match) + elif field_value == value: + filtered_results.append(obj) + + return self.__class__(filtered_results, len(filtered_results), self.page, self.page_size) diff --git a/setup.py b/setup.py index fab80e0..c094b43 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='abarorm', - version='5.0.0', + version='5.0.2', description='abarorm is a lightweight and easy-to-use Object-Relational Mapping (ORM) library for SQLite and PostgreSQL databases in Python. It aims to provide a simple and intuitive interface for managing database models and interactions.', long_description=open('README.md').read(), long_description_content_type='text/markdown',