{"id":20845774,"url":"https://github.com/adriamontoto/criteria-pattern","last_synced_at":"2026-05-19T00:10:25.318Z","repository":{"id":252845968,"uuid":"841628645","full_name":"adriamontoto/criteria-pattern","owner":"adriamontoto","description":"The Criteria Pattern is a Python 🐍 package that simplifies and standardizes criteria based filtering 🤏🏻, validation and selection.","archived":false,"fork":false,"pushed_at":"2025-05-02T16:48:13.000Z","size":141,"stargazers_count":4,"open_issues_count":9,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-06T12:16:37.534Z","etag":null,"topics":["criteria","development","filtering","pattern","python","python3","python311","python312","python313","selection","sql","tools","utilities","validation"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/criteria-pattern/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adriamontoto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-12T19:40:53.000Z","updated_at":"2025-03-16T13:05:49.000Z","dependencies_parsed_at":"2024-08-12T23:18:16.039Z","dependency_job_id":"37198685-30e5-4e13-a181-658da2dc94d8","html_url":"https://github.com/adriamontoto/criteria-pattern","commit_stats":null,"previous_names":["adriamontoto/criteria-pattern"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adriamontoto%2Fcriteria-pattern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adriamontoto%2Fcriteria-pattern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adriamontoto%2Fcriteria-pattern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adriamontoto%2Fcriteria-pattern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adriamontoto","download_url":"https://codeload.github.com/adriamontoto/criteria-pattern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253180806,"owners_count":21866987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["criteria","development","filtering","pattern","python","python3","python311","python312","python313","selection","sql","tools","utilities","validation"],"created_at":"2024-11-18T02:13:54.367Z","updated_at":"2026-05-19T00:10:25.309Z","avatar_url":"https://github.com/adriamontoto.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n# 🤏🏻 Criteria Pattern\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/adriamontoto/criteria-pattern/actions/workflows/ci.yaml?event=push\u0026branch=master\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://github.com/adriamontoto/criteria-pattern/actions/workflows/ci.yaml/badge.svg?event=push\u0026branch=master\" alt=\"CI Pipeline\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/criteria-pattern\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/criteria-pattern.svg\" alt=\"Coverage Pipeline\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/criteria-pattern\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/pypi/v/criteria-pattern?color=%2334D058\u0026label=pypi%20package\" alt=\"Package Version\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/criteria-pattern/\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/pypi/pyversions/criteria-pattern.svg?color=%2334D058\" alt=\"Supported Python Versions\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pepy.tech/projects/criteria-pattern\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://static.pepy.tech/badge/criteria-pattern/month\" alt=\"Package Downloads\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://deepwiki.com/adriamontoto/criteria-pattern\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/DeepWiki-adriamontoto%2Fcriteria--pattern-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==\" alt=\"Project Documentation\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nThe **Criteria Pattern** is a Python 🐍 package that simplifies and standardizes criteria based filtering 🤏🏻, validation and selection. This package provides a set of prebuilt 👷🏻 objects and utilities that you can drop into your existing projects and not have to implement yourself.\n\nThese utilities 🛠️ are useful when you need complex filtering logic. It also enforces 👮🏻 best practices so all your filtering processes follow a uniform standard.\n\nEasy to install and integrate, this is a must have for any Python developer looking to simplify their workflow, enforce design patterns and use the full power of modern ORMs and SQL 🗄️ in their projects 🚀.\n\u003cbr\u003e\u003cbr\u003e\n\n## Table of Contents\n\n- [📥 Installation](#installation)\n- [📚 Documentation](#documentation)\n- [💻 Utilization](#utilization)\n  - [🔄 Available Converters](#available-converters)\n  - [🔎 Simple URL Query Examples](#simple-url-query-examples)\n  - [🎯 Real-Life Case: Multi-tenant User Search Service](#real-life-case)\n- [🤝 Contributing](#contributing)\n- [🔑 License](#license)\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\u003cbr\u003e\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n\n## 📥 Installation\n\nYou can install **Criteria Pattern** using `pip`:\n\n```bash\npip install criteria-pattern\n```\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\u003cbr\u003e\n\n\u003ca name=\"documentation\"\u003e\u003c/a\u003e\n\n## 📚 Documentation\n\nThis [project's documentation](https://deepwiki.com/adriamontoto/criteria-pattern) is powered by DeepWiki, which provides a comprehensive overview of the **Criteria Pattern** and its usage.\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\u003cbr\u003e\n\n\u003ca name=\"utilization\"\u003e\u003c/a\u003e\n\n## 💻 Utilization\n\n```python\nfrom criteria_pattern import Criteria, Filter, Operator\nfrom criteria_pattern.converters import CriteriaToPostgresqlConverter\n\nis_adult = Criteria(filters=[Filter(field='age', operator=Operator.GREATER_OR_EQUAL, value=18)])\nemail_is_gmail = Criteria(filters=[Filter(field='email', operator=Operator.ENDS_WITH, value='@gmail.com')])\nemail_is_yahoo = Criteria(filters=[Filter(field='email', operator=Operator.ENDS_WITH, value='@yahoo.com')])\n\nquery, parameters = CriteriaToPostgresqlConverter.convert(criteria=is_adult \u0026 (email_is_gmail | email_is_yahoo), table='user')\nprint(query)\nprint(parameters)\n# \u003e\u003e\u003e SELECT * FROM user WHERE (age \u003e= %(parameter_0)s AND (email LIKE '%%' || %(parameter_1)s OR email LIKE '%%' || %(parameter_2)s));\n# \u003e\u003e\u003e {'parameter_0': 18, 'parameter_1': '@gmail.com', 'parameter_2': '@yahoo.com'}\n```\n\n\u003ca name=\"available-converters\"\u003e\u003c/a\u003e\n\n### 🔄 Available Converters\n\nThe package includes converters for SQL generation and request parsing:\n\n- [`criteria_pattern.converters.CriteriaToPostgresqlConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/criteria_to_postgresql_converter.py): Converts a `Criteria` object into PostgreSQL SQL + parameters.\n- [`criteria_pattern.converters.CriteriaToMysqlConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/criteria_to_mysql_converter.py): Converts a `Criteria` object into MySQL SQL + parameters.\n- [`criteria_pattern.converters.CriteriaToMariadbConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/criteria_to_mariadb_converter.py): Converts a `Criteria` object into MariaDB SQL + parameters.\n- [`criteria_pattern.converters.CriteriaToSqliteConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/criteria_to_sqlite_converter.py): Converts a `Criteria` object into SQLite SQL + parameters.\n- [`criteria_pattern.converters.SimpleUrlToCriteriaConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/simple_url_to_criteria_converter.py): Parses simple public URL query parameters into a `Criteria` object.\n- [`criteria_pattern.converters.UrlToCriteriaConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/url_to_criteria_converter.py): Parses URL query parameters into a `Criteria` object.\n- [`criteria_pattern.converters.BodyToCriteriaConverter`](https://github.com/adriamontoto/criteria-pattern/blob/master/criteria_pattern/converters/body_to_criteria_converter.py): Parses decoded request bodies into a `Criteria` object.\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ca name=\"real-life-case\"\u003e\u003c/a\u003e\n\n### 🎯 Real-Life Case: Multi-tenant User Search Service\n\nImagine an admin dashboard where each request must:\n\n1. Always restrict results to the current tenant.\n2. Optionally filter active users.\n3. Search only users with company emails.\n4. Sort by newest users first.\n\nWith Criteria Pattern, each concern is a small reusable criteria object. You combine them using `\u0026` and `|`, then convert once to SQL:\n\n```python\nfrom criteria_pattern import Criteria, Direction, Filter, Operator, Order\nfrom criteria_pattern.converters import CriteriaToPostgresqlConverter\n\n\nclass UserSearchService:\n    def __init__(self, tenant_id: str) -\u003e None:\n        self.tenant_id = tenant_id\n\n    def build_query(self, *, only_active: bool, corporate_domain: str) -\u003e tuple[str, dict[str, object]]:\n        tenant_scope = Criteria(filters=[Filter(field='tenant_id', operator=Operator.EQUAL, value=self.tenant_id)])\n        active_scope = Criteria(filters=[Filter(field='is_active', operator=Operator.EQUAL, value=True)])\n        email_scope = Criteria(filters=[Filter(field='email', operator=Operator.ENDS_WITH, value=corporate_domain)])\n        sort_scope = Criteria(orders=[Order(field='created_at', direction=Direction.DESC)])\n\n        criteria = tenant_scope \u0026 email_scope \u0026 sort_scope\n        if only_active:\n            criteria = criteria \u0026 active_scope\n\n        return CriteriaToPostgresqlConverter.convert(criteria=criteria, table='users')\n\n\nservice = UserSearchService(tenant_id='tenant_123')\nquery, parameters = service.build_query(only_active=True, corporate_domain='@acme.com')\n\nprint(query)\nprint(parameters)\n```\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\u003cbr\u003e\n\n\u003ca name=\"simple-url-query-examples\"\u003e\u003c/a\u003e\n\n### 🔎 Simple URL Query Examples\n\nUse `SimpleUrlToCriteriaConverter` when you want a compact public query format where each parameter becomes one `AND` filter. Plain parameters use equality, and suffixes map to operators.\n\n```python\nfrom criteria_pattern.converters import SimpleUrlToCriteriaConverter\n\n\ncriteria = SimpleUrlToCriteriaConverter.convert(\n    url='https://api.example.com/users?name=Doe\u0026age_gte=18\u0026page_size=20\u0026page_number=1'\n)\n\nprint(criteria.filters[0].field, criteria.filters[0].operator, criteria.filters[0].value)\n# \u003e\u003e\u003e name EQUAL Doe\n\nprint(criteria.filters[1].field, criteria.filters[1].operator, criteria.filters[1].value)\n# \u003e\u003e\u003e age GREATER_OR_EQUAL 18\n\nprint(criteria.page_size, criteria.page_number)\n# \u003e\u003e\u003e 20 1\n```\n\nCommon suffixes:\n\n| URL parameter | Parsed filter |\n| --- | --- |\n| `name=Doe` | `Filter(field='name', operator=Operator.EQUAL, value='Doe')` |\n| `name_eq=Doe` | `Filter(field='name', operator=Operator.EQUAL, value='Doe')` |\n| `status_ne=DELETED` | `Filter(field='status', operator=Operator.NOT_EQUAL, value='DELETED')` |\n| `price_gt=10` | `Filter(field='price', operator=Operator.GREATER, value=10)` |\n| `price_gte=10` | `Filter(field='price', operator=Operator.GREATER_OR_EQUAL, value=10)` |\n| `price_lt=100` | `Filter(field='price', operator=Operator.LESS, value=100)` |\n| `price_lte=100` | `Filter(field='price', operator=Operator.LESS_OR_EQUAL, value=100)` |\n| `email_contains=gmail.com` | `Filter(field='email', operator=Operator.CONTAINS, value='gmail.com')` |\n| `name_starts_with=Ad` | `Filter(field='name', operator=Operator.STARTS_WITH, value='Ad')` |\n| `email_ends_with=.com` | `Filter(field='email', operator=Operator.ENDS_WITH, value='.com')` |\n| `status_in=ACTIVE\u0026status_in=PENDING` | `Filter(field='status', operator=Operator.IN, value=['ACTIVE', 'PENDING'])` |\n| `status_not_in=DELETED` | `Filter(field='status', operator=Operator.NOT_IN, value=['DELETED'])` |\n| `deleted_at_is_null=true` | `Filter(field='deleted_at', operator=Operator.IS_NULL, value=None)` |\n| `deleted_at_is_not_null=true` | `Filter(field='deleted_at', operator=Operator.IS_NOT_NULL, value=None)` |\n\nComma-separated values are also supported for list operators:\n\n```python\ncriteria = SimpleUrlToCriteriaConverter.convert(\n    url='https://api.example.com/users?status_in=ACTIVE,PENDING,BLOCKED'\n)\n\nprint(criteria.filters[0].value)\n# \u003e\u003e\u003e ['ACTIVE', 'PENDING', 'BLOCKED']\n```\n\nYou can map public field names to internal field names:\n\n```python\ncriteria = SimpleUrlToCriteriaConverter.convert(\n    url='https://api.example.com/users?full_name_contains=Doe',\n    fields_mapping={'full_name': 'name'},\n)\n\nprint(criteria.filters[0].field, criteria.filters[0].operator, criteria.filters[0].value)\n# \u003e\u003e\u003e name CONTAINS Doe\n```\n\nYou can also extend or override URL suffixes:\n\n```python\ncriteria = SimpleUrlToCriteriaConverter.convert(\n    url='https://api.example.com/users?created_at_after=2026-05-18',\n    suffix_operator_mapping={'after': Operator.GREATER},\n)\n\nprint(criteria.filters[0].field, criteria.filters[0].operator, criteria.filters[0].value)\n# \u003e\u003e\u003e created_at GREATER 2026-05-18\n```\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ca name=\"contributing\"\u003e\u003c/a\u003e\n\n## 🤝 Contributing\n\nWe love community help! Before you open an issue or pull request, please read:\n\n- [`🤝 How to Contribute`](https://github.com/adriamontoto/criteria-pattern/blob/master/.github/CONTRIBUTING.md)\n- [`🧭 Code of Conduct`](https://github.com/adriamontoto/criteria-pattern/blob/master/.github/CODE_OF_CONDUCT.md)\n- [`🔐 Security Policy`](https://github.com/adriamontoto/criteria-pattern/blob/master/.github/SECURITY.md)\n\n_Thank you for helping make **🤏🏻 Criteria Pattern** package awesome! 🌟_\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\u003cbr\u003e\n\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n\n## 🔑 License\n\nThis project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/criteria-pattern/blob/master/LICENSE.md).\n\n\u003cp align=\"right\"\u003e\n    \u003ca href=\"#readme-top\"\u003e🔼 Back to top\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadriamontoto%2Fcriteria-pattern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadriamontoto%2Fcriteria-pattern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadriamontoto%2Fcriteria-pattern/lists"}