{"id":28496303,"url":"https://github.com/geoion/norma","last_synced_at":"2026-04-11T18:03:12.550Z","repository":{"id":296630527,"uuid":"993978045","full_name":"Geoion/Norma","owner":"Geoion","description":"Modern, type-safe Python ORM with dataclass support. Works with PostgreSQL, SQLite, MongoDB, and Cassandra.","archived":false,"fork":false,"pushed_at":"2025-06-01T01:55:49.000Z","size":210,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-08T12:07:11.923Z","etag":null,"topics":["async","cassandra","cli","codegen","dataclass","fastapi","mongodb","orm","postgres","postgresql","pydantic","python","schema-generation","sqlite","tornado","type-safety","validation"],"latest_commit_sha":null,"homepage":"","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/Geoion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-31T23:28:55.000Z","updated_at":"2025-06-01T02:11:33.000Z","dependencies_parsed_at":"2025-06-07T23:02:47.108Z","dependency_job_id":null,"html_url":"https://github.com/Geoion/Norma","commit_stats":null,"previous_names":["geoion/norma"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Geoion/Norma","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geoion%2FNorma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geoion%2FNorma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geoion%2FNorma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geoion%2FNorma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Geoion","download_url":"https://codeload.github.com/Geoion/Norma/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Geoion%2FNorma/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263210389,"owners_count":23431113,"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":["async","cassandra","cli","codegen","dataclass","fastapi","mongodb","orm","postgres","postgresql","pydantic","python","schema-generation","sqlite","tornado","type-safety","validation"],"created_at":"2025-06-08T12:07:14.708Z","updated_at":"2026-04-11T18:03:12.476Z","avatar_url":"https://github.com/Geoion.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Norma ORM\n\nA modern Python ORM framework with dataclass support, providing type-safe database operations across PostgreSQL, SQLite, MongoDB, and Cassandra.\n\n[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![GitHub Stars](https://img.shields.io/github/stars/Geoion/Norma.svg)](https://github.com/Geoion/Norma/stargazers)\n[![GitHub Issues](https://img.shields.io/github/issues/Geoion/Norma.svg)](https://github.com/Geoion/Norma/issues)\n\n## 🚀 Features\n\n- 🎯 **Type-Safe**: Built with modern Python type hints and full mypy support\n- 🏗️ **Dataclass-Based**: Define models using Python dataclasses with automatic validation\n- 🔄 **Multi-Database**: Unified interface for PostgreSQL, SQLite, MongoDB, and Cassandra\n- 📊 **Schema Generation**: Automatic Pydantic schema generation for APIs\n- ⚡ **Async/Sync**: Support for both asynchronous and synchronous operations\n- 🛠️ **CLI Tools**: Powerful command-line interface for project initialization and code generation\n- 🔍 **Query Builder**: Intuitive query syntax with support for complex filters\n- 🔒 **Validation**: Built-in field validation with customizable constraints\n- 📖 **Relationships**: Support for one-to-one, one-to-many, and many-to-many relationships\n- 🎨 **Developer Experience**: Rich error messages and comprehensive debugging tools\n\n## 📋 Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Models](#models)\n- [Database Operations](#database-operations)\n- [Schema Generation](#schema-generation)\n- [CLI Tools](#cli-tools)\n- [Configuration](#configuration)\n- [Advanced Usage](#advanced-usage)\n- [API Reference](#api-reference)\n- [Examples](#examples)\n- [Contributing](#contributing)\n- [License](#license)\n\n## 📦 Installation\n\n### Basic Installation\n\n```bash\npip install norma-orm\n```\n\n### Database-Specific Dependencies\n\n```bash\n# For PostgreSQL support\npip install norma-orm[postgres]\n\n# For Cassandra support\npip install norma-orm[cassandra]\n\n# For all development tools\npip install norma-orm[dev]\n\n# For CLI tools with rich output\npip install norma-orm[cli]\n\n# Install everything\npip install norma-orm[postgres,cassandra,dev,cli]\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/Geoion/Norma.git\ncd Norma\npip install -e .\n```\n\n## ⚡ Quick Start\n\n### 1. Define Your Models\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\nfrom datetime import datetime\nfrom norma import BaseModel, Field\n\n@dataclass\nclass User(BaseModel):\n    # Primary key with auto-generation\n    id: str = Field(\n        primary_key=True,\n        default_factory=lambda: __import__('uuid').uuid4().hex,\n        description=\"Unique user identifier\"\n    )\n    \n    # Required fields with validation\n    name: str = Field(\n        max_length=100,\n        min_length=1,\n        index=True,\n        description=\"User's full name\"\n    )\n    \n    email: str = Field(\n        unique=True,\n        max_length=255,\n        regex_pattern=r\"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\",\n        description=\"User's email address\"\n    )\n    \n    # Optional fields with defaults\n    age: int = Field(\n        default=0,\n        min_value=0,\n        max_value=150,\n        description=\"User's age in years\"\n    )\n    \n    is_active: bool = Field(\n        default=True,\n        index=True,\n        description=\"Whether the user account is active\"\n    )\n    \n    created_at: Optional[datetime] = Field(\n        default_factory=datetime.now,\n        description=\"Account creation timestamp\"\n    )\n```\n\n### 2. Initialize the Client\n\n```python\nfrom norma import NormaClient\n\n# SQLite (for development)\nclient = NormaClient(\n    adapter_type=\"sql\",\n    database_url=\"sqlite:///./app.db\"\n)\n\n# PostgreSQL (for production)\nclient = NormaClient(\n    adapter_type=\"sql\",\n    database_url=\"postgresql://user:password@localhost:5432/mydb\"\n)\n\n# MongoDB\nclient = NormaClient(\n    adapter_type=\"mongo\",\n    database_url=\"mongodb://localhost:27017\",\n    database_name=\"myapp\"\n)\n\n# Cassandra\nclient = NormaClient(\n    adapter_type=\"cassandra\",\n    database_url=\"127.0.0.1\",\n    keyspace=\"myapp_keyspace\"\n)\n```\n\n### 3. Basic CRUD Operations\n\n```python\nimport asyncio\n\nasync def main():\n    async with client:\n        # Get model client\n        user_client = client.get_model_client(User)\n        \n        # Create table/collection\n        await user_client.create_table()\n        \n        # Create a user\n        user = User(\n            name=\"John Doe\",\n            email=\"john@example.com\",\n            age=30\n        )\n        created_user = await user_client.insert(user)\n        print(f\"Created: {created_user}\")\n        \n        # Find by ID\n        found_user = await user_client.find_by_id(created_user.id)\n        print(f\"Found: {found_user}\")\n        \n        # Update user\n        found_user.age = 31\n        updated_user = await user_client.update(found_user)\n        print(f\"Updated: {updated_user}\")\n        \n        # Query users\n        adults = await user_client.find_many({\"age\": {\"$gte\": 18}})\n        print(f\"Adults: {len(adults)}\")\n        \n        # Delete user\n        deleted = await user_client.delete_by_id(created_user.id)\n        print(f\"Deleted: {deleted}\")\n\n# Run the example\nasyncio.run(main())\n```\n\n## 🏗️ Models\n\n### Defining Models\n\nModels in Norma are Python dataclasses that inherit from `BaseModel`:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional, List\nfrom norma import BaseModel, Field, OneToMany, ManyToOne\n\n@dataclass\nclass Author(BaseModel):\n    id: str = Field(primary_key=True, default_factory=lambda: __import__('uuid').uuid4().hex)\n    name: str = Field(max_length=100, index=True)\n    email: str = Field(unique=True)\n    bio: Optional[str] = Field(max_length=1000, default=None)\n\n@dataclass\nclass Post(BaseModel):\n    id: str = Field(primary_key=True, default_factory=lambda: __import__('uuid').uuid4().hex)\n    title: str = Field(max_length=200, index=True)\n    content: str = Field(min_length=1)\n    published: bool = Field(default=False, index=True)\n    \n    # Foreign key relationship\n    author_id: str = Field(\n        relationship=ManyToOne(\"Author\", foreign_key=\"id\"),\n        description=\"ID of the post author\"\n    )\n    \n    created_at: datetime = Field(default_factory=datetime.now, index=True)\n```\n\n### Field Configuration\n\nThe `Field()` function provides extensive configuration options:\n\n```python\nfrom norma import Field\n\n# Basic field types\nname: str = Field()  # Simple string field\nage: int = Field(default=0)  # With default value\nactive: bool = Field(default=True)\n\n# Validation constraints\nemail: str = Field(\n    unique=True,                    # Unique constraint\n    max_length=255,                 # Maximum string length\n    min_length=5,                   # Minimum string length\n    regex_pattern=r\"^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$\"  # Regex validation\n)\n\nprice: float = Field(\n    min_value=0.0,                  # Minimum numeric value\n    max_value=999999.99,            # Maximum numeric value\n    default=0.0\n)\n\n# Database options\nuser_id: str = Field(\n    primary_key=True,               # Primary key\n    index=True,                     # Create database index\n    nullable=False,                 # Not nullable\n    db_column_name=\"user_uuid\",     # Custom column name\n    db_type=\"UUID\"                  # Custom database type\n)\n\n# Documentation\ndescription: str = Field(\n    max_length=500,\n    description=\"User-friendly field description\"\n)\n```\n\n### Relationships\n\nNorma supports various relationship types:\n\n```python\nfrom norma import OneToOne, OneToMany, ManyToOne, ManyToMany\n\n@dataclass\nclass User(BaseModel):\n    id: str = Field(primary_key=True)\n    name: str = Field()\n\n@dataclass\nclass Profile(BaseModel):\n    id: str = Field(primary_key=True)\n    user_id: str = Field(relationship=OneToOne(\"User\"))\n    bio: str = Field()\n\n@dataclass\nclass Post(BaseModel):\n    id: str = Field(primary_key=True)\n    author_id: str = Field(relationship=ManyToOne(\"User\"))\n    title: str = Field()\n\n@dataclass\nclass Tag(BaseModel):\n    id: str = Field(primary_key=True)\n    name: str = Field()\n    post_ids: List[str] = Field(relationship=ManyToMany(\"Post\"))\n```\n\n## 💾 Database Operations\n\n### Basic CRUD\n\n```python\n# Create\nuser = User(name=\"Alice\", email=\"alice@example.com\")\ncreated_user = await user_client.insert(user)\n\n# Read\nuser = await user_client.find_by_id(\"user_id\")\nusers = await user_client.find_many()\n\n# Update\nuser.age = 25\nupdated_user = await user_client.update(user)\n\n# Delete\ndeleted = await user_client.delete_by_id(\"user_id\")\n```\n\n### Advanced Queries\n\n```python\n# Filter by single field\nactive_users = await user_client.find_many({\"is_active\": True})\n\n# Multiple filters\nadult_active_users = await user_client.find_many({\n    \"age\": {\"$gte\": 18},\n    \"is_active\": True\n})\n\n# Comparison operators\nusers = await user_client.find_many({\n    \"age\": {\"$gte\": 18, \"$lte\": 65},  # Between 18 and 65\n    \"name\": {\"$ne\": \"Admin\"},         # Not equal to \"Admin\"\n    \"email\": {\"$in\": [\"user1@test.com\", \"user2@test.com\"]}  # In list\n})\n\n# Pagination and sorting\nusers = await user_client.find_many(\n    filters={\"is_active\": True},\n    limit=10,\n    offset=20,\n    order_by=[\"-created_at\", \"name\"]  # Desc by created_at, asc by name\n)\n\n# Count records\ntotal_users = await user_client.count()\nactive_users_count = await user_client.count({\"is_active\": True})\n\n# Check existence\nuser_exists = await user_client.exists({\"email\": \"test@example.com\"})\n```\n\n### Synchronous Operations\n\nFor scenarios where you need synchronous operations:\n\n```python\n# Synchronous client usage\nwith client:\n    user_client = client.get_model_client(User)\n    \n    # Synchronous operations\n    user = User(name=\"Sync User\", email=\"sync@example.com\")\n    created_user = user_client.insert_sync(user)\n    \n    found_user = user_client.find_by_id_sync(created_user.id)\n    \n    users = user_client.find_many_sync({\"is_active\": True})\n```\n\n## 📊 Schema Generation\n\nNorma automatically generates Pydantic schemas for API integration:\n\n```python\nfrom norma.schema import generate_schemas\n\n# Generate all schemas\nschemas = generate_schemas(User)\n\nCreateUserSchema = schemas['create']  # For input validation\nReadUserSchema = schemas['read']      # For output serialization  \nUpdateUserSchema = schemas['update']  # For partial updates\n\n# Use with FastAPI\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n@app.post(\"/users/\", response_model=ReadUserSchema)\nasync def create_user(user_data: CreateUserSchema):\n    # Convert schema to model\n    user = User.from_dict(user_data.model_dump())\n    created_user = await user_client.insert(user)\n    return created_user.to_dict()\n\n@app.patch(\"/users/{user_id}\", response_model=ReadUserSchema)\nasync def update_user(user_id: str, user_data: UpdateUserSchema):\n    # Find existing user\n    user = await user_client.find_by_id(user_id)\n    if not user:\n        raise HTTPException(status_code=404)\n    \n    # Apply updates\n    update_data = user_data.model_dump(exclude_none=True)\n    user.update(**update_data)\n    \n    updated_user = await user_client.update(user)\n    return updated_user.to_dict()\n```\n\n## 🛠️ CLI Tools\n\n### Project Initialization\n\n```bash\n# Create a new project\nnorma init my-project\n\n# With specific template and database\nnorma init my-project --template fastapi --database postgresql\n\n# Available templates: basic, fastapi, django\n# Available databases: sqlite, postgresql, mongodb, cassandra\n```\n\nThis creates a complete project structure:\n\n```\nmy-project/\n├── models/\n│   ├── __init__.py\n│   ├── user.py\n│   └── post.py\n├── schemas/\n│   └── __init__.py\n├── config/\n│   ├── __init__.py\n│   └── database.py\n├── main.py\n├── requirements.txt\n└── README.md\n```\n\n### Schema Generation\n\n```bash\n# Generate Pydantic schemas from models\nnorma generate --models ./models --output ./schemas\n\n# Watch for changes and auto-regenerate\nnorma generate --models ./models --output ./schemas --watch\n\n# Different output formats\nnorma generate --models ./models --output ./schemas --format pydantic\n```\n\n### Version Information\n\n```bash\nnorma version\n```\n\n## ⚙️ Configuration\n\n### Database Configuration\n\n```python\n# config/database.py\nimport os\n\nDATABASE_CONFIG = {\n    \"type\": \"postgresql\",\n    \"url\": os.getenv(\"DATABASE_URL\", \"postgresql://user:pass@localhost/db\"),\n    \"echo\": os.getenv(\"DB_ECHO\", \"false\").lower() == \"true\",\n    \"pool_size\": int(os.getenv(\"DB_POOL_SIZE\", \"5\")),\n    \"max_overflow\": int(os.getenv(\"DB_MAX_OVERFLOW\", \"10\")),\n}\n\n# For MongoDB\nMONGODB_CONFIG = {\n    \"url\": os.getenv(\"MONGODB_URL\", \"mongodb://localhost:27017\"),\n    \"database_name\": os.getenv(\"MONGODB_DB\", \"myapp\"),\n    \"server_selection_timeout\": 5000,\n    \"max_pool_size\": 100,\n}\n```\n\n### Environment Variables\n\n```bash\n# .env file\nDATABASE_URL=postgresql://user:password@localhost:5432/mydb\nDB_ECHO=false\nDB_POOL_SIZE=10\nDB_MAX_OVERFLOW=20\n\n# For MongoDB\nMONGODB_URL=mongodb://localhost:27017\nMONGODB_DB=myapp\n\n# For Cassandra\nCASSANDRA_HOSTS=127.0.0.1,127.0.0.2,127.0.0.3\nCASSANDRA_KEYSPACE=myapp_keyspace\nCASSANDRA_PORT=9042\nCASSANDRA_USERNAME=cassandra\nCASSANDRA_PASSWORD=cassandra\n```\n\n### Client Configuration\n\n```python\n# Advanced client configuration\nclient = NormaClient(\n    adapter_type=\"sql\",\n    database_url=\"postgresql://user:pass@localhost/db\",\n    echo=True,              # Log SQL queries\n    pool_size=10,           # Connection pool size\n    max_overflow=20,        # Max overflow connections\n    pool_timeout=30,        # Pool timeout in seconds\n    pool_recycle=3600,      # Recycle connections after 1 hour\n)\n\n# Cassandra client configuration\ncassandra_client = NormaClient(\n    adapter_type=\"cassandra\",\n    database_url=\"127.0.0.1,127.0.0.2,127.0.0.3\",\n    keyspace=\"myapp_keyspace\",\n    port=9042,\n    username=\"cassandra\",\n    password=\"cassandra\",\n    protocol_version=4,\n    connect_timeout=10,\n    request_timeout=10,\n)\n```\n\n## 🚀 Advanced Usage\n\n### Custom Validation\n\n```python\nfrom norma.exceptions import ValidationError\n\n@dataclass\nclass User(BaseModel):\n    email: str = Field(unique=True)\n    age: int = Field(min_value=0, max_value=150)\n    \n    def __post_init__(self):\n        super().__post_init__()  # Call parent validation\n        \n        # Custom validation logic\n        if self.age \u003c 13 and \"@\" not in self.email:\n            raise ValidationError(\"Users under 13 must have a valid email\")\n        \n        # Domain-specific validation\n        if self.email.endswith(\"@competitor.com\"):\n            raise ValidationError(\"Competitor emails not allowed\")\n```\n\n### Error Handling\n\n```python\nfrom norma.exceptions import (\n    NormaError, ValidationError, NotFoundError, \n    DuplicateError, ConnectionError\n)\n\ntry:\n    user = User(name=\"\", email=\"invalid-email\")  # Will raise ValidationError\n    await user_client.insert(user)\nexcept ValidationError as e:\n    print(f\"Validation failed: {e.message}\")\n    print(f\"Field: {e.field}, Value: {e.value}\")\n\nexcept DuplicateError as e:\n    print(f\"Duplicate entry: {e.message}\")\n\nexcept NotFoundError as e:\n    print(f\"Not found: {e.message}\")\n\nexcept ConnectionError as e:\n    print(f\"Database connection failed: {e.message}\")\n\nexcept NormaError as e:\n    print(f\"Norma error: {e.message}\")\n    print(f\"Details: {e.details}\")\n```\n\n## 📚 API Reference\n\n### BaseModel\n\nThe base class for all Norma models.\n\n```python\nclass BaseModel:\n    def validate(self) -\u003e None:\n        \"\"\"Validate the model according to field configurations.\"\"\"\n    \n    def to_dict(self, exclude_none: bool = True, exclude_private: bool = True) -\u003e Dict[str, Any]:\n        \"\"\"Convert model to dictionary.\"\"\"\n    \n    @classmethod\n    def from_dict(cls, data: Dict[str, Any]) -\u003e 'BaseModel':\n        \"\"\"Create model from dictionary.\"\"\"\n    \n    def update(self, **kwargs) -\u003e None:\n        \"\"\"Update model fields with validation.\"\"\"\n    \n    @classmethod\n    def get_primary_key_field(cls) -\u003e Optional[str]:\n        \"\"\"Get the primary key field name.\"\"\"\n    \n    @classmethod\n    def get_unique_fields(cls) -\u003e List[str]:\n        \"\"\"Get all unique field names.\"\"\"\n    \n    def is_persisted(self) -\u003e bool:\n        \"\"\"Check if model has been saved to database.\"\"\"\n```\n\n### NormaClient\n\nMain client for database operations.\n\n```python\nclass NormaClient:\n    def __init__(self, adapter_type: str, database_url: str, **kwargs):\n        \"\"\"Initialize client with database configuration.\"\"\"\n    \n    async def connect(self) -\u003e None:\n        \"\"\"Connect to database.\"\"\"\n    \n    async def disconnect(self) -\u003e None:\n        \"\"\"Disconnect from database.\"\"\"\n    \n    def get_model_client(self, model_class: Type[BaseModel]) -\u003e ModelClient:\n        \"\"\"Get client for specific model.\"\"\"\n    \n    # Context manager support\n    async def __aenter__(self): ...\n    async def __aexit__(self, exc_type, exc_val, exc_tb): ...\n```\n\n### ModelClient\n\nClient for operations on a specific model.\n\n```python\nclass ModelClient:\n    async def insert(self, model: BaseModel) -\u003e BaseModel:\n        \"\"\"Insert new record.\"\"\"\n    \n    async def update(self, model: BaseModel) -\u003e BaseModel:\n        \"\"\"Update existing record.\"\"\"\n    \n    async def find_by_id(self, id_value: Any) -\u003e Optional[BaseModel]:\n        \"\"\"Find record by primary key.\"\"\"\n    \n    async def find_many(self, filters: Dict = None, limit: int = None, \n                       offset: int = None, order_by: List[str] = None) -\u003e List[BaseModel]:\n        \"\"\"Find multiple records.\"\"\"\n    \n    async def delete_by_id(self, id_value: Any) -\u003e bool:\n        \"\"\"Delete record by primary key.\"\"\"\n    \n    async def count(self, filters: Dict = None) -\u003e int:\n        \"\"\"Count matching records.\"\"\"\n    \n    async def exists(self, filters: Dict) -\u003e bool:\n        \"\"\"Check if records exist.\"\"\"\n```\n\n## 🔧 Troubleshooting\n\n### Common Issues\n\n1. **Import Errors**\n   ```bash\n   pip install norma-orm[dev]  # Make sure all dependencies are installed\n   ```\n\n2. **Database Connection Issues**\n   ```python\n   # Test your connection string\n   client = NormaClient(adapter_type=\"sql\", database_url=\"your_url_here\")\n   try:\n       await client.connect()\n       print(\"Connection successful!\")\n   except ConnectionError as e:\n       print(f\"Connection failed: {e}\")\n   ```\n\n3. **Validation Errors**\n   ```python\n   # Enable detailed error reporting\n   import logging\n   logging.getLogger('norma').setLevel(logging.DEBUG)\n   ```\n\n4. **Performance Issues**\n   ```python\n   # Optimize queries with indexes\n   name: str = Field(index=True)  # Add indexes to frequently queried fields\n   \n   # Use pagination for large datasets\n   users = await user_client.find_many(limit=100, offset=0)\n   ```\n\n## 🤝 Contributing\n\nWe welcome contributions! Here's how you can help:\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/Geoion/Norma.git\ncd Norma\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate  # On Windows: venv\\Scripts\\activate\n\n# Install development dependencies\npip install -e .[dev]\n\n# Run tests\npytest\n\n# Run linting\nblack .\nisort .\nmypy norma/\n```\n\n### Contribution Guidelines\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Write** tests for your changes\n4. **Ensure** tests pass and code is formatted\n5. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n6. **Push** to your branch (`git push origin feature/amazing-feature`)\n7. **Open** a Pull Request\n\n### Reporting Issues\n\nWhen reporting issues, please include:\n\n- Python version\n- Norma version (`norma version`)\n- Database type and version\n- Minimal code example\n- Full error traceback\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeoion%2Fnorma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeoion%2Fnorma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeoion%2Fnorma/lists"}