A powerful CLI tool that generates type-safe, production-ready Dart and Python models from Appwrite configuration JSON files. Streamline your Appwrite development workflow by automatically generating models, enums, and attribute constants directly from your database schema.
- π Python/Pydantic Models: Generate production-ready Pydantic v2 models
- π― Dart Models: Generate type-safe Dart classes with full null safety
- π Generate Both: Create Dart and Python models simultaneously
- π Complete Serialization: Automatic JSON serialization/deserialization
- π Enum Support: Creates proper enums from enum-type columns
- π Attribute Constants: Type-safe property access with generated constants
- β
Schema Validation: Respects
required,max_length,min/maxconstraints - π Relationship Support: Handles one-to-one, one-to-many, many-to-one, and many-to-many relationships
- π¦ Well-Organized Output: Models organized by collection with clear structure
- β‘ Fast & Efficient: Quickly generates all models with a single command
- π Appwrite Metadata: Include
$id,$createdAt,$updatedAtand more - βοΈ Equatable Support (Dart): Optional
Equatablemixin for easy comparisons - βοΈ Validation Helpers: Schema-based validation methods and decorators
- π Watch Mode: Auto-regenerate on file changes
- π¨ Auto-Formatting: Format Dart (dart format) and Python (black) automatically
Clone the repository and activate locally:
git clone https://github.com/moinsen-dev/appwrite_generator.git
cd appwrite_generator
dart pub global activate --source=path .Once published on pub.dev:
dart pub global activate appwrite_generator- Dart SDK 3.9.0 or higher
- An
appwrite.jsonconfiguration file from your Appwrite project
# Generate Dart models from appwrite.json (default)
$ appwrite_generator generate
# Generate Python/Pydantic models
$ appwrite_generator generate --config appwrite_generator.yaml # with target: python
# Generate both Dart and Python models
$ appwrite_generator generate --config appwrite_generator.yaml # with target: both
# Specify custom input and output paths
$ appwrite_generator generate --input my_config.json --output lib/generated
# Watch for changes and auto-regenerate (v0.2.0)
$ appwrite_generator watch
# Show CLI version
$ appwrite_generator --version
# Show usage help
$ appwrite_generator --help
# Update the CLI to the latest version
$ appwrite_generator updateCreate an appwrite_generator.yaml file to configure multi-language generation:
# Target language: dart, python, or both
target: both
# Input Appwrite configuration
input: appwrite.json
# Dart output directory
output: lib/models
# Python configuration
python:
output: python/models
pydantic_version: v2
# Features
features:
validation: true
metadata_fields: true
equatable: false # Dart onlyFrom your appwrite.json configuration, the generator creates:
- Type-safe model classes with
fromJson,toJson, andcopyWithmethods - Enums for all enum-type columns
- Attribute constants for type-safe property access
- Null-safe code based on the
requiredflag in your schema
- Pydantic BaseModel classes with automatic validation
- Type hints using Python's typing module
- String-based Enums for enum-type columns
- Field validators using
@field_validatordecorators - Field constants for type-safe property access
Given this appwrite.json:
{
"tables": [{
"$id": "users",
"name": "Users",
"columns": [
{
"key": "handle",
"type": "string",
"required": true,
"size": 20
},
{
"key": "age_band",
"type": "string",
"required": false,
"elements": ["18-24", "25-34", "35-44", "45+"],
"format": "enum"
}
]
}]
}The generator creates:
// lib/models/users/user.dart
class User {
const User({required this.handle, this.ageBand});
final String handle;
final AgeBand? ageBand;
factory User.fromJson(Map<String, dynamic> json) { ... }
Map<String, dynamic> toJson() { ... }
User copyWith({String? handle, AgeBand? ageBand}) { ... }
}
// lib/models/users/user_enums.dart
enum AgeBand {
value18to24('18-24'),
value25to34('25-34'),
value35to44('35-44'),
value45Plus('45+');
final String value;
const AgeBand(this.value);
factory AgeBand.fromString(String value) { ... }
}
// lib/models/users/user_attributes.dart
class UserAttributes {
static const String handle = 'handle';
static const String ageBand = 'age_band';
}The same schema generates Python/Pydantic models:
# python/models/users/user.py
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field, ConfigDict, field_validator
from .user_enums import AgeBand
class User(BaseModel):
"""Users model from Appwrite"""
# Appwrite metadata fields
id: Optional[str] = Field(None, alias=r'$id', description='Appwrite document ID')
created_at: Optional[datetime] = Field(None, alias=r'$createdAt')
# Schema fields
handle: str = Field(alias='handle', description='Column: handle', max_length=20)
age_band: Optional[AgeBand] = Field(None, alias='age_band', description='Column: age_band')
# Pydantic configuration
model_config = ConfigDict(
populate_by_name=True,
use_enum_values=True,
validate_assignment=True,
)
@field_validator("handle")
@classmethod
def validate_handle_length(cls, v: str) -> str:
"""Validate handle length"""
if v and len(v) > 20:
raise ValueError(f"handle must be 20 characters or less, got {len(v)}")
return v
# python/models/users/user_enums.py
from enum import Enum
class AgeBand(str, Enum):
"""AgeBand enum from Appwrite"""
value_18_24 = '18-24'
value_25_34 = '25-34'
value_35_44 = '35-44'
value_45_plus = '45+'
@classmethod
def from_string(cls, value: str) -> "AgeBand":
"""Create enum from string value"""
try:
return cls(value)
except ValueError:
raise ValueError(f'Invalid AgeBand: {value}')
# python/models/users/user_fields.py
class UserFields:
"""Field name constants for Users"""
HANDLE = 'handle'
AGE_BAND = 'age_band'Include Appwrite document metadata in your models:
# appwrite_generator.yaml
features:
metadata_fields: true # enabled by defaultGenerated models will include:
class User {
final String? id; // $id
final DateTime? createdAt; // $createdAt
final DateTime? updatedAt; // $updatedAt
final List<String>? permissions; // $permissions
final String? collectionId; // $collectionId
final String? databaseId; // $databaseId
// ... your columns
}Enable for easy equality comparisons (great for state management):
features:
equatable: true # disabled by defaultclass User extends Equatable {
// ... fields
@override
List<Object?> get props => [id, handle, ageBand, ...];
}
// Now you can compare instances easily
final user1 = User(handle: 'john');
final user2 = User(handle: 'john');
print(user1 == user2); // true!Generate schema-based validation methods:
features:
validation: true // disabled by defaultGenerated validation class:
// lib/models/users/user_validation.dart
class UserValidation {
static String? validateHandle(String value) {
if (value.isEmpty) return 'Handle is required';
if (value.length > 20) return 'Handle must be 20 characters or less';
return null;
}
static String? validateEmail(String? value) {
if (value != null && !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return 'Invalid email format';
}
return null;
}
}Auto-regenerate models during development:
$ appwrite_generator watch
π Watching appwrite.json for changes...
Press Ctrl+C to stop watching
π Change detected in appwrite.json
π Regenerating models...
β
Models regenerated successfullyThe generator supports all Appwrite attribute types:
| Appwrite Type | Dart Type | Notes |
|---|---|---|
string |
String |
Includes support for enum format |
integer |
int |
With min/max validation support |
double |
double |
Floating-point numbers |
boolean |
bool |
True/false values |
datetime |
DateTime |
ISO 8601 format |
email |
String |
Email validation in schema |
ip |
String |
IP address validation |
url |
String |
URL validation |
enum |
Custom Enum | Generates dedicated enum class |
relationship |
N/A | Documented but not directly generated |
Check out the example directory for a complete Flutter application with a comprehensive to-do list schema featuring:
- 5 interconnected tables: Projects, Todos, Tags, TodoTags (junction table), and Comments
- Multiple enum types: Project status, todo priority, todo status
- Various attribute types: strings, integers, datetimes, enums
- Relationships: One-to-many and many-to-many patterns
- Complete Flutter app: Working example showing generated models in action
# Activate coverage tool
$ dart pub global activate coverage 1.15.0
# Run tests with coverage
$ dart test --coverage=coverage
# Format coverage data
$ dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info
# Generate HTML coverage report (requires lcov)
$ genhtml coverage/lcov.info -o coverage/
# Open coverage report
$ open coverage/index.htmlContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Publish to pub.dev
- Add support for custom templates
- Generate repository/service layers
- Add validation helpers
- Support for custom attribute types
- Generate API documentation
- Migration generator for schema changes
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2025 Moinsen Development
- Built with Very Good CLI
- Uses mason_logger for beautiful CLI output
- Follows Very Good Analysis style guide