{"id":31696595,"url":"https://github.com/brandonzylstra/essence","last_synced_at":"2026-04-14T14:33:12.228Z","repository":{"id":307011210,"uuid":"1026447148","full_name":"brandonzylstra/essence","owner":"brandonzylstra","description":"🧘🏼‍♂️ Relaxed Rails Modeling \u0026 Migrations","archived":false,"fork":false,"pushed_at":"2025-12-12T19:17:26.000Z","size":16971,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-11T14:41:28.211Z","etag":null,"topics":["active-record","data","database","gem","hcl","modeling","rails","ruby","ruby-on-rails","yaml"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brandonzylstra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-07-25T22:59:56.000Z","updated_at":"2025-07-30T02:24:22.000Z","dependencies_parsed_at":"2025-07-29T00:58:50.417Z","dependency_job_id":null,"html_url":"https://github.com/brandonzylstra/essence","commit_stats":null,"previous_names":["brandonzylstra/essence"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/brandonzylstra/essence","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonzylstra%2Fessence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonzylstra%2Fessence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonzylstra%2Fessence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonzylstra%2Fessence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brandonzylstra","download_url":"https://codeload.github.com/brandonzylstra/essence/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonzylstra%2Fessence/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31801388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T11:13:53.975Z","status":"ssl_error","status_checked_at":"2026-04-14T11:13:53.299Z","response_time":153,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["active-record","data","database","gem","hcl","modeling","rails","ruby","ruby-on-rails","yaml"],"created_at":"2025-10-08T17:09:27.894Z","updated_at":"2026-04-14T14:33:12.204Z","avatar_url":"https://github.com/brandonzylstra.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🌿 Essence 🫧 - ActiveRecord Modeling #\n\n[![CI](https://github.com/brandonzylstra/essence/workflows/CI/badge.svg)](https://github.com/brandonzylstra/essence/actions)\n\n**Essence** is a powerful tool for rapid database schema iteration in Rails applications. It provides a clean, YAML-based syntax with intelligent defaults and pattern matching that compiles to Atlas HCL format for seamless database migrations.\n\n## 🚀 Why Essence?\n\n- **10x faster schema iteration** - Write schemas in clean YAML instead of verbose Rails migrations or GUI tools\n- **Flexible data type syntax** - Use familiar Rails migration types (`:string`, `:integer`) or concise Atlas/SQL types (`string(100)`, `integer`)\n- **Smart defaults** - Automatic `id`, `created_at`, `updated_at` columns for every table\n- **Pattern-based property inference** - `league_id: ~` automatically becomes a foreign key to `leagues.id`\n- **Version control friendly** - Text-based schemas that diff and merge cleanly\n- **Rails integration** - Seamless workflow with rake tasks and Atlas backend\n- **Template generation** - Quick project setup with sensible defaults\n\n## 🔌 Installation ##\n\n**Note:** This gem is not yet published to RubyGems. Install from source:\n\n### From GitHub (recommended)\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'essence', git: 'https://github.com/brandonzylstra/essence.git'\n```\n\nAnd then execute:\n\n```shell\n$ bundle install\n```\n\n### Build and install locally\n\nClone the repository and build the gem:\n\n```shell\n$ git clone https://github.com/brandonzylstra/essence.git\n$ cd essence\n$ bundle install\n$ gem build essence.gemspec\n$ gem install essence-0.1.0.gem\n```\n\n## 🚀 Quick Start ##\n\n### 1. Generate a schema template ###\n\n```shell\n# In your Rails project\nrake essence:template\n```\n\nThis creates `db/schema.yaml` with sensible defaults:\n\n```yaml\n# Enhanced Essence Schema with Default Columns and Pattern Matching\nschema_name: public\n\ndefaults:\n  \"*\":\n    columns:\n      id: ~\n      created_at: ~\n      updated_at: ~\n\ncolumn_patterns:\n  - \"^id$\": \"primary_key\"\n  - \"_id$\": \"integer -\u003e {table}.id on_delete=cascade not_null\"\n  - \"_at$\": \"datetime not_null\"\n  - \".*\": \"string\"\n\ntables:\n  users:\n    columns:\n      email: string(255) not_null unique\n      name: string(100) not_null\n      league_id: ~\n      last_login_at: ~\n\n  leagues:\n    columns:\n      name: string(255) not_null unique\n      description: text\n```\n\n### 2. Compile to HCL format\n\n```shell\nrake essence:compile\n```\n\nThis generates `db/schema.hcl` in Atlas format with foreign keys automatically resolved:\n\n```hcl\nschema \"public\" {\n  comment = \"Generated by Essence\"\n}\n\ntable \"users\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = integer\n    auto_increment = true\n  }\n  column \"email\" {\n    null = false\n    type = varchar(255)\n  }\n  column \"name\" {\n    null = false\n    type = varchar(100)\n  }\n  column \"league_id\" {\n    null = false\n    type = integer\n  }\n  column \"last_login_at\" {\n    null = false\n    type = datetime\n  }\n  column \"created_at\" {\n    null = false\n    type = datetime\n  }\n  column \"updated_at\" {\n    null = false\n    type = datetime\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"FK_USERS_LEAGUE\" {\n    columns     = [column.league_id]\n    ref_columns = [table.leagues.column.id]\n    on_delete   = CASCADE\n  }\n  index \"IDX_USERS_EMAIL\" {\n    columns = [column.email]\n    unique  = true\n  }\n}\n```\n\n### 3. Preview and apply changes ###\n\n```shell\n# See what would change\nrake essence:preview\n\n# Generate Rails migration and apply\nrake essence:deploy[\"add tournament tables\"]\n```\n\n## 🎯 Core Features ##\n\n### Smart Defaults ###\nEvery table automatically gets:\n- `id` primary key column\n- `created_at` and `updated_at` timestamps\n- Proper indexing and constraints\n\n### Pattern-Based Intelligence ###\nWrite `league_id: ~` and—based on the pattern that name matches—automatically get:\n- Integer column\n- Foreign key to `leagues.id`\n- Cascading delete\n- Proper indexing\n\n### Flexible Data Type Syntax ###\nChoose the syntax that works best for your team:\n\n```yaml\n# Atlas/SQL syntax\ntables:\n  tournaments:\n    columns:\n      name: string(255) not_null unique\n      league_id: ~   # Becomes foreign key automatically\n      start_date: ~  # Becomes datetime not_null\n\n# Rails syntax\n  users:\n    columns:\n      name: :string, limit: 255, null: false, unique: true\n      league_id: ~   # Pattern matching works with both syntaxes\n      created_at: :datetime, null: false\n\n# Mixed syntax\n  posts:\n    columns:\n      title: string(255) not_null           # Atlas/SQL syntax\n      content: :text                        # Rails syntax\n      user_id: ~                            # Pattern matching\n```\n\n### Full Rails Integration ###\n```shell\nrake essence:template     # Generate schema template\nrake essence:convert      # Convert YAML to HCL\nrake essence:preview      # Preview changes\nrake essence:apply        # Apply to database\nrake essence:deploy[name] # Full workflow\n```\n\n## 🗃️ Supported Schema Elements ##\n\nEssence provides comprehensive support for database schema elements, with plans to expand coverage over time.\n\n|Status| Group    | Element                  | Explanation                                                        |\n|:----:|:--------:|:-------------------------|:-------------------------------------------------------------------|\n| ✅   | Core     | **Tables**               | Primary schema containers with columns, constraints, and metadata  |\n| ✅   | Core     | **Columns**              | All standard data types with dual syntax support (Atlas/SQL + Rails) |\n| ✅   | Core     | **Data Types**           | Support for both `:string` (Rails) and `string(100)` (Atlas/SQL) syntax |\n| ✅   | Core     | **Primary Keys**         | Auto-incrementing ID columns with proper constraints               |\n| ✅   | Core     | **Foreign Keys**         | Automatic relationship detection with cascade/set null options     |\n| ✅   | Core     | **Indexes**              | Single and multi-column indexes with unique constraints            |\n| ⏳   | Core     | **Check Constraints**    | Column-level validation rules *(planned for Rails 6.1+ support)*   |\n| ⏳   | Advanced | **Views**                | Read-only virtual tables (`scenic` gem integration)                |\n| ⏳   | Advanced | **Materialized Views**   | Cached query results (`scenic` gem integration)                    |\n| ⏳   | Advanced | **Functions/Stored Procedures**  | Database-level business logic (`scenic`, `fx` gems)        |\n| ❓   | Advanced | **Exclusion Constraints**| PostgreSQL-specific constraints                                    |\n| ❓   | Advanced | **Enums**                | Type-safe enumerated values (Rails native with PostgreSQL)         |\n| ❓   | Advanced | **Partitioned Tables**   | Large table performance optimization (Rails 6.1+ with PostgreSQL)  |\n| ❓   | Advanced | **Triggers**             | Event-driven database actions (`hair_trigger` gem integration)     |\n| ❓   | Advanced | **Full-text Search Indexes** | Advanced search capabilities (`pg_search` gem)                 |\n\n### Version Compatibility ###\n\n**ActiveRecord Schema Versions:**\n- ✅ **8.0** - Fully supported (current)\n- 🚧 **7.2** - Possible support\n- 🚧 **7.1** - Possible support\n- 🚧 **7.0** - Possible support\n\nPriority is given to supporting newer Rails versions as they are released (8.1, 8.2, etc.) before adding backward compatibility.\n\n## 📋 Available Patterns ##\n\nEssence automatically recognizes these column patterns (works with both Atlas/SQL and Rails syntax):\n\n| Pattern | Example | Result |\n|---------|---------|--------|\n| `*_id` | `user_id: ~` | `integer -\u003e users.id on_delete=cascade not_null` |\n| `*_at` | `published_at: ~` | `datetime not_null` |\n| `*_on` | `published_on: ~` | `date not_null` |\n| `*_date` | `birth_date: ~` | `date not_null` |\n| `is_*` | `is_active: ~` | `boolean default=false not_null` |\n| `has_*` | `has_premium: ~` | `boolean default=false not_null` |\n| `can_*` | `can_edit: ~` | `boolean default=false not_null` |\n| `*_flag` | `admin_flag: ~` | `boolean default=false not_null` |\n| `*_content` | `body_content: ~` | `text` |\n| `*_body` | `email_body: ~` | `text` |\n| `*_text` | `description_text: ~` | `text` |\n| `*_html` | `content_html: ~` | `text` |\n| `*_count` | `view_count: ~` | `integer default=0 not_null` |\n| `*_score` | `rating_score: ~` | `decimal(8,2)` |\n| `*_amount` | `price_amount: ~` | `decimal(10,2)` |\n| `*_price` | `unit_price: ~` | `decimal(10,2)` |\n| `*_email` | `contact_email: ~` | `string(255)` |\n| `*_url` | `website_url: ~` | `string(500)` |\n| `*_code` | `product_code: ~` | `string(50)` |\n| `*_slug` | `permalink_slug: ~` | `string(255) unique` |\n| `*_status` | `order_status: ~` | `string(50)` |\n| `*_state` | `workflow_state: ~` | `string(50)` |\n\n## 🛠️ Advanced Usage ##\n\n### Custom Patterns ###\nDefine your own patterns in the schema:\n\n```yaml\ncolumn_patterns:\n  - \"_uuid$\": \"uuid not_null unique\"\n  - \"_json$\": \"json\"\n  - \"encrypted_\": \"text not_null\"\n```\n\n### Table-Specific Defaults ###\nOverride defaults for specific tables:\n\n```yaml\ndefaults:\n  \"*\":\n    columns:\n      id: ~\n      created_at: ~\n      updated_at: ~\n  \"audit_*\":\n    columns:\n      id: uuid primary_key\n      created_at: ~\n      created_by: string(255) not_null\n```\n\n### Explicit Overrides ###\nOverride pattern matching with explicit definitions:\n\n```yaml\ntables:\n  users:\n    columns:\n      league_id: string(50) not_null  # Override foreign key pattern\n      created_at: timestamp not_null  # Override default\n```\n\n## 🔄 Workflow Integration ##\n\n### Complete Development Workflow ###\n\n```shell\n# 1. Set up (first time)\nrake essence:init           # Import existing schema\n# OR\nrake essence:template       # Start fresh\n\n# 2. Edit schema\nvim db/schema.yaml\n\n# 3. Iterate rapidly\nrake essence:compile        # YAML → HCL\nrake essence:preview        # See changes\nrake essence:generate[name] # Create migration\nrake essence:apply          # Apply to DB\n\n# 4. Deploy\nrake essence:deploy[name]   # All-in-one\n```\n\n### CI/CD Integration ###\n\n```yaml\n# .github/workflows/schema.yml\nname: Schema Validation\non: [push, pull_request]\njobs:\n  validate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          bundler-cache: true\n      - name: Validate schema\n        run: rake essence:validate\n```\n\n## 📚 Command Reference ##\n\n### CLI Commands ###\n```shell\nessence template [path]         # Generate template\nessence compile [yaml] [hcl]    # Compile formats\nessence version                 # Show version\nessence help                    # Show help\n```\n\n### Rake Tasks ###\n```shell\nrake essence:template[path]     # Generate schema template\nrake essence:compile[yaml,hcl]  # Compile YAML to HCL\nrake essence:preview            # Preview changes\nrake essence:generate[name]     # Generate Rails migration\nrake essence:apply              # Apply schema to database\nrake essence:deploy[name]       # Full workflow\nrake essence:seed               # Generate seed data\nrake essence:init               # Initialize from existing\nrake essence:validate           # Validate schema\nrake essence:history            # Show migration history\nrake essence:help               # Show all commands\n```\n\n## 🏗️ Architecture ##\n\nEssence works by:\n\n1. **YAML Definition** - You write clean, pattern-rich schemas\n2. **Pattern Resolution** - Automatic foreign keys, constraints, indexes\n3. **HCL Generation** - Compiles to Atlas-compatible HCL format\n4. **Atlas Integration** - Uses Atlas for migration planning\n5. **Rails Compatibility** - Generates standard Rails migrations\n\n```\nschema.yaml → [Essence] → schema.hcl → [Atlas] → migration.rb → [Rails] → Database\n```\n\n## 💻 Examples ##\n\n### Basic Blog Schema ###\n```yaml\nschema_name: public\ntables:\n  users:  # Atlas/SQL syntax\n    columns:\n      email: string(255) not_null unique\n      username: string(50) not_null unique\n      first_name: string(100)\n      last_name: string(100)\n      is_admin: ~\n      last_login_at: ~\n\n  posts:  # Rails syntax\n    columns:\n      title: :string, limit: 255, null: false\n      post_slug: ~                    # Pattern matching works with both\n      content_html: :text\n      user_id: ~                      # Foreign key via pattern\n      published_at: :datetime\n      is_published: :boolean, default: false\n      view_count: :integer, default: 0\n```\n\n  comments:\n    columns:\n      post_id: ~\n      user_id: ~\n      comment_body: ~\n      is_approved: ~\n```\n\n### E-commerce Schema ###\n```yaml\nschema_name: public\ntables:\n  customers:\n    columns:\n      email: string(255) not_null unique\n      first_name: string(100) not_null\n      last_name: string(100) not_null\n      phone: string(20)\n      birth_date: ~\n      is_active: ~\n\n  products:\n    columns:\n      name: string(255) not_null\n      product_code: ~\n      description_text: ~\n      unit_price: ~\n      cost_amount: ~\n      stock_count: ~\n      is_active: ~\n\n  orders:\n    columns:\n      customer_id: ~\n      order_status: ~\n      total_amount: ~\n      tax_amount: ~\n      shipping_amount: ~\n      order_date: ~\n      shipped_at: ~\n```\n\n## 💡 Tips and Best Practices ##\n\n### 1. Always Preview First ###\n```shell\nrake essence:preview  # See what will change\nrake essence:apply    # Apply changes\n```\n\n### 2. Use Descriptive Names ###\n```yaml\n# Good - descriptive and clear\nusers:\n  columns:\n    email: string(255) not_null unique\n    contact_email: string(255)\n\n# Avoid - too generic\nusers:\n  columns:\n    data1: string\n    field2: text\n```\n\n### 3. Be Explicit About Constraints ###\n```yaml\n# Good - explicit constraints\nemail: string(255) not_null unique\nuser_id: integer -\u003e users.id on_delete=cascade not_null\n\n# Avoid - relying only on patterns\nemail: ~\nuser_id: ~\n```\n\n### 4. Group Related Tables ###\nOrganize your YAML file with related tables together for better readability:\n\n```yaml\n# Authentication \u0026 Users\nusers:\n  # ...\nuser_sessions:\n  # ...\n\n# Content Management\nposts:\n  # ...\ncomments:\n  # ...\n```\n\n### 5. Use Pattern Matching Effectively ###\n```yaml\n# Let patterns handle repetitive definitions\npublished_at: ~     # Becomes: datetime not_null\nis_active: ~        # Becomes: boolean default=false not_null\nview_count: ~       # Becomes: integer default=0 not_null\n\n# Override patterns when needed\nspecial_id: bigint -\u003e special_table.id on_delete=set_null\n```\n\n## 🤝 Contributing ##\n\n1. Fork it (https://github.com/brandonzylstra/essence/fork)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## 📄 License ##\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## 🙏 Acknowledgments ##\n\n- [Atlas](https://atlasgo.io/) for the powerful migration engine\n- [Rails](https://rubyonrails.org/) for the amazing framework\n- The Ruby community for inspiration and support\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonzylstra%2Fessence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrandonzylstra%2Fessence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonzylstra%2Fessence/lists"}