Full Code of hanami/model for AI

main f07823d79c9a cached
150 files
414.9 KB
112.1k tokens
773 symbols
1 requests
Download .txt
Showing preview only (456K chars total). Download the full file or copy to clipboard to get everything.
Repository: hanami/model
Branch: main
Commit: f07823d79c9a
Files: 150
Total size: 414.9 KB

Directory structure:
gitextract_p2apyb1u/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .jrubyrc
├── .rspec
├── .rubocop.yml
├── .yardopts
├── CHANGELOG.md
├── Gemfile
├── LICENSE.md
├── README.md
├── Rakefile
├── hanami-model.gemspec
├── lib/
│   ├── hanami/
│   │   ├── entity/
│   │   │   └── schema.rb
│   │   ├── entity.rb
│   │   ├── model/
│   │   │   ├── association.rb
│   │   │   ├── associations/
│   │   │   │   ├── belongs_to.rb
│   │   │   │   ├── dsl.rb
│   │   │   │   ├── has_many.rb
│   │   │   │   ├── has_one.rb
│   │   │   │   └── many_to_many.rb
│   │   │   ├── configuration.rb
│   │   │   ├── configurator.rb
│   │   │   ├── entity_name.rb
│   │   │   ├── error.rb
│   │   │   ├── mapped_relation.rb
│   │   │   ├── mapping.rb
│   │   │   ├── migration.rb
│   │   │   ├── migrator/
│   │   │   │   ├── adapter.rb
│   │   │   │   ├── connection.rb
│   │   │   │   ├── logger.rb
│   │   │   │   ├── mysql_adapter.rb
│   │   │   │   ├── postgres_adapter.rb
│   │   │   │   └── sqlite_adapter.rb
│   │   │   ├── migrator.rb
│   │   │   ├── plugins/
│   │   │   │   ├── mapping.rb
│   │   │   │   ├── schema.rb
│   │   │   │   └── timestamps.rb
│   │   │   ├── plugins.rb
│   │   │   ├── relation_name.rb
│   │   │   ├── sql/
│   │   │   │   ├── console.rb
│   │   │   │   ├── consoles/
│   │   │   │   │   ├── abstract.rb
│   │   │   │   │   ├── mysql.rb
│   │   │   │   │   ├── postgresql.rb
│   │   │   │   │   └── sqlite.rb
│   │   │   │   ├── entity/
│   │   │   │   │   └── schema.rb
│   │   │   │   ├── types/
│   │   │   │   │   └── schema/
│   │   │   │   │       └── coercions.rb
│   │   │   │   └── types.rb
│   │   │   ├── sql.rb
│   │   │   ├── types.rb
│   │   │   └── version.rb
│   │   ├── model.rb
│   │   └── repository.rb
│   └── hanami-model.rb
├── script/
│   └── ci
└── spec/
    ├── integration/
    │   └── hanami/
    │       └── model/
    │           ├── associations/
    │           │   ├── belongs_to_spec.rb
    │           │   ├── has_many_spec.rb
    │           │   ├── has_one_spec.rb
    │           │   ├── many_to_many_spec.rb
    │           │   └── relation_alias_spec.rb
    │           ├── migration/
    │           │   ├── mysql.rb
    │           │   ├── postgresql.rb
    │           │   └── sqlite.rb
    │           ├── migration_spec.rb
    │           └── repository/
    │               ├── base_spec.rb
    │               ├── command_spec.rb
    │               └── legacy_spec.rb
    ├── spec_helper.rb
    ├── support/
    │   ├── database/
    │   │   └── strategies/
    │   │       ├── abstract.rb
    │   │       ├── mysql.rb
    │   │       ├── postgresql.rb
    │   │       ├── sql.rb
    │   │       └── sqlite.rb
    │   ├── database.rb
    │   ├── fixtures/
    │   │   ├── database_migrations/
    │   │   │   ├── 20150612081248_column_types.rb
    │   │   │   ├── 20150612084656_default_values.rb
    │   │   │   ├── 20150612093458_null_constraints.rb
    │   │   │   ├── 20150612093810_column_indexes.rb
    │   │   │   ├── 20150612094740_primary_keys.rb
    │   │   │   ├── 20150612115204_foreign_keys.rb
    │   │   │   ├── 20150612122233_table_constraints.rb
    │   │   │   ├── 20150612124205_table_alterations.rb
    │   │   │   ├── 20160830094800_create_users.rb
    │   │   │   ├── 20160830094851_create_authors.rb
    │   │   │   ├── 20160830094941_create_books.rb
    │   │   │   ├── 20160830095033_create_t_operator.rb
    │   │   │   ├── 20160905125728_create_source_files.rb
    │   │   │   ├── 20160909150704_create_avatars.rb
    │   │   │   ├── 20161104143844_create_warehouses.rb
    │   │   │   ├── 20161114094644_create_products.rb
    │   │   │   ├── 20170103142428_create_colors.rb
    │   │   │   ├── 20170124081339_create_labels.rb
    │   │   │   ├── 20170517115243_create_tokens.rb
    │   │   │   ├── 20170519172332_create_categories.rb
    │   │   │   └── 20171002201227_create_posts_and_comments.rb
    │   │   ├── empty_migrations/
    │   │   │   └── .gitkeep
    │   │   └── migrations/
    │   │       ├── 20160831073534_create_reviews.rb
    │   │       └── 20160831090612_add_rating_to_reviews.rb
    │   ├── fixtures.rb
    │   ├── platform/
    │   │   ├── ci.rb
    │   │   ├── db.rb
    │   │   ├── engine.rb
    │   │   ├── matcher.rb
    │   │   └── os.rb
    │   ├── platform.rb
    │   ├── rspec.rb
    │   └── test_io.rb
    └── unit/
        └── hanami/
            ├── entity/
            │   ├── automatic_schema_spec.rb
            │   ├── manual_schema/
            │   │   ├── base_spec.rb
            │   │   ├── strict_spec.rb
            │   │   └── types_spec.rb
            │   ├── schema/
            │   │   ├── definition_spec.rb
            │   │   └── schemaless_spec.rb
            │   ├── schema_spec.rb
            │   └── schemaless_spec.rb
            ├── entity_spec.rb
            └── model/
                ├── check_constraint_validation_error_spec.rb
                ├── configuration_spec.rb
                ├── constraint_violation_error_spec.rb
                ├── disconnect_spec.rb
                ├── error_spec.rb
                ├── foreign_key_constraint_violation_error_spec.rb
                ├── load_spec.rb
                ├── mapped_relation_spec.rb
                ├── migrator/
                │   ├── adapter_spec.rb
                │   ├── connection_spec.rb
                │   ├── mysql.rb
                │   ├── postgresql.rb
                │   └── sqlite.rb
                ├── migrator_spec.rb
                ├── not_null_constraint_violation_error_spec.rb
                ├── sql/
                │   ├── console/
                │   │   ├── mysql.rb
                │   │   ├── postgresql.rb
                │   │   └── sqlite.rb
                │   ├── console_spec.rb
                │   ├── entity/
                │   │   └── schema/
                │   │       ├── automatic_spec.rb
                │   │       └── mapping_spec.rb
                │   └── schema/
                │       ├── array_spec.rb
                │       ├── bool_spec.rb
                │       ├── date_spec.rb
                │       ├── date_time_spec.rb
                │       ├── decimal_spec.rb
                │       ├── float_spec.rb
                │       ├── hash_spec.rb
                │       ├── int_spec.rb
                │       ├── string_spec.rb
                │       └── time_spec.rb
                ├── sql_spec.rb
                ├── unique_constraint_violation_error_spec.rb
                └── version_spec.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: hanami


================================================
FILE: .github/workflows/ci.yml
================================================
name: ci

"on":
  push:
    paths:
      - ".github/workflows/ci.yml"
      - "lib/**"
      - "*.gemspec"
      - "spec/**"
      - "Rakefile"
      - "Gemfile"
      - ".rubocop.yml"
      - "script/ci"
  pull_request:
    branches:
      - main
  create:

jobs:
  tests:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        ruby:
          - "2.7"
        db:
          - sqlite3
          - mysql
          - postgresql
    env:
      DB: ${{matrix.db}}
    steps:
      - uses: actions/checkout@v1
      - name: Install package dependencies
        run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
          ruby-version: ${{matrix.ruby}}
      - name: Run all tests
        env:
          HANAMI_DATABASE_USERNAME: root
          HANAMI_DATABASE_PASSWORD: root
          HANAMI_DATABASE_HOST: 127.0.0.1
          HANAMI_DATABASE_NAME: hanami_model
        run: script/ci
    services:
      mysql:
        image: mysql:8
        env:
          ALLOW_EMPTY_PASSWORD: true
          MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: hanami_model
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
      postgres:
        image: postgres:13
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        env:
          POSTGRES_USER: root
          POSTGRES_PASSWORD: root
          POSTGRES_DB: hanami_model


================================================
FILE: .gitignore
================================================
*.gem
*.rbc
.bundle
.config
.DS_Store
.greenbar
.ruby-version
.yardoc
.rubocop-*
_yardoc
coverage
doc/
Gemfile.lock
InstalledFiles
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp


================================================
FILE: .jrubyrc
================================================
debug.fullTrace=true


================================================
FILE: .rspec
================================================
--color
--require spec_helper


================================================
FILE: .rubocop.yml
================================================
# Please keep AllCops, Bundler, Style, Metrics groups and then order cops
# alphabetically
inherit_from:
  - https://raw.githubusercontent.com/hanami/devtools/1.3.x/.rubocop.yml
Naming/MethodParameterName:
  AllowedNames:
    - ci
    - db
    - id
    - os
Layout/LineLength:
  Enabled: false
Naming/RescuedExceptionsVariableName:
  PreferredName: "exception"
Style/RescueStandardError:
  Enabled: false
Style/DateTime:
  Enabled: false


================================================
FILE: .yardopts
================================================
--protected
--private
-
LICENSE.md
lib/**/*.rb


================================================
FILE: CHANGELOG.md
================================================
# Hanami::Model
A persistence layer for Hanami

## v1.3.3 - 2021-05-22
### Fixed
- [Sean Collins] Specify dependency on BigDecimal v1.4
- [Adam Daniels] Use environment variables for PostgreSQL CLI tools

## v1.3.2 - 2019-01-31
### Fixed
- [Luca Guidi] Depend on `dry-logic` `~> 0.4.2`, `< 0.5`

## v1.3.1 - 2019-01-18
### Added
- [Luca Guidi] Official support for Ruby: MRI 2.6
- [Luca Guidi] Support `bundler` 2.0+

## v1.3.0 - 2018-10-24

## v1.3.0.beta1 - 2018-08-08
### Fixed
- [Luca Guidi] Print meaningful error message when connection URL is misconfigured (eg. `Unknown database adapter for URL: "". Please check your database configuration (hint: ENV['DATABASE_URL']).`)
- [Ian Ker-Seymer] Reliably parse query params from connection string

## v1.2.0 - 2018-04-11

## v1.2.0.rc2 - 2018-04-06

## v1.2.0.rc1 - 2018-03-30
### Fixed
- [Marcello Rocha & Luca Guidi] Ensure repository relations to access database attributes via `#[]` (eg. `projects[:name].ilike("Hanami")`)

## v1.2.0.beta2 - 2018-03-23

## v1.2.0.beta1 - 2018-02-28
### Added
- [Luca Guidi] Official support for Ruby: MRI 2.5
- [Marcello Rocha] Introduce `Hanami::Repository#command` as a factory for custom database commands. This is useful to create custom bulk operations.

## v1.1.0 - 2017-10-25
### Fixed
- [Luca Guidi] Ensure associations to always accept objects that are serializable into `::Hash`

## v1.1.0.rc1 - 2017-10-16
### Added
- [Marcello Rocha] Added support for associations aliasing via `:as` option (`has_many :users, through: :comments, as: :authors`)
- [Luca Guidi] Allow entities to be used as type in entities manual schema (`attribute :owner, Types::Entity(User)`)

## v1.1.0.beta3 - 2017-10-04

## v1.1.0.beta2 - 2017-10-03
### Added
- [Alfonso Uceda] Introduce `Hanami::Model::Migrator#rollback` to provide database migrations rollback
- [Alfonso Uceda] Improve connection string for PostgreSQL in order to pass credentials as URI query string

### Fixed
- [Marcello Rocha] One-To-Many properly destroy the associated methods

## v1.1.0.beta1 - 2017-08-11
### Added
- [Marcello Rocha] Many-To-One association (aka `belongs_to`)
- [Marcello Rocha] One-To-One association (aka `has_one`)
- [Marcello Rocha] Many-To-Many association (aka `has_many :through`)
- [Luca Guidi] Introduced new extra behaviors for entity manual schema: `:schema` (default), `:strict`, `:weak`, and `:permissive`

### Fixed
- [Sean Collins] Enhanced error message for Postgres `db create` and `db drop` when `createdb` and `dropdb` aren't in `PATH`

## v1.0.4 - 2017-10-14
### Fixed
- [Nikita Shilnikov] Keep the dependency on `rom-sql` at `~> 1.3`, which is compatible with `dry-types` `~> 0.11.0`
- [Nikita Shilnikov] Ensure to write Postgres JSON (`PGJSON`) type for nested associated records
- [Nikita Shilnikov] Ensure `Repository#select` to work with `Hanami::Model::MappedRelation`

## v1.0.3 - 2017-10-11
### Fixed
- [Luca Guidi] Keep the dependency on `dry-types` at `~> 0.11.0`

## v1.0.2 - 2017-08-04
### Fixed
- [Maurizio De Magnis] URI escape for Postgres password
- [Marion Duprey] Ensure repository to generate timestamps values even when only one between `created_at` and `updated_at` is present
- [Paweł Świątkowski] Make Postgres JSON(B) to work with Ruby arrays
- [Luca Guidi] Don't remove migrations when running `Hanami::Model::Migrator#apply` fails to dump the database

## v1.0.1 - 2017-06-23
### Fixed
- [Kai Kuchenbecker & Marcello Rocha & Luca Guidi] Ensure `Hanami::Entity#initialize` to not serialize (into `Hash`) other entities passed as an argument
- [Luca Guidi] Let `Hanami::Repository.relation=` to accept strings as an argument
- [Nikita Shilnikov] Prevent stack-overflow when `Hanami::Repository#update` is called thousand times

## v1.0.0 - 2017-04-06

## v1.0.0.rc1 - 2017-03-31

## v1.0.0.beta3 - 2017-03-17
### Added
- [Luca Guidi] Introduced `Hanami::Model.disconnect` to disconnect all the active database connections

## v1.0.0.beta2 - 2017-03-02
### Added
- [Semyon Pupkov] Allow to define Postgres connection URL as `"postgresql:///mydb?host=localhost&port=6433&user=postgres&password=testpasswd"`

### Fixed
- [Marcello Rocha] Fixed migrations MySQL detection of username and password
- [Luca Guidi] Fixed migrations creation/drop of a MySQL database with a dash in the name
- [Semyon Pupkov] Ensure `db console` to work when Postgres connection URL is defined with `"postgresql://"` scheme

## v1.0.0.beta1 - 2017-02-14
### Added
- [Luca Guidi] Official support for Ruby: MRI 2.4
- [Luca Guidi] Introduced `Repository#read` to fetch from database with raw SQL string
- [Luca Guidi] Introduced `Repository.schema` to manually configure the schema of a database table. This is useful for legacy databases where Hanami::Model autoinferring doesn't map correctly the schema.
- [Luca Guidi & Alfonso Uceda] Added `Hanami::Model::Configuration#gateway` to configure gateway and the raw connection
- [Luca Guidi] Added `Hanami::Model::Configuration#logger` to configure a logger
- [Luca Guidi] Database operations (including migrations) print informations to standard output

### Fixed
- [Thorbjørn Hermansen] Ensure repository to not override given timestamps
- [Luca Guidi] Raise `Hanami::Model::MissingPrimaryKeyError` if `Repository#find` is ran against a database w/o a primary key
- [Alfonso Uceda] Ensure SQLite databases to be used on JRuby when the database path is in the same directory of the Ruby script (eg. `./test.sqlite`)

### Changed
- [Luca Guidi] Automap the main relation in a repository, by removing the need of use `.as(:entity)`
- [Luca Guidi] Raise an `Hanami::Model::UnknownDatabaseTypeError` when the application is loaded and there is an unknown column type in the database

## v0.7.0 - 2016-11-15
### Added
- [Luca Guidi] `Hanami::Entity` defines an automatic schema for SQL databases
– [Luca Guidi] `Hanami::Entity` attributes schema
- [Luca Guidi] Experimental support for One-To-Many association (aka `has_many`)
- [Luca Guidi] Native support for PostgreSQL types like UUID, Array, JSON(B) and Money
- [Luca Guidi] Repositories instances can access all the relations (eg. `BookRepository` can access `users` relation via `#users`)
- [Luca Guidi] Automapping for SQL databases
- [Luca Guidi] Added `Hanami::Model::DatabaseError`

### Changed
- [Luca Guidi] Entities are immutable
- [Luca Guidi] Removed support for Memory and File System adapters
- [Luca Guidi] Removed support for _dirty tracking_
- [Luca Guidi] `Hanami::Entity.attributes` method no longer accepts a list of attributes, but a block to optionally define typed attributes
- [Luca Guidi] Removed `#fetch`, `#execute` and `#transaction` from repository
- [Luca Guidi] Removed `mapping` block from `Hanami::Model.configure`
- [Luca Guidi] Changed `adapter` signature in `Hanami::Model.configure` (use `adapter :sql, ENV['DATABASE_URL']`)
- [Luca Guidi] Repositories must inherit from `Hanami::Repository` instead of including it
- [Luca Guidi] Entities must inherit from `Hanami::Entity` instead of including it
- [Pascal Betz] Repositories use instance level interface (eg. `BookRepository.new.find` instead of `BookRepository.find`)
- [Luca Guidi] Repositories now accept hashes for CRUD operations
- [Luca Guidi] `Hanami::Repository#create` now accepts: hash (or entity)
- [Luca Guidi] `Hanami::Repository#update` now accepts two arguments: primary key (`id`) and data (or entity)
- [Luca Guidi] `Hanami::Repository#delete` now accepts: primary key (`id`)
- [Luca Guidi] Drop `Hanami::Model::NonPersistedEntityError`, `Hanami::Model::InvalidMappingError`, `Hanami::Model::InvalidCommandError`, `Hanami::Model::InvalidQueryError`
- [Luca Guidi] Official support for Ruby 2.3 and JRuby 9.0.5.0
- [Luca Guidi] Drop support for Ruby 2.0, 2.1, 2.2, and JRuby 9.0.0.0
- [Luca Guidi] Drop support for `mysql` gem in favor of `mysql2`

### Fixed
- [Luca Guidi] Ensure booleans to be correctly dumped in database
- [Luca Guidi] Ensure to respect default database schema values
- [Luca Guidi] Ensure SQL UPDATE to not override non-default primary key
- [James Hamilton] Print appropriate error message when trying to create a PostgreSQL database that is already existing

## v0.6.2 - 2016-06-01
### Changed
- [Kjell-Magne Øierud] Ensure inherited entities to expose attributes from base class

## v0.6.1 - 2016-02-05
### Changed
- [Hélio Costa e Silva & Pascal Betz] Mapping SQL Adapter's errors as `Hanami::Model` errors

## v0.6.1 - 2016-02-05
### Changed
- [Hélio Costa e Silva & Pascal Betz] Mapping SQL Adapter's errors as `Hanami::Model` errors

## v0.6.0 - 2016-01-22
### Changed
- [Luca Guidi] Renamed the project

## v0.5.2 - 2016-01-19
### Changed
- [Sean Collins] Improved error message for `Lotus::Model::Adapters::NoAdapterError`

### Fixed
- [Kyle Chong & Trung Lê] Catch Sequel exceptions and re-raise as `Lotus::Model::Error`

## v0.5.1 - 2016-01-12
### Added
- [Taylor Finnell] Let `Lotus::Model::Configuration#adapter` to accept arbitrary options (eg. `adapter type: :sql, uri: 'jdbc:...', after_connect: Proc.new { |connection| connection.auto_commit(true) }`)

### Changed
- [Andrey Deryabin] Improved `Entity#inspect`
- [Karim Tarek] Introduced `Lotus::Model::Error` and let all the framework exceptions to inherit from it.

### Fixed
- [Luca Guidi] Improved error message when trying to use a repository without mapping the corresponding collections
- [Sean Collins] Improved error message when trying to create database, but it fails (eg. missing `createdb` executable)
- [Andrey Deryabin] Improved error message when trying to drop database, but a client is still connected (useful for PostgreSQL)
- [Hiếu Nguyễn] Improved error message when trying to "prepare" database, but it fails

## v0.5.0 - 2015-09-30
### Added
- [Brenno Costa] Official support for JRuby 9k+
- [Luca Guidi] Command/Query separation via `Repository.execute` and `Repository.fetch`
- [Luca Guidi] Custom attribute coercers for data mapper
- [Alfonso Uceda] Added `#join` and `#left_join` and `#group` to SQL adapter

### Changed
- [Luca Guidi] `Repository.execute` no longer returns a result from the database.

### Fixed
- [Manuel Corrales] Use `dropdb` to drop PostgreSQL database.
- [Luca Guidi & Bohdan V.] Ignore dotfiles while running migrations.

## v0.4.1 - 2015-07-10
### Fixed
- [Nick Coyne] Fixed database creation for PostgreSQL (now it uses `createdb`).

## v0.4.0 - 2015-06-23
### Added
- [Luca Guidi] Database migrations

### Changed
- [Matthew Bellantoni] Made `Repository.execute` not callable from the outside (private Ruby method, public API).

## v0.3.2 - 2015-05-22
### Added
- [Dmitry Tymchuk & Luca Guidi] Fix for dirty tracking of attributes changed in place (eg. `book.tags << 'non-fiction'`)

## v0.3.1 - 2015-05-15
### Added
- [Dmitry Tymchuk] Dirty tracking for entities (via `Lotus::Entity::DirtyTracking` module to include)
- [My Mai] Automatic update of timestamps when an entity is persisted.
- [Peter Berkenbosch] Introduced `Lotus::Repository#execute`, to execute raw query/commands against database (eg. `BookRepository.execute "SELECT * FROM users"` or `BookRepository.execute "UPDATE users SET admin = 'f'"`)
- [Guilherme Franco] Memory and File System adapters now accept a block for `where`, `or`, `and` conditions (eg `where { age > 33 }`).

### Fixed
- [Luca Guidi] Ensure Array coercion to preserve original data structure

## v0.3.0 - 2015-03-23
### Added
- [Linus Pettersson] Database console

### Fixed
- [Alfonso Uceda Pompa] Don't send unwanted null values to the database, while coercing entities
- [Jan Lelis] Do not define top-level `Boolean`, because it is already defined by `hanami-utils`
- [Vsevolod Romashov] Fix entity class resolving in `Coercer#from_record`
- [Jason Harrelson] Add file and line to `instance_eval` in `Coercer` to make backtrace more usable

## v0.2.4 - 2015-02-20
### Fixed
- [Luca Guidi] When duplicate the framework don't copy over the original `Lotus::Model` configuration

## v0.2.3 - 2015-02-13
### Added
- [Alfonso Uceda Pompa] Added support for database transactions in repositories

### Fixed
- [Luca Guidi] Ensure file system adapter old data is read when a new process is started

## v0.2.2 - 2015-01-18
### Added
- [Luca Guidi] Coerce entities when persisted

## v0.2.1 - 2015-01-12
### Added
- [Luca Guidi] Compatibility between Lotus::Entity and Lotus::Validations

## v0.2.0 - 2014-12-23
### Added
- [Luca Guidi] Introduced file system adapter
– [Benny Klotz & Trung Lê] Introduced `Entity` inheritance of attributes
- [Trung Lê] Introduced `Entity#update` for bulk update of attributes
- [Luca Guidi] Improved error when try to use a repository which wasn't configured or when the framework wasn't loaded yet
- [Trung Lê] Introduced `Entity#to_h`
- [Trung Lê] Introduced `Lotus::Model.duplicate`
- [Trung Lê] Made `Lotus::Mapper` lazy
- [Trung Lê] Introduced thread safe autoloading for adapters
- [Felipe Sere] Add support for `Symbol` coercion
- [Celso Fernandes] Add support for `BigDecimal` coercion
- [Trung Lê] Introduced `Lotus::Model.load!` as entry point for loading
- [Trung Lê] Introduced `Mapper#repository` as DSL to associate a repository to a collection
- [Trung Lê & Tao Guo] Introduced `Configuration#mapping` as DSL to configure the mapping
- [Coen Wessels] Allow `where`, `exclude` and `or` to accept blocks
- [Trung Lê & Tao Guo] Introduced `Configuration#adapter` as DSL to configure the adapter
- [Trung Lê] Introduced `Lotus::Model::Configuration`

### Changed
- [Trung Lê] Changed `Entity.attributes=` to `Entity.attributes`
- [Trung Lê] In case of missing entity, let `Repository#find` returns `nil` instead of raise an exception

### Fixed
- [Rik Tonnard] Ensure correct behavior of `#offset` in memory adapter
- [Benny Klotz] Ensure `Entity` to set the attributes even when the given Hash uses strings as keys
- [Ben Askins] Always return the entity from `Repository#persist`
- [Jeremy Stephens] Made `Memory::Query#where` and `#or` behave more like the SQL counter-part

## v0.1.2 - 2014-06-26
### Fixed
- [Stanislav Spiridonov] Ensure to require `'hanami/model/mapping/coercions'`
- [Krzysztof Zalewski] `Entity` defines `#id` accessor by default


## v0.1.1 - 2014-06-23
### Added
- [Luca Guidi] Introduced `Lotus::Model::Mapping::Coercions` in order to decouple from `Lotus::Utils::Kernel`
- [Luca Guidi] Official support for Ruby 2.1

## v0.1.0 - 2014-04-23
### Added
- [Luca Guidi] Allow to inject coercer into mapper
- [Luca Guidi] Introduced database mapping
- [Luca Guidi] Introduced `Lotus::Entity`
- [Luca Guidi] Introduced SQL adapter
- [Luca Guidi] Introduced memory adapter
– [Luca Guidi] Introduced adapters for repositories
- [Luca Guidi] Introduced `Lotus::Repository`


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"
gemspec

unless ENV["CI"]
  gem "byebug", require: false, platforms: :mri
  gem "yard",   require: false
end

gem "hanami-utils", "~> 1.3", require: false, git: "https://github.com/hanami/utils.git", branch: "1.3.x"

gem "sqlite3", require: false, platforms: :mri, group: :sqlite
gem "pg",      require: false, platforms: :mri, group: :postgres
gem "mysql2",  require: false, platforms: :mri, group: :mysql

gem "jdbc-sqlite3",  require: false, platforms: :jruby, group: :sqlite
gem "jdbc-postgres", require: false, platforms: :jruby, group: :postgres
gem "jdbc-mysql",    require: false, platforms: :jruby, group: :mysql

gem "hanami-devtools", require: false, git: "https://github.com/hanami/devtools.git", branch: "1.3.x"


================================================
FILE: LICENSE.md
================================================
Copyright © 2014-2021 Luca Guidi

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# Hanami::Model (deprecated)

## _Important notice_
**NOTE**: Hanami::Model was the persistence layer for Hanami 1.x. This library will not receive any updates.

For the persistence layer for Hanami 2.x, please see [`hanami/db`](https://github.com/hanami/db)

## Contact

* Home page: http://hanamirb.org
* Mailing List: http://hanamirb.org/mailing-list
* API Doc: http://rubydoc.info/gems/hanami-model
* Chat: https://chat.hanamirb.org

## Rubies

`Hanami::Model` **supports Hanami 1.x only**, and Ruby (MRI) 2.6 and 2.7.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'hanami-model'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install hanami-model

## Usage

This class provides a DSL to configure the connection.

```ruby
require 'hanami/model'
require 'hanami/model/sql'

class User < Hanami::Entity
end

class UserRepository < Hanami::Repository
end

Hanami::Model.configure do
  adapter :sql, 'postgres://username:password@localhost/bookshelf'
end.load!

repository = UserRepository.new
user       = repository.create(name: 'Luca')

puts user.id # => 1

found = repository.find(user.id)
found == user # => true

updated = repository.update(user.id, age: 34)
updated.age # => 34

repository.delete(user.id)
```

## Concepts

### Entities

A model domain object that is defined by its identity.
See "Domain Driven Design" by Eric Evans.

An entity is the core of an application, where the part of the domain logic is implemented.
It's a small, cohesive object that expresses coherent and meaningful behaviors.

It deals with one and only one responsibility that is pertinent to the
domain of the application, without caring about details such as persistence
or validations.

This simplicity of design allows developers to focus on behaviors, or
message passing if you will, which is the quintessence of Object Oriented Programming.

```ruby
require 'hanami/model'

class Person < Hanami::Entity
end
```

### Repositories

An object that mediates between entities and the persistence layer.
It offers a standardized API to query and execute commands on a database.

A repository is **storage independent**, all the queries and commands are
delegated to the current adapter.

This architecture has several advantages:

  * Applications depend on a standard API, instead of low level details
    (Dependency Inversion principle)

  * Applications depend on a stable API, that doesn't change if the
    storage changes

  * Developers can postpone storage decisions

  * Confines persistence logic at a low level

  * Multiple data sources can easily coexist in an application

When a class inherits from `Hanami::Repository`, it will receive the following interface:

  * `#create(data)`     – Create a record for the given data (or entity)
  * `#update(id, data)` – Update the record corresponding to the given id by setting the given data (or entity)
  * `#delete(id)`       – Delete the record corresponding to the given id
  * `#all`              - Fetch all the entities from the relation
  * `#find`             - Fetch an entity from the relation by primary key
  * `#first`            - Fetch the first entity from the relation
  * `#last`             - Fetch the last entity from the relation
  * `#clear`            - Delete all the records from the relation

**A relation is a homogenous set of records.**
It corresponds to a table for a SQL database or to a MongoDB collection.

**All the queries are private**.
This decision forces developers to define intention revealing API, instead of leaking storage API details outside of a repository.

Look at the following code:

```ruby
ArticleRepository.new.where(author_id: 23).order(:published_at).limit(8)
```

This is **bad** for a variety of reasons:

  * The caller has an intimate knowledge of the internal mechanisms of the Repository.

  * The caller works on several levels of abstraction.

  * It doesn't express a clear intent, it's just a chain of methods.

  * The caller can't be easily tested in isolation.

  * If we change the storage, we are forced to change the code of the caller(s).

There is a better way:

```ruby
require 'hanami/model'

class ArticleRepository < Hanami::Repository
  def most_recent_by_author(author, limit: 8)
    articles.where(author_id: author.id).
      order(:published_at).
      limit(limit)
  end
end
```

This is a **huge improvement**, because:

  * The caller doesn't know how the repository fetches the entities.

  * The caller works on a single level of abstraction. It doesn't even know about records, only works with entities.

  * It expresses a clear intent.

  * The caller can be easily tested in isolation. It's just a matter of stubbing this method.

  * If we change the storage, the callers aren't affected.

### Mapping

Hanami::Model can **_automap_** columns from relations and entities attributes.

When using a `sql` adapter, you must require `hanami/model/sql` before `Hanami::Model.load!` is called so the relations are loaded correctly.

However, there are cases where columns and attribute names do not match (mainly **legacy databases**).

```ruby
require 'hanami/model'

class UserRepository < Hanami::Repository
  self.relation = :t_user_archive

  mapping do
    attribute :id,   from: :i_user_id
    attribute :name, from: :s_name
    attribute :age,  from: :i_age
  end
end
```
**NOTE:** This feature should be used only when **_automapping_** fails because of the naming mismatch.

### Conventions

  * A repository must be named after an entity, by appending `"Repository"` to the entity class name (eg. `Article` => `ArticleRepository`).

### Thread safety

**Hanami::Model**'s is thread safe during the runtime, but it isn't during the loading process.
The mapper compiles some code internally, so be sure to safely load it before your application starts.

```ruby
Mutex.new.synchronize do
  Hanami::Model.load!
end
```

**This is not necessary when Hanami::Model is used within a Hanami application.**

## Features

### Timestamps

If an entity has the following accessors: `:created_at` and `:updated_at`, they will be automatically updated when the entity is persisted.

```ruby
require 'hanami/model'
require 'hanami/model/sql'

class User < Hanami::Entity
end

class UserRepository < Hanami::Repository
end

Hanami::Model.configure do
  adapter :sql, 'postgresql://localhost/bookshelf'
end.load!

repository = UserRepository.new

user = repository.create(name: 'Luca')

puts user.created_at.to_s # => "2016-09-19 13:40:13 UTC"
puts user.updated_at.to_s # => "2016-09-19 13:40:13 UTC"

sleep 3
user = repository.update(user.id, age: 34)
puts user.created_at.to_s # => "2016-09-19 13:40:13 UTC"
puts user.updated_at.to_s # => "2016-09-19 13:40:16 UTC"
```

## Configuration

### Logging

In order to log database operations, you can configure a logger:

```ruby
Hanami::Model.configure do
  # ...
  logger "log/development.log", level: :debug
end
```

It accepts the following arguments:

  * `stream`: a Ruby StringIO object - it can be `$stdout` or a path to file (eg. `"log/development.log"`) - Defaults to `$stdout`
  * `:level`: logging level - it can be: `:debug`, `:info`, `:warn`, `:error`, `:fatal`, `:unknown` - Defaults to `:debug`
  * `:formatter`: logging formatter - it can be: `:default` or `:json` - Defaults to `:default`

## Versioning

__Hanami::Model__ uses [Semantic Versioning 2.0.0](http://semver.org)

## Contributing

1. Fork it ( https://github.com/hanami/model/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## Copyright

Copyright © 2014-2021 Luca Guidi – Released under MIT License

This project was formerly known as Lotus (`lotus-model`).


================================================
FILE: Rakefile
================================================
# frozen_string_literal: true

require "rake"
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "hanami/devtools/rake_tasks"

namespace :spec do
  RSpec::Core::RakeTask.new(:unit) do |task|
    task.pattern = FileList["spec/**/*_spec.rb"]
  end
end

task default: "spec:unit"


================================================
FILE: hanami-model.gemspec
================================================
# frozen_string_literal: true

lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "hanami/model/version"

Gem::Specification.new do |spec|
  spec.name          = "hanami-model"
  spec.version       = Hanami::Model::VERSION
  spec.authors       = ["Luca Guidi"]
  spec.email         = ["me@lucaguidi.com"]
  spec.summary       = "A persistence layer for Hanami"
  spec.description   = "A persistence framework with entities and repositories"
  spec.homepage      = "http://hanamirb.org"
  spec.license       = "MIT"

  spec.files         = `git ls-files -z -- lib/* CHANGELOG.md EXAMPLE.md LICENSE.md README.md hanami-model.gemspec`.split("\x0")
  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
  spec.require_paths = ["lib"]
  spec.required_ruby_version = ">= 2.3.0", "< 3"

  spec.add_runtime_dependency "hanami-utils",    "~> 1.3"
  spec.add_runtime_dependency "rom",             "~> 3.3", ">= 3.3.3"
  spec.add_runtime_dependency "rom-sql",         "~> 1.3", ">= 1.3.5"
  spec.add_runtime_dependency "rom-repository",  "~> 1.4"
  spec.add_runtime_dependency "dry-types",       "~> 0.11.0"
  spec.add_runtime_dependency "dry-logic",       "~> 0.4.2", "< 0.5"
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
  spec.add_runtime_dependency "bigdecimal",      "~> 1.4"

  spec.add_development_dependency "bundler", ">= 1.6", "< 3"
  spec.add_development_dependency "rake",  "~> 12"
  spec.add_development_dependency "rspec", "~> 3.7"
  spec.add_development_dependency "rubocop", "0.81" # rubocop 0.81+ removed support for Ruby 2.3
end


================================================
FILE: lib/hanami/entity/schema.rb
================================================
# frozen_string_literal: true

require "hanami/model/types"
require "hanami/utils/hash"

module Hanami
  class Entity
    # Entity schema is a definition of a set of typed attributes.
    #
    # @since 0.7.0
    # @api private
    #
    # @example SQL Automatic Setup
    #  require 'hanami/model'
    #
    #   class Account < Hanami::Entity
    #   end
    #
    #   account = Account.new(name: "Acme Inc.")
    #   account.name # => "Hanami"
    #
    #   account = Account.new(foo: "bar")
    #   account.foo # => NoMethodError
    #
    # @example Non-SQL Manual Setup
    #   require 'hanami/model'
    #
    #   class Account < Hanami::Entity
    #     attributes do
    #       attribute :id,         Types::Int
    #       attribute :name,       Types::String
    #       attribute :codes,      Types::Array(Types::Int)
    #       attribute :users,      Types::Array(User)
    #       attribute :email,      Types::String.constrained(format: /@/)
    #       attribute :created_at, Types::DateTime
    #     end
    #   end
    #
    #   account = Account.new(name: "Acme Inc.")
    #   account.name # => "Acme Inc."
    #
    #   account = Account.new(foo: "bar")
    #   account.foo # => NoMethodError
    #
    # @example Schemaless Entity
    #   require 'hanami/model'
    #
    #   class Account < Hanami::Entity
    #   end
    #
    #   account = Account.new(name: "Acme Inc.")
    #   account.name # => "Acme Inc."
    #
    #   account = Account.new(foo: "bar")
    #   account.foo # => "bar"
    class Schema
      # Schemaless entities logic
      #
      # @since 0.7.0
      # @api private
      class Schemaless
        # @since 0.7.0
        # @api private
        def initialize
          freeze
        end

        # @param attributes [#to_hash] the attributes hash
        #
        # @return [Hash]
        #
        # @since 0.7.0
        # @api private
        def call(attributes)
          if attributes.nil?
            {}
          else
            Utils::Hash.deep_symbolize(attributes.to_hash.dup)
          end
        end

        # @since 0.7.0
        # @api private
        def attribute?(_name)
          true
        end
      end

      # Schema definition
      #
      # @since 0.7.0
      # @api private
      class Definition
        # Schema DSL
        #
        # @since 0.7.0
        class Dsl
          # @since 1.1.0
          # @api private
          TYPES = %i[schema strict weak permissive strict_with_defaults symbolized].freeze

          # @since 1.1.0
          # @api private
          DEFAULT_TYPE = TYPES.first

          # @since 0.7.0
          # @api private
          def self.build(type, &blk)
            type ||= DEFAULT_TYPE
            raise Hanami::Model::Error.new("Unknown schema type: `#{type.inspect}'") unless TYPES.include?(type)

            attributes = new(&blk).to_h
            [attributes, Hanami::Model::Types::Coercible::Hash.__send__(type, attributes)]
          end

          # @since 0.7.0
          # @api private
          def initialize(&blk)
            @attributes = {}
            instance_eval(&blk)
          end

          # Define an attribute
          #
          # @param name [Symbol] the attribute name
          # @param type [Dry::Types::Definition] the attribute type
          #
          # @since 0.7.0
          #
          # @example
          #   require 'hanami/model'
          #
          #   class Account < Hanami::Entity
          #     attributes do
          #       attribute :id,         Types::Int
          #       attribute :name,       Types::String
          #       attribute :codes,      Types::Array(Types::Int)
          #       attribute :users,      Types::Array(User)
          #       attribute :email,      Types::String.constrained(format: /@/)
          #       attribute :created_at, Types::DateTime
          #     end
          #   end
          #
          #   account = Account.new(name: "Acme Inc.")
          #   account.name # => "Acme Inc."
          #
          #   account = Account.new(foo: "bar")
          #   account.foo # => NoMethodError
          def attribute(name, type)
            @attributes[name] = type
          end

          # @since 0.7.0
          # @api private
          def to_h
            @attributes
          end
        end

        # Instantiate a new DSL instance for an entity
        #
        # @param blk [Proc] the block that defines the attributes
        #
        # @return [Hanami::Entity::Schema::Dsl] the DSL
        #
        # @since 0.7.0
        # @api private
        def initialize(type = nil, &blk)
          raise LocalJumpError unless block_given?

          @attributes, @schema = Dsl.build(type, &blk)
          @attributes = Hash[@attributes.map { |k, _| [k, true] }]
          freeze
        end

        # Process attributes
        #
        # @param attributes [#to_hash] the attributes hash
        #
        # @raise [TypeError] if the process fails
        # @raise [ArgumentError] if data is missing, or unknown keys are given
        #
        # @since 0.7.0
        # @api private
        def call(attributes)
          schema.call(attributes)
        rescue Dry::Types::SchemaError => exception
          raise TypeError.new(exception.message)
        rescue Dry::Types::MissingKeyError, Dry::Types::UnknownKeysError => exception
          raise ArgumentError.new(exception.message)
        end

        # Check if the attribute is known
        #
        # @param name [Symbol] the attribute name
        #
        # @return [TrueClass,FalseClass] the result of the check
        #
        # @since 0.7.0
        # @api private
        def attribute?(name)
          attributes.key?(name)
        end

        private

        # @since 0.7.0
        # @api private
        attr_reader :schema

        # @since 0.7.0
        # @api private
        attr_reader :attributes
      end

      # Build a new instance of Schema with the attributes defined by the given block
      #
      # @param blk [Proc] the optional block that defines the attributes
      #
      # @return [Hanami::Entity::Schema] the schema
      #
      # @since 0.7.0
      # @api private
      def initialize(type = nil, &blk)
        @schema = if block_given?
                    Definition.new(type, &blk)
                  else
                    Schemaless.new
                  end
      end

      # Process attributes
      #
      # @param attributes [#to_hash] the attributes hash
      #
      # @raise [TypeError] if the process fails
      #
      # @since 0.7.0
      # @api private
      def call(attributes)
        Utils::Hash.deep_symbolize(
          schema.call(attributes)
        )
      end

      # @since 0.7.0
      # @api private
      alias_method :[], :call

      # Check if the attribute is known
      #
      # @param name [Symbol] the attribute name
      #
      # @return [TrueClass,FalseClass] the result of the check
      #
      # @since 0.7.0
      # @api private
      def attribute?(name)
        schema.attribute?(name)
      end

      protected

      # @since 0.7.0
      # @api private
      attr_reader :schema
    end
  end
end


================================================
FILE: lib/hanami/entity.rb
================================================
# frozen_string_literal: true

require "hanami/model/types"

module Hanami
  # An object that is defined by its identity.
  # See "Domain Driven Design" by Eric Evans.
  #
  # An entity is the core of an application, where the part of the domain
  # logic is implemented. It's a small, cohesive object that expresses coherent
  # and meaningful behaviors.
  #
  # It deals with one and only one responsibility that is pertinent to the
  # domain of the application, without caring about details such as persistence
  # or validations.
  #
  # This simplicity of design allows developers to focus on behaviors, or
  # message passing if you will, which is the quintessence of Object Oriented
  # Programming.
  #
  # @example With Hanami::Entity
  #   require 'hanami/model'
  #
  #   class Person < Hanami::Entity
  #   end
  #
  # If we expand the code above in **pure Ruby**, it would be:
  #
  # @example Pure Ruby
  #   class Person
  #     attr_accessor :id, :name, :age
  #
  #     def initialize(attributes = {})
  #       @id, @name, @age = attributes.values_at(:id, :name, :age)
  #     end
  #   end
  #
  # **Hanami::Model** ships `Hanami::Entity` for developers' convenience.
  #
  # **Hanami::Model** depends on a narrow and well-defined interface for an
  # Entity - `#id`, `#id=`, `#initialize(attributes={})`.If your object
  # implements that interface then that object can be used as an Entity in the
  # **Hanami::Model** framework.
  #
  # However, we suggest to implement this interface by including
  # `Hanami::Entity`, in case that future versions of the framework will expand
  # it.
  #
  # See Dependency Inversion Principle for more on interfaces.
  #
  # @since 0.1.0
  #
  # @see Hanami::Repository
  class Entity
    require "hanami/entity/schema"

    # Syntactic shortcut to reference types in custom schema DSL
    #
    # @since 0.7.0
    module Types
      include Hanami::Model::Types
    end

    # Class level interface
    #
    # @since 0.7.0
    # @api private
    module ClassMethods
      # Define manual entity schema
      #
      # With a SQL database this setup happens automatically and you SHOULD NOT
      # use this DSL. You should use only when you want to customize the automatic
      # setup.
      #
      # If you're working with an entity that isn't "backed" by a SQL table or
      # with a schema-less database, you may want to manually setup a set of
      # attributes via this DSL. If you don't do any setup, the entity accepts all
      # the given attributes.
      #
      # @param type [Symbol] the type of schema to build
      # @param blk [Proc] the block that defines the attributes
      #
      # @since 0.7.0
      #
      # @see Hanami::Entity
      def attributes(type = nil, &blk)
        self.schema = Schema.new(type, &blk)
        @attributes = true
      end

      # Assign a schema
      #
      # @param value [Hanami::Entity::Schema] the schema
      #
      # @since 0.7.0
      # @api private
      def schema=(value)
        return if defined?(@attributes)

        @schema = value
      end

      # @since 0.7.0
      # @api private
      attr_reader :schema
    end

    # @since 0.7.0
    # @api private
    def self.inherited(klass)
      klass.class_eval do
        @schema = Schema.new
        extend  ClassMethods
      end
    end

    # Instantiate a new entity
    #
    # @param attributes [Hash,#to_h,NilClass] data to initialize the entity
    #
    # @return [Hanami::Entity] the new entity instance
    #
    # @raise [TypeError] if the given attributes are invalid
    #
    # @since 0.1.0
    def initialize(attributes = nil)
      @attributes = self.class.schema[attributes]
      freeze
    end

    # Entity ID
    #
    # @return [Object,NilClass] the ID, if present
    #
    # @since 0.7.0
    def id
      attributes.fetch(:id, nil)
    end

    # Handle dynamic accessors
    #
    # If internal attributes set has the requested key, it returns the linked
    # value, otherwise it raises a <tt>NoMethodError</tt>
    #
    # @since 0.7.0
    def method_missing(method_name, *)
      attribute?(method_name) or super
      attributes.fetch(method_name, nil)
    end

    # Implement generic equality for entities
    #
    # Two entities are equal if they are instances of the same class and they
    # have the same id.
    #
    # @param other [Object] the object of comparison
    #
    # @return [FalseClass,TrueClass] the result of the check
    #
    # @since 0.1.0
    def ==(other)
      self.class == other.class &&
        id == other.id
    end

    # Implement predictable hashing for hash equality
    #
    # @return [Integer] the object hash
    #
    # @since 0.7.0
    def hash
      [self.class, id].hash
    end

    # Freeze the entity
    #
    # @since 0.7.0
    def freeze
      attributes.freeze
      super
    end

    # Serialize entity to a Hash
    #
    # @return [Hash] the result of serialization
    #
    # @since 0.1.0
    def to_h
      Utils::Hash.deep_dup(attributes)
    end

    # @since 0.7.0
    alias_method :to_hash, :to_h

    protected

    # Check if the attribute is allowed to be read
    #
    # @since 0.7.0
    # @api private
    def attribute?(name)
      self.class.schema.attribute?(name)
    end

    private

    # @since 0.1.0
    # @api private
    attr_reader :attributes

    # @since 0.7.0
    # @api private
    def respond_to_missing?(name, _include_all)
      attribute?(name)
    end
  end
end


================================================
FILE: lib/hanami/model/association.rb
================================================
# frozen_string_literal: true

require "rom-sql"
require "hanami/model/associations/belongs_to"
require "hanami/model/associations/has_many"
require "hanami/model/associations/has_one"
require "hanami/model/associations/many_to_many"

module Hanami
  module Model
    # Association factory
    #
    # @since 0.7.0
    # @api private
    class Association
      # Instantiate an association
      #
      # @since 0.7.0
      # @api private
      def self.build(repository, target, subject)
        lookup(repository.root.associations[target])
          .new(repository, repository.root.name.to_sym, target, subject)
      end

      # Translate ROM SQL associations into Hanami::Model associations
      #
      # @since 0.7.0
      # @api private
      def self.lookup(association)
        case association
        when ROM::SQL::Association::ManyToMany
          Associations::ManyToMany
        when ROM::SQL::Association::OneToOne
          Associations::HasOne
        when ROM::SQL::Association::OneToMany
          Associations::HasMany
        when ROM::SQL::Association::ManyToOne
          Associations::BelongsTo
        else
          raise "Unsupported association: #{association}"
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/associations/belongs_to.rb
================================================
# frozen_string_literal: true

require "hanami/model/types"

module Hanami
  module Model
    module Associations
      # Many-To-One association
      #
      # @since 1.1.0
      # @api private
      class BelongsTo
        # @since 1.1.0
        # @api private
        def self.schema_type(entity)
          Sql::Types::Schema::AssociationType.new(entity)
        end

        # @since 1.1.0
        # @api private
        attr_reader :repository

        # @since 1.1.0
        # @api private
        attr_reader :source

        # @since 1.1.0
        # @api private
        attr_reader :target

        # @since 1.1.0
        # @api private
        attr_reader :subject

        # @since 1.1.0
        # @api private
        attr_reader :scope

        # @since 1.1.0
        # @api private
        def initialize(repository, source, target, subject, scope = nil)
          @repository = repository
          @source     = source
          @target     = target
          @subject    = subject.to_hash unless subject.nil?
          @scope      = scope || _build_scope
          freeze
        end

        # @since 1.1.0
        # @api private
        def one
          scope.one
        end

        private

        # @since 1.1.0
        # @api private
        def container
          repository.container
        end

        # @since 1.1.0
        # @api private
        def primary_key
          association_keys.first
        end

        # @since 1.1.0
        # @api private
        def relation(name)
          repository.relations[Hanami::Utils::String.pluralize(name)]
        end

        # @since 1.1.0
        # @api private
        def foreign_key
          association_keys.last
        end

        # Returns primary key and foreign key
        #
        # @since 1.1.0
        # @api private
        def association_keys
          association
            .__send__(:join_key_map, container.relations)
        end

        # Return the ROM::Associations for the source relation
        #
        # @since 1.1.9
        # @api private
        def association
          relation(source).associations[target]
        end

        # @since 1.1.0
        # @api private
        def _build_scope
          result = relation(association.target.to_sym)
          result = result.where(foreign_key => subject.fetch(primary_key)) unless subject.nil?
          result.as(Model::MappedRelation.mapper_name)
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/associations/dsl.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    module Associations
      # Auto-infer relations linked to repository's associations
      #
      # @since 0.7.0
      # @api private
      #
      class Dsl
        # @since 0.7.0
        # @api private
        def initialize(repository, &blk)
          @repository = repository
          instance_eval(&blk)
        end

        # @since 0.7.0
        # @api private
        def has_many(relation, **args)
          @repository.__send__(:relations, relation)
          @repository.__send__(:relations, args[:through]) if args[:through]
        end

        # @since 1.1.0
        # @api private
        def has_one(relation, *)
          @repository.__send__(:relations, Hanami::Utils::String.pluralize(relation).to_sym)
        end

        # @since 1.1.0
        # @api private
        def belongs_to(relation, *)
          @repository.__send__(:relations, Hanami::Utils::String.pluralize(relation).to_sym)
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/associations/has_many.rb
================================================
# frozen_string_literal: true

require "hanami/model/types"

module Hanami
  module Model
    module Associations
      # One-To-Many association
      #
      # @since 0.7.0
      # @api private
      class HasMany
        # @since 0.7.0
        # @api private
        def self.schema_type(entity)
          type = Sql::Types::Schema::AssociationType.new(entity)
          Types::Strict::Array.member(type)
        end

        # @since 0.7.0
        # @api private
        attr_reader :repository

        # @since 0.7.0
        # @api private
        attr_reader :source

        # @since 0.7.0
        # @api private
        attr_reader :target

        # @since 0.7.0
        # @api private
        attr_reader :subject

        # @since 0.7.0
        # @api private
        attr_reader :scope

        # @since 0.7.0
        # @api private
        def initialize(repository, source, target, subject, scope = nil)
          @repository = repository
          @source     = source
          @target     = target
          @subject    = subject.to_hash unless subject.nil?
          @scope      = scope || _build_scope
          freeze
        end

        # @since 0.7.0
        # @api private
        def create(data)
          entity.new(command(:create, aggregate(target), mapper: nil, use: [:timestamps])
            .call(serialize(data)))
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        # @since 0.7.0
        # @api private
        def add(data)
          command(:create, relation(target), use: [:timestamps])
            .call(associate(serialize(data)))
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        # @since 0.7.0
        # @api private
        def remove(id)
          command(:update, relation(target), use: [:timestamps])
            .by_pk(id)
            .call(unassociate)
        end

        # @since 0.7.0
        # @api private
        def delete
          scope.delete
        end

        # @since 0.7.0
        # @api private
        def each(&blk)
          scope.each(&blk)
        end

        # @since 0.7.0
        # @api private
        def map(&blk)
          to_a.map(&blk)
        end

        # @since 0.7.0
        # @api private
        def to_a
          scope.to_a
        end

        # @since 0.7.0
        # @api private
        def where(condition)
          __new__(scope.where(condition))
        end

        # @since 0.7.0
        # @api private
        def count
          scope.count
        end

        private

        # @since 0.7.0
        # @api private
        def command(target, relation, options = {})
          repository.command(target, relation, options)
        end

        # @since 0.7.0
        # @api private
        def entity
          repository.class.entity
        end

        # @since 0.7.0
        # @api private
        def relation(name)
          repository.relations[name]
        end

        # @since 0.7.0
        # @api private
        def aggregate(name)
          repository.aggregate(name)
        end

        # @since 0.7.0
        # @api private
        def association(name)
          relation(target).associations[name]
        end

        # @since 0.7.0
        # @api private
        def associate(data)
          relation(source)
            .associations[target]
            .associate(container.relations, data, subject)
        end

        # @since 0.7.0
        # @api private
        def unassociate
          {foreign_key => nil}
        end

        # @since 0.7.0
        # @api private
        def container
          repository.container
        end

        # @since 0.7.0
        # @api private
        def primary_key
          association_keys.first
        end

        # @since 0.7.0
        # @api private
        def foreign_key
          association_keys.last
        end

        # Returns primary key and foreign key
        #
        # @since 0.7.0
        # @api private
        def association_keys
          target_association
            .__send__(:join_key_map, container.relations)
        end

        # Returns the targeted association for a given source
        #
        # @since 0.7.0
        # @api private
        def target_association
          relation(source).associations[target]
        end

        # @since 0.7.0
        # @api private
        def _build_scope
          result = relation(target_association.target.to_sym)
          result = result.where(foreign_key => subject.fetch(primary_key)) unless subject.nil?
          result.as(Model::MappedRelation.mapper_name)
        end

        # @since 0.7.0
        # @api private
        def __new__(new_scope)
          self.class.new(repository, source, target, subject, new_scope)
        end

        def serialize(data)
          Utils::Hash.deep_serialize(data)
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/associations/has_one.rb
================================================
# frozen_string_literal: true

require "hanami/utils/hash"

module Hanami
  module Model
    module Associations
      # Many-To-One association
      #
      # @since 1.1.0
      # @api private
      class HasOne
        # @since 1.1.0
        # @api private
        def self.schema_type(entity)
          Sql::Types::Schema::AssociationType.new(entity)
        end
        #
        # @since 1.1.0
        # @api private
        attr_reader :repository

        # @since 1.1.0
        # @api private
        attr_reader :source

        # @since 1.1.0
        # @api private
        attr_reader :target

        # @since 1.1.0
        # @api private
        attr_reader :subject

        # @since 1.1.0
        # @api private
        attr_reader :scope

        # @since 1.1.0
        # @api private
        def initialize(repository, source, target, subject, scope = nil)
          @repository = repository
          @source     = source
          @target     = target
          @subject    = subject.to_hash unless subject.nil?
          @scope      = scope || _build_scope
          freeze
        end

        def one
          scope.one
        end

        def create(data)
          entity.new(
            command(:create, aggregate(target), mapper: nil).call(serialize(data))
          )
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        def add(data)
          command(:create, relation(target), mapper: nil).call(associate(serialize(data)))
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        def update(data)
          command(:update, relation(target), mapper: nil)
            .by_pk(
              one.public_send(relation(target).primary_key)
            ).call(serialize(data))
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        def delete
          scope.delete
        end
        alias_method :remove, :delete

        def replace(data)
          repository.transaction do
            delete
            add(serialize(data))
          end
        end

        private

        # @since 1.1.0
        # @api private
        def entity
          repository.class.entity
        end

        # @since 1.1.0
        # @api private
        def aggregate(name)
          repository.aggregate(name)
        end

        # @since 1.1.0
        # @api private
        def command(target, relation, options = {})
          repository.command(target, relation, options)
        end

        # @since 1.1.0
        # @api private
        def relation(name)
          repository.relations[Hanami::Utils::String.pluralize(name)]
        end

        # @since 1.1.0
        # @api private
        def container
          repository.container
        end

        # @since 1.1.0
        # @api private
        def primary_key
          association_keys.first
        end

        # @since 1.1.0
        # @api private
        def foreign_key
          association_keys.last
        end

        # @since 1.1.0
        # @api private
        def associate(data)
          relation(source)
            .associations[target]
            .associate(container.relations, data, subject)
        end

        # Returns primary key and foreign key
        #
        # @since 1.1.0
        # @api private
        def association_keys
          relation(source)
            .associations[target]
            .__send__(:join_key_map, container.relations)
        end

        # @since 1.1.0
        # @api private
        def _build_scope
          result = relation(target)
          result = result.where(foreign_key => subject.fetch(primary_key)) unless subject.nil?
          result.as(Model::MappedRelation.mapper_name)
        end

        # @since 1.1.0
        # @api private
        def serialize(data)
          Utils::Hash.deep_serialize(data)
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/associations/many_to_many.rb
================================================
# frozen_string_literal: true

require "hanami/utils/hash"

module Hanami
  module Model
    module Associations
      # Many-To-Many association
      #
      # @since 0.7.0
      # @api private
      class ManyToMany
        # @since 0.7.0
        # @api private
        def self.schema_type(entity)
          type = Sql::Types::Schema::AssociationType.new(entity)
          Types::Strict::Array.member(type)
        end

        # @since 1.1.0
        # @api private
        attr_reader :repository

        # @since 1.1.0
        # @api private
        attr_reader :source

        # @since 1.1.0
        # @api private
        attr_reader :target

        # @since 1.1.0
        # @api private
        attr_reader :subject

        # @since 1.1.0
        # @api private
        attr_reader :scope

        # @since 1.1.0
        # @api private
        attr_reader :through

        def initialize(repository, source, target, subject, scope = nil)
          @repository = repository
          @source     = source
          @target     = target
          @subject    = subject.to_hash unless subject.nil?
          @through    = relation(source).associations[target].through.to_sym
          @scope      = scope || _build_scope
          freeze
        end

        def to_a
          scope.to_a
        end

        def map(&blk)
          to_a.map(&blk)
        end

        def each(&blk)
          scope.each(&blk)
        end

        def count
          scope.count
        end

        def where(condition)
          __new__(scope.where(condition))
        end

        # Return the association table object. Would need an aditional query to return the entity
        #
        # @since 1.1.0
        # @api private
        def add(*data)
          command(:create, relation(through), use: [:timestamps])
            .call(associate(serialize(data)))
        rescue => exception
          raise Hanami::Model::Error.for(exception)
        end

        # @since 1.1.0
        # @api private
        def delete
          relation(through).where(source_foreign_key => subject.fetch(source_primary_key)).delete
        end

        # @since 1.1.0
        # @api private
        def remove(target_id)
          association_record = relation(through)
            .where(target_foreign_key => target_id, source_foreign_key => subject.fetch(source_primary_key))
            .one

          return if association_record.nil?

          ar_id = association_record.public_send relation(through).primary_key
          command(:delete, relation(through)).by_pk(ar_id).call
        end

        private

        # @since 1.1.0
        # @api private
        def container
          repository.container
        end

        # @since 1.1.0
        # @api private
        def relation(name)
          repository.relations[name]
        end

        # @since 1.1.0
        # @api private
        def command(target, relation, options = {})
          repository.command(target, relation, options)
        end

        # @since 1.1.0
        # @api private
        def associate(data)
          relation(target)
            .associations[source]
            .associate(container.relations, data, subject)
        end

        # @since 1.1.0
        # @api private
        def source_primary_key
          association_keys[0].first
        end

        # @since 1.1.0
        # @api private
        def source_foreign_key
          association_keys[0].last
        end

        # @since 1.1.0
        # @api private
        def association_keys
          relation(source)
            .associations[target]
            .__send__(:join_key_map, container.relations)
        end

        # @since 1.1.0
        # @api private
        def target_foreign_key
          association_keys[1].first
        end

        # @since 1.1.0
        # @api private
        def target_primary_key
          association_keys[1].last
        end

        # Return the ROM::Associations for the source relation
        #
        # @since 1.1.0
        # @api private
        def association
          relation(source).associations[target]
        end

        # @since 1.1.0
        #
        # @api private
        def _build_scope
          result = relation(association.target.to_sym).qualified
          unless subject.nil?
            result = result
              .join(through, target_foreign_key => target_primary_key)
              .where(source_foreign_key => subject.fetch(source_primary_key))
          end
          result.as(Model::MappedRelation.mapper_name)
        end

        # @since 1.1.0
        # @api private
        def __new__(new_scope)
          self.class.new(repository, source, target, subject, new_scope)
        end

        # @since 1.1.0
        # @api private
        def serialize(data)
          data.map do |d|
            Utils::Hash.deep_serialize(d)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/configuration.rb
================================================
# frozen_string_literal: true

require "rom/configuration"

module Hanami
  module Model
    # Configuration for the framework, models and adapters.
    #
    # Hanami::Model has its own global configuration that can be manipulated
    # via `Hanami::Model.configure`.
    #
    # @since 0.2.0
    class Configuration
      # @since 0.7.0
      # @api private
      attr_reader :mappings

      # @since 0.7.0
      # @api private
      attr_reader :entities

      # @since 1.0.0
      # @api private
      attr_reader :logger

      # @since 1.0.0
      # @api private
      attr_reader :migrations_logger

      # @since 0.2.0
      # @api private
      def initialize(configurator)
        @backend = configurator.backend
        @url = configurator.url
        @migrations = configurator._migrations
        @schema = configurator._schema
        @gateway_config = configurator._gateway
        @logger = configurator._logger
        @migrations_logger = configurator.migrations_logger
        @mappings = {}
        @entities = {}
      end

      # NOTE: This must be changed when we want to support several adapters at the time
      #
      # @since 0.7.0
      # @api private
      attr_reader :url

      # NOTE: This must be changed when we want to support several adapters at the time
      #
      # @raise [Hanami::Model::UnknownDatabaseAdapterError] if `url` is blank,
      #   or it uses an unknown adapter.
      #
      # @since 0.7.0
      # @api private
      def connection
        gateway.connection
      end

      # NOTE: This must be changed when we want to support several adapters at the time
      #
      # @raise [Hanami::Model::UnknownDatabaseAdapterError] if `url` is blank,
      #   or it uses an unknown adapter.
      #
      # @since 0.7.0
      # @api private
      def gateway
        gateways[:default]
      end

      # Root directory
      #
      # @since 0.4.0
      # @api private
      def root
        Hanami.respond_to?(:root) ? Hanami.root : Pathname.pwd
      end

      # Migrations directory
      #
      # @since 0.4.0
      def migrations
        (@migrations.nil? ? root : root.join(@migrations)).realpath
      end

      # Path for schema dump file
      #
      # @since 0.4.0
      def schema
        @schema.nil? ? root : root.join(@schema)
      end

      # @since 0.7.0
      # @api private
      def define_mappings(root, &blk)
        @mappings[root] = Mapping.new(&blk)
      end

      # @since 0.7.0
      # @api private
      def register_entity(plural, singular, klass)
        @entities[plural]   = klass
        @entities[singular] = klass
      end

      # @since 0.7.0
      # @api private
      def define_entities_mappings(container, repositories)
        return unless defined?(Sql::Entity::Schema)

        repositories.each do |r|
          relation = r.relation
          entity   = r.entity

          entity.schema = Sql::Entity::Schema.new(entities, container.relations[relation], mappings.fetch(relation))
        end
      end

      # @since 1.0.0
      # @api private
      def configure_gateway
        @gateway_config&.call(gateway)
      end

      # @since 1.0.0
      # @api private
      def logger=(value)
        return if value.nil?

        gateway.use_logger(@logger = value)
      end

      # @raise [Hanami::Model::UnknownDatabaseAdapterError] if `url` is blank,
      #   or it uses an unknown adapter.
      #
      # @since 1.0.0
      # @api private
      def rom
        @rom ||= ROM::Configuration.new(@backend, @url, infer_relations: false)
      rescue => exception
        raise UnknownDatabaseAdapterError.new(@url) if exception.message =~ /adapters/

        raise exception
      end

      # @raise [Hanami::Model::UnknownDatabaseAdapterError] if `url` is blank,
      #   or it uses an unknown adapter.
      #
      # @since 1.0.0
      # @api private
      def load!(repositories, &blk)
        rom.setup.auto_registration(config.directory.to_s) unless config.directory.nil?
        rom.instance_eval(&blk)                            if     block_given?
        configure_gateway
        repositories.each(&:load!)
        self.logger = logger

        container = ROM.container(rom)
        define_entities_mappings(container, repositories)
        container
      rescue => exception
        raise Hanami::Model::Error.for(exception)
      end

      # @since 1.0.0
      # @api private
      def method_missing(method_name, *args, &blk)
        if rom.respond_to?(method_name)
          rom.__send__(method_name, *args, &blk)
        else
          super
        end
      end

      # @since 1.1.0
      # @api private
      def respond_to_missing?(method_name, include_all)
        rom.respond_to?(method_name, include_all)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/configurator.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Configuration DSL
    #
    # @since 0.7.0
    # @api private
    class Configurator
      # @since 0.7.0
      # @api private
      attr_reader :backend

      # @since 0.7.0
      # @api private
      attr_reader :url

      # @since 0.7.0
      # @api private
      attr_reader :directory

      # @since 0.7.0
      # @api private
      attr_reader :_migrations

      # @since 0.7.0
      # @api private
      attr_reader :_schema

      # @since 1.0.0
      # @api private
      attr_reader :_logger

      # @since 1.0.0
      # @api private
      attr_reader :_gateway

      # @since 0.7.0
      # @api private
      def self.build(&block)
        new.tap { |config| config.instance_eval(&block) }
      end

      # @since 1.0.0
      # @api private
      def migrations_logger(stream = $stdout)
        require "hanami/model/migrator/logger"
        @migrations_logger ||= Hanami::Model::Migrator::Logger.new(stream)
      end

      private

      # @since 0.7.0
      # @api private
      def adapter(backend, url)
        @backend = backend
        @url = url
      end

      # @since 0.7.0
      # @api private
      def path(path)
        @directory = path
      end

      # @since 0.7.0
      # @api private
      def migrations(path)
        @_migrations = path
      end

      # @since 0.7.0
      # @api private
      def schema(path)
        @_schema = path
      end

      # @since 1.0.0
      # @api private
      def logger(stream, options = {})
        require "hanami/logger"

        opts = options.merge(stream: stream)
        @_logger = Hanami::Logger.new("hanami.model", **opts)
      end

      # @since 1.0.0
      # @api private
      def gateway(&blk)
        @_gateway = blk
      end
    end
  end
end


================================================
FILE: lib/hanami/model/entity_name.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Conventional name for entities.
    #
    # Given a repository named <tt>SourceFileRepository</tt>, the associated
    # entity will be <tt>SourceFile</tt>.
    #
    # @since 0.7.0
    # @api private
    class EntityName
      # @since 0.7.0
      # @api private
      SUFFIX = /Repository\z/.freeze

      # @param name [Class,String] the class or its name
      # @return [String] the entity name
      #
      # @since 0.7.0
      # @api private
      def initialize(name)
        @name = name.sub(SUFFIX, "")
      end

      # @since 0.7.0
      # @api private
      def underscore
        Utils::String.underscore(@name).to_sym
      end

      # @since 0.7.0
      # @api private
      def to_s
        @name
      end
    end
  end
end


================================================
FILE: lib/hanami/model/error.rb
================================================
# frozen_string_literal: true

require "concurrent"

module Hanami
  module Model
    # Default Error class
    #
    # @since 0.5.1
    class Error < ::StandardError
      # @api private
      # @since 0.7.0
      @__mapping__ = Concurrent::Map.new

      # @api private
      # @since 0.7.0
      def self.for(exception)
        mapping.fetch(exception.class, self).new(exception)
      end

      # @api private
      # @since 0.7.0
      def self.register(external, internal)
        mapping.put_if_absent(external, internal)
      end

      # @api private
      # @since 0.7.0
      def self.mapping
        @__mapping__
      end
    end

    # Generic database error
    #
    # @since 0.7.0
    class DatabaseError < Error
    end

    # Error for invalid raw command syntax
    #
    # @since 0.5.0
    class InvalidCommandError < Error
      # @since 0.5.0
      # @api private
      def initialize(message = "Invalid command")
        super
      end
    end

    # Error for Constraint Violation
    #
    # @since 0.7.0
    class ConstraintViolationError < Error
      # @since 0.7.0
      # @api private
      def initialize(message = "Constraint has been violated")
        super
      end
    end

    # Error for Unique Constraint Violation
    #
    # @since 0.6.1
    class UniqueConstraintViolationError < ConstraintViolationError
      # @since 0.6.1
      # @api private
      def initialize(message = "Unique constraint has been violated")
        super
      end
    end

    # Error for Foreign Key Constraint Violation
    #
    # @since 0.6.1
    class ForeignKeyConstraintViolationError < ConstraintViolationError
      # @since 0.6.1
      # @api private
      def initialize(message = "Foreign key constraint has been violated")
        super
      end
    end

    # Error for Not Null Constraint Violation
    #
    # @since 0.6.1
    class NotNullConstraintViolationError < ConstraintViolationError
      # @since 0.6.1
      # @api private
      def initialize(message = "NOT NULL constraint has been violated")
        super
      end
    end

    # Error for Check Constraint Violation raised by Sequel
    #
    # @since 0.6.1
    class CheckConstraintViolationError < ConstraintViolationError
      # @since 0.6.1
      # @api private
      def initialize(message = "Check constraint has been violated")
        super
      end
    end

    # Unknown database type error for repository auto-mapping
    #
    # @since 1.0.0
    class UnknownDatabaseTypeError < Error
    end

    # Unknown primary key error
    #
    # @since 1.0.0
    class MissingPrimaryKeyError < Error
    end

    # Unknown attribute error
    #
    # @since 1.2.0
    class UnknownAttributeError < Error
    end

    # Unknown database adapter error
    #
    # @since 1.2.1
    class UnknownDatabaseAdapterError < Error
      def initialize(url)
        super("Unknown database adapter for URL: #{url.inspect}. Please check your database configuration (hint: ENV['DATABASE_URL']).")
      end
    end
  end
end


================================================
FILE: lib/hanami/model/mapped_relation.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Mapped proxy for ROM relations.
    #
    # It eliminates the need to use #as for repository queries
    #
    # @since 1.0.0
    # @api private
    class MappedRelation < SimpleDelegator
      # Mapper name.
      #
      # With ROM mapping there is a link between the entity class and a generic
      # reference for it. Example: <tt>BookRepository</tt> references <tt>Book</tt>
      # as <tt>:entity</tt>.
      #
      # @since 1.0.0
      # @api private
      MAPPER_NAME = :entity

      # @since 1.0.0
      # @api private
      def self.mapper_name
        MAPPER_NAME
      end

      # @since 1.0.0
      # @api private
      def initialize(relation)
        @relation = relation
        super(relation.as(self.class.mapper_name))
      end

      # Access low level relation's attribute
      #
      # @param attribute [Symbol] the attribute name
      #
      # @return [ROM::SQL::Attribute] the attribute
      #
      # @raise [Hanami::Model::UnknownAttributeError] if the attribute cannot be found
      #
      # @since 1.2.0
      #
      # @example
      #   class UserRepository < Hanami::Repository
      #     def by_matching_name(name)
      #       users
      #         .where(users[:name].ilike(name))
      #         .map_to(User)
      #         .to_a
      #     end
      #   end
      def [](attribute)
        @relation[attribute]
      rescue KeyError => exception
        raise UnknownAttributeError.new(exception.message)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/mapping.rb
================================================
# frozen_string_literal: true

require "transproc/all"

module Hanami
  module Model
    # Mapping
    #
    # @since 0.1.0
    # @api private
    class Mapping
      extend Transproc::Registry

      import Transproc::HashTransformations

      # @since 0.1.0
      # @api private
      def initialize(&blk)
        @attributes   = {}
        @r_attributes = {}
        instance_eval(&blk)
        @processor = @attributes.empty? ? ::Hash : t(:rename_keys, @attributes)
      end

      # @api private
      def t(name, *args)
        self.class[name, *args]
      end

      # @api private
      def model(entity)
      end

      # @api private
      def register_as(name)
      end

      # @api private
      def attribute(name, options)
        from = options.fetch(:from, name)

        @attributes[name]   = from
        @r_attributes[from] = name
      end

      # @api private
      def process(input)
        @processor[input]
      end

      # @api private
      def reverse?
        @r_attributes.any?
      end

      # @api private
      def translate(attribute)
        @r_attributes.fetch(attribute)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migration.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Database migration
    #
    # @since 0.7.0
    # @api private
    class Migration
      # @since 0.7.0
      # @api private
      attr_reader :gateway

      # @since 0.7.0
      # @api private
      attr_reader :migration

      # @since 0.7.0
      # @api private
      def initialize(gateway, &block)
        @gateway = gateway
        @migration = gateway.migration(&block)
        freeze
      end

      # @since 0.7.0
      # @api private
      def run(direction = :up)
        migration.apply(gateway.connection, direction)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/adapter.rb
================================================
# frozen_string_literal: true

require "uri"
require "shellwords"
require "open3"

module Hanami
  module Model
    class Migrator
      # Migrator base adapter
      #
      # @since 0.4.0
      # @api private
      class Adapter
        # Migrations table to store migrations metadata.
        #
        # @since 0.4.0
        # @api private
        MIGRATIONS_TABLE = :schema_migrations

        # Migrations table version column
        #
        # @since 0.4.0
        # @api private
        MIGRATIONS_TABLE_VERSION_COLUMN = :filename

        # Loads and returns a specific adapter for the given connection.
        #
        # @since 0.4.0
        # @api private
        def self.for(configuration)
          connection = Connection.new(configuration)

          case connection.database_type
          when :sqlite
            require "hanami/model/migrator/sqlite_adapter"
            SQLiteAdapter
          when :postgres
            require "hanami/model/migrator/postgres_adapter"
            PostgresAdapter
          when :mysql
            require "hanami/model/migrator/mysql_adapter"
            MySQLAdapter
          else
            self
          end.new(connection)
        end

        # Initialize an adapter
        #
        # @since 0.4.0
        # @api private
        def initialize(connection)
          @connection = connection
        end

        # Create database.
        # It must be implemented by subclasses.
        #
        # @since 0.4.0
        # @api private
        #
        # @see Hanami::Model::Migrator.create
        def create
          raise MigrationError.new("Current adapter (#{connection.database_type}) doesn't support create.")
        end

        # Drop database.
        # It must be implemented by subclasses.
        #
        # @since 0.4.0
        # @api private
        #
        # @see Hanami::Model::Migrator.drop
        def drop
          raise MigrationError.new("Current adapter (#{connection.database_type}) doesn't support drop.")
        end

        # @since 0.4.0
        # @api private
        def migrate(migrations, version)
          version = Integer(version) unless version.nil?

          Sequel::Migrator.run(connection.raw, migrations, target: version, allow_missing_migration_files: true)
        rescue Sequel::Migrator::Error => exception
          raise MigrationError.new(exception.message)
        end

        # @since 1.1.0
        # @api private
        def rollback(migrations, steps)
          table = migrations_table_dataset
          version = version_to_rollback(table, steps)

          Sequel::Migrator.run(connection.raw, migrations, target: version, allow_missing_migration_files: true)
        rescue Sequel::Migrator::Error => exception
          raise MigrationError.new(exception.message)
        end

        # Load database schema.
        # It must be implemented by subclasses.
        #
        # @since 0.4.0
        # @api private
        #
        # @see Hanami::Model::Migrator.prepare
        def load
          raise MigrationError.new("Current adapter (#{connection.database_type}) doesn't support load.")
        end

        # Database version.
        #
        # @since 0.4.0
        # @api private
        def version
          table = migrations_table_dataset
          return if table.nil?

          record = table.order(MIGRATIONS_TABLE_VERSION_COLUMN).last
          return if record.nil?

          record.fetch(MIGRATIONS_TABLE_VERSION_COLUMN).scan(MIGRATIONS_FILE_NAME_PATTERN).first.to_s
        end

        private

        # @since 1.1.0
        # @api private
        MIGRATIONS_FILE_NAME_PATTERN = /\A[\d]{14}/.freeze

        # @since 1.1.0
        # @api private
        def version_to_rollback(table, steps)
          record = table.order(Sequel.desc(MIGRATIONS_TABLE_VERSION_COLUMN)).all[steps]
          return 0 unless record

          record.fetch(MIGRATIONS_TABLE_VERSION_COLUMN).scan(MIGRATIONS_FILE_NAME_PATTERN).first.to_i
        end

        # @since 1.1.0
        # @api private
        def migrations_table_dataset
          connection.table(MIGRATIONS_TABLE)
        end

        # @since 0.5.0
        # @api private
        attr_reader :connection

        # @since 0.4.0
        # @api private
        def schema
          connection.schema
        end

        # Returns a database connection
        #
        # Given a DB connection URI we can connect to a specific database or not, we need this when creating
        # or dropping a database. Important to notice that we can't always open a _global_ DB connection,
        # because most of the times application's DB user has no rights to do so.
        #
        # @param global [Boolean] determine whether or not a connection should specify a database.
        #
        # @since 0.5.0
        # @api private
        def new_connection(global: false)
          uri = global ? connection.global_uri : connection.uri

          Sequel.connect(uri)
        end

        # @since 0.4.0
        # @api private
        def database
          escape connection.database
        end

        # @since 0.4.0
        # @api private
        def port
          escape connection.port
        end

        # @since 0.4.0
        # @api private
        def host
          escape connection.host
        end

        # @since 0.4.0
        # @api private
        def username
          escape connection.user
        end

        # @since 0.4.0
        # @api private
        def password
          escape connection.password
        end

        # @since 0.4.0
        # @api private
        def migrations_table
          escape MIGRATIONS_TABLE
        end

        # @since 0.4.0
        # @api private
        def escape(string)
          Shellwords.escape(string) unless string.nil?
        end

        # @since 1.0.2
        # @api private
        def execute(command, env: {}, error: ->(err) { raise MigrationError.new(err) })
          Open3.popen3(env, command) do |_, stdout, stderr, wait_thr|
            error.call(stderr.read) unless wait_thr.value.success?
            yield stdout if block_given?
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/connection.rb
================================================
# frozen_string_literal: true

require "cgi"

module Hanami
  module Model
    class Migrator
      # Sequel connection wrapper
      #
      # Normalize external adapters interfaces
      #
      # @since 0.5.0
      # @api private
      class Connection
        # @since 0.5.0
        # @api private
        def initialize(configuration)
          @configuration = configuration
        end

        # @since 0.7.0
        # @api private
        def raw
          @raw ||= begin
                     Sequel.connect(
                       configuration.url,
                       loggers: [configuration.migrations_logger]
                     )
                   rescue Sequel::AdapterNotFound
                     raise MigrationError.new("Current adapter (#{configuration.adapter.type}) doesn't support SQL database operations.")
                   end
        end

        # Returns DB connection host
        #
        # Even when adapter doesn't provide it explicitly it tries to parse
        #
        # @since 0.5.0
        # @api private
        def host
          @host ||= parsed_uri.host || parsed_opt("host")
        end

        # Returns DB connection port
        #
        # Even when adapter doesn't provide it explicitly it tries to parse
        #
        # @since 0.5.0
        # @api private
        def port
          @port ||= parsed_uri.port || parsed_opt("port").to_i.nonzero?
        end

        # Returns DB name from conenction
        #
        # Even when adapter doesn't provide it explicitly it tries to parse
        #
        # @since 0.5.0
        # @api private
        def database
          @database ||= parsed_uri.path[1..-1]
        end

        # Returns DB type
        #
        # @example
        #   connection.database_type
        #     # => 'postgres'
        #
        # @since 0.5.0
        # @api private
        def database_type
          case uri
          when /sqlite/
            :sqlite
          when /postgres/
            :postgres
          when /mysql/
            :mysql
          end
        end

        # Returns user from DB connection
        #
        # Even when adapter doesn't provide it explicitly it tries to parse
        #
        # @since 0.5.0
        # @api private
        def user
          @user ||= parsed_opt("user") || parsed_uri.user
        end

        # Returns user from DB connection
        #
        # Even when adapter doesn't provide it explicitly it tries to parse
        #
        # @since 0.5.0
        # @api private
        def password
          @password ||= parsed_opt("password") || parsed_uri.password
        end

        # Returns DB connection URI directly from adapter
        #
        # @since 0.5.0
        # @api private
        def uri
          @configuration.url
        end

        # Returns DB connection wihout specifying database name
        #
        # @since 0.5.0
        # @api private
        def global_uri
          uri.sub(parsed_uri.select(:path).first, "")
        end

        # Returns a boolean telling if a DB connection is from JDBC or not
        #
        # @since 0.5.0
        # @api private
        def jdbc?
          !uri.scan("jdbc:").empty?
        end

        # Returns database connection URI instance without JDBC namespace
        #
        # @since 0.5.0
        # @api private
        def parsed_uri
          @parsed_uri ||= URI.parse(uri.sub("jdbc:", ""))
        end

        # @api private
        def schema
          configuration.schema
        end

        # Return the database table for the given name
        #
        # @since 0.7.0
        # @api private
        def table(name)
          raw[name] if raw.tables.include?(name)
        end

        private

        # @since 1.0.0
        # @api private
        attr_reader :configuration

        # Returns a value of a given query string param
        #
        # @param option [String] which option from database connection will be extracted from URI
        #
        # @since 0.5.0
        # @api private
        def parsed_opt(option, query: parsed_uri.query)
          return if query.nil?

          @parsed_query_opts ||= CGI.parse(query)
          @parsed_query_opts[option].to_a.last
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/logger.rb
================================================
# frozen_string_literal: true

require "hanami/logger"

module Hanami
  module Model
    class Migrator
      # Automatic logger for migrations
      #
      # @since 1.0.0
      # @api private
      class Logger < Hanami::Logger
        # Formatter for migrations logger
        #
        # @since 1.0.0
        # @api private
        class Formatter < Hanami::Logger::Formatter
          private

          # @since 1.0.0
          # @api private
          def _format(hash)
            "[hanami] [#{hash.fetch(:severity)}] #{hash.fetch(:message)}\n"
          end
        end

        # @since 1.0.0
        # @api private
        def initialize(stream)
          super(nil, stream: stream, formatter: Formatter.new)
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/mysql_adapter.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    class Migrator
      # MySQL adapter
      #
      # @since 0.4.0
      # @api private
      class MySQLAdapter < Adapter
        # @since 0.7.0
        # @api private
        PASSWORD = "MYSQL_PWD"

        # @since 1.3.3
        # @api private
        DEFAULT_PORT = 3306

        # @since 1.0.0
        # @api private
        DB_CREATION_ERROR = "Database creation failed. If the database exists, " \
                            "then its console may be open. See this issue for more details: " \
                            "https://github.com/hanami/model/issues/250"

        # @since 0.4.0
        # @api private
        def create
          new_connection(global: true).run %(CREATE DATABASE `#{database}`;)
        rescue Sequel::DatabaseError => exception
          message = if exception.message.match(/database exists/)
                      DB_CREATION_ERROR
                    else
                      exception.message
                    end

          raise MigrationError.new(message)
        end

        # @since 0.4.0
        # @api private
        def drop
          new_connection(global: true).run %(DROP DATABASE `#{database}`;)
        rescue Sequel::DatabaseError => exception
          message = if exception.message.match(/doesn\'t exist/)
                      "Cannot find database: #{database}"
                    else
                      exception.message
                    end

          raise MigrationError.new(message)
        end

        # @since 0.4.0
        # @api private
        def dump
          dump_structure
          dump_migrations_data
        end

        # @since 0.4.0
        # @api private
        def load
          load_structure
        end

        private

        # @since 0.7.0
        # @api private
        def password
          connection.password
        end

        def port
          super || DEFAULT_PORT
        end

        # @since 0.4.0
        # @api private
        def dump_structure
          execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --no-data --skip-comments --ignore-table=#{database}.#{migrations_table} #{database} > #{schema}", env: {PASSWORD => password}
        end

        # @since 0.4.0
        # @api private
        def load_structure
          execute("mysql --host=#{host} --port=#{port} --user=#{username} #{database} < #{escape(schema)}", env: {PASSWORD => password}) if schema.exist?
        end

        # @since 0.4.0
        # @api private
        def dump_migrations_data
          execute "mysqldump --host=#{host} --port=#{port} --user=#{username} --skip-comments #{database} #{migrations_table} >> #{schema}", env: {PASSWORD => password}
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/postgres_adapter.rb
================================================
# frozen_string_literal: true

require "hanami/utils/blank"

module Hanami
  module Model
    class Migrator
      # PostgreSQL adapter
      #
      # @since 0.4.0
      # @api private
      class PostgresAdapter < Adapter
        # @since 0.4.0
        # @api private
        HOST     = "PGHOST"

        # @since 0.4.0
        # @api private
        PORT     = "PGPORT"

        # @since 0.4.0
        # @api private
        USER     = "PGUSER"

        # @since 0.4.0
        # @api private
        PASSWORD = "PGPASSWORD"

        # @since 1.0.0
        # @api private
        DB_CREATION_ERROR = "createdb: database creation failed. If the database exists, " \
                            "then its console may be open. See this issue for more details: " \
                            "https://github.com/hanami/model/issues/250"

        # @since 0.4.0
        # @api private
        def create
          call_db_command("createdb")
        end

        # @since 0.4.0
        # @api private
        def drop
          call_db_command("dropdb")
        end

        # @since 0.4.0
        # @api private
        def dump
          dump_structure
          dump_migrations_data
        end

        # @since 0.4.0
        # @api private
        def load
          load_structure
        end

        private

        # @since 1.3.3
        # @api private
        def environment_variables
          {}.tap do |env|
            env[HOST] = host unless host.nil?
            env[PORT] = port.to_s unless port.nil?
            env[PASSWORD] = password unless password.nil?
            env[USER] = username unless username.nil?
          end
        end

        # @since 0.4.0
        # @api private
        def dump_structure
          execute "pg_dump -s -x -O -T #{migrations_table} -f #{escape(schema)} #{database}", env: environment_variables
        end

        # @since 0.4.0
        # @api private
        def load_structure
          return unless schema.exist?

          execute "psql -X -q -f #{escape(schema)} #{database}", env: environment_variables
        end

        # @since 0.4.0
        # @api private
        def dump_migrations_data
          error = ->(err) { raise MigrationError.new(err) unless err =~ /no matching tables/i }
          execute "pg_dump -t #{migrations_table} #{database} >> #{escape(schema)}", error: error, env: environment_variables
        end

        # @since 0.5.1
        # @api private
        def call_db_command(command)
          require "open3"

          begin
            Open3.popen3(environment_variables, command, database) do |_stdin, _stdout, stderr, wait_thr|
              raise MigrationError.new(modified_message(stderr.read)) unless wait_thr.value.success? # wait_thr.value is the exit status
            end
          rescue SystemCallError => exception
            raise MigrationError.new(modified_message(exception.message))
          end
        end

        # @since 1.1.0
        # @api private
        def modified_message(original_message)
          case original_message
          when /already exists/
            DB_CREATION_ERROR
          when /does not exist/
            "Cannot find database: #{database}"
          when /No such file or directory/
            "Could not find executable in your PATH: `#{original_message.split.last}`"
          else
            original_message
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator/sqlite_adapter.rb
================================================
# frozen_string_literal: true

require "pathname"
require "hanami/utils"
require "English"

module Hanami
  module Model
    class Migrator
      # SQLite3 Migrator
      #
      # @since 0.4.0
      # @api private
      class SQLiteAdapter < Adapter
        # No-op for in-memory databases
        #
        # @since 0.4.0
        # @api private
        module Memory
          # @since 0.4.0
          # @api private
          def create
          end

          # @since 0.4.0
          # @api private
          def drop
          end
        end

        # Initialize adapter
        #
        # @since 0.4.0
        # @api private
        def initialize(configuration)
          super
          extend Memory if memory?
        end

        # @since 0.4.0
        # @api private
        def create
          path.dirname.mkpath
          FileUtils.touch(path)
        rescue Errno::EACCES, Errno::EPERM
          raise MigrationError.new("Permission denied: #{path.sub(/\A\/\//, '')}")
        end

        # @since 0.4.0
        # @api private
        def drop
          path.delete
        rescue Errno::ENOENT
          raise MigrationError.new("Cannot find database: #{path.sub(/\A\/\//, '')}")
        end

        # @since 0.4.0
        # @api private
        def dump
          dump_structure
          dump_migrations_data
        end

        # @since 0.4.0
        # @api private
        def load
          load_structure
        end

        private

        # @since 0.4.0
        # @api private
        def path
          root.join(
            @connection.uri.sub(/\A(jdbc:sqlite:\/\/|sqlite:\/\/)/, "")
          )
        end

        # @since 0.4.0
        # @api private
        def root
          Hanami::Model.configuration.root
        end

        # @since 0.4.0
        # @api private
        def memory?
          uri = path.to_s
          uri.match(/sqlite\:\/\z/) ||
            uri.match(/\:memory\:/)
        end

        # @since 0.4.0
        # @api private
        def dump_structure
          execute "sqlite3 #{escape(path)} .schema > #{escape(schema)}"
        end

        # @since 0.4.0
        # @api private
        def load_structure
          execute "sqlite3 #{escape(path)} < #{escape(schema)}" if schema.exist?
        end

        # @since 0.4.0
        # @api private
        #
        def dump_migrations_data
          execute "sqlite3 #{escape(path)} .dump" do |stdout|
            begin
              contents = stdout.read.split($INPUT_RECORD_SEPARATOR)
              contents = contents.grep(/^INSERT INTO "?#{migrations_table}"?/)

              ::File.open(schema, ::File::CREAT | ::File::BINARY | ::File::WRONLY | ::File::APPEND) do |file|
                file.write(contents.join($INPUT_RECORD_SEPARATOR))
              end
            rescue => exception
              raise MigrationError.new(exception.message)
            end
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/migrator.rb
================================================
# frozen_string_literal: true

require "sequel"
require "sequel/extensions/migration"

module Hanami
  module Model
    # Migration error
    #
    # @since 0.4.0
    class MigrationError < Hanami::Model::Error
    end

    # Database schema migrator
    #
    # @since 0.4.0
    class Migrator
      require "hanami/model/migrator/connection"
      require "hanami/model/migrator/adapter"

      # Create database defined by current configuration.
      #
      # It's only implemented for the following databases:
      #
      #   * SQLite3
      #   * PostgreSQL
      #   * MySQL
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 0.4.0
      #
      # @see Hanami::Model::Configuration#adapter
      #
      # @example
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter :sql, 'postgres://localhost/foo'
      #   end
      #
      #   Hanami::Model::Migrator.create # Creates `foo' database
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.create
        new.create
      end

      # Drop database defined by current configuration.
      #
      # It's only implemented for the following databases:
      #
      #   * SQLite3
      #   * PostgreSQL
      #   * MySQL
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 0.4.0
      #
      # @see Hanami::Model::Configuration#adapter
      #
      # @example
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter :sql, 'postgres://localhost/foo'
      #   end
      #
      #   Hanami::Model::Migrator.drop # Drops `foo' database
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.drop
        new.drop
      end

      # Migrate database schema
      #
      # It's possible to migrate "down" by specifying a version
      # (eg. <tt>"20150610133853"</tt>)
      #
      # @param version [String,NilClass] target version
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 0.4.0
      #
      # @see Hanami::Model::Configuration#adapter
      # @see Hanami::Model::Configuration#migrations
      # @see Hanami::Model::Configuration#rollback
      #
      # @example Migrate Up
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #   end
      #
      #   # Reads all files from "db/migrations" and apply them
      #   Hanami::Model::Migrator.migrate
      #
      # @example Migrate Down
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #   end
      #
      #   # Reads all files from "db/migrations" and apply them
      #   Hanami::Model::Migrator.migrate
      #
      #   # Migrate to a specific version
      #   Hanami::Model::Migrator.migrate(version: "20150610133853")
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.migrate(version: nil)
        new.migrate(version: version)
      end

      # Rollback database schema
      #
      # @param steps [Number,NilClass] number of versions to rollback
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 1.1.0
      #
      # @see Hanami::Model::Configuration#adapter
      # @see Hanami::Model::Configuration#migrations
      # @see Hanami::Model::Configuration#migrate
      #
      # @example Rollback
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #   end
      #
      #   # Reads all files from "db/migrations" and apply them
      #   Hanami::Model::Migrator.migrate
      #
      #   # By default only rollback one version
      #   Hanami::Model::Migrator.rollback
      #
      #   # Use a hash passing a number of versions to rollback, it will rollbacks those versions
      #   Hanami::Model::Migrator.rollback(versions: 2)
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.rollback(steps: 1)
        new.rollback(steps: steps)
      end

      # Migrate, dump schema, delete migrations.
      #
      # This is an experimental feature.
      # It may change or be removed in the future.
      #
      # Actively developed applications accumulate tons of migrations.
      # In the long term they are hard to maintain and slow to execute.
      #
      # "Apply" feature solves this problem.
      #
      # It keeps an updated SQL file with the structure of the database.
      # This file can be used to create fresh databases for developer machines
      # or during testing. This is faster than to run dozen or hundred migrations.
      #
      # When we use "apply", it eliminates all the migrations that are no longer
      # necessary.
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 0.4.0
      #
      # @see Hanami::Model::Configuration#adapter
      # @see Hanami::Model::Configuration#migrations
      #
      # @example Apply Migrations
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #     schema     'db/schema.sql'
      #   end
      #
      #   # Reads all files from "db/migrations" and apply and delete them.
      #   # It generates an updated version of "db/schema.sql"
      #   Hanami::Model::Migrator.apply
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.apply
        new.apply
      end

      # Prepare database: drop, create, load schema (if any), migrate.
      #
      # This is designed for development machines and testing mode.
      # It works faster if used with <tt>apply</tt>.
      #
      # @raise [Hanami::Model::MigrationError] if an error occurs
      #
      # @since 0.4.0
      #
      # @see Hanami::Model::Migrator.apply
      #
      # @example Prepare Database
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #   end
      #
      #   Hanami::Model::Migrator.prepare # => creates `foo' and runs migrations
      #
      # @example Prepare Database (with schema dump)
      #   require 'hanami/model'
      #   require 'hanami/model/migrator'
      #
      #   Hanami::Model.configure do
      #     # ...
      #     adapter    :sql, 'postgres://localhost/foo'
      #     migrations 'db/migrations'
      #     schema     'db/schema.sql'
      #   end
      #
      #   Hanami::Model::Migrator.apply   # => updates schema dump
      #   Hanami::Model::Migrator.prepare # => creates `foo', load schema and run pending migrations (if any)
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.prepare
        new.prepare
      end

      # Return current database version timestamp
      #
      # If no migrations were ran, it returns <tt>nil</tt>.
      #
      # @return [String,NilClass] current version, if previously migrated
      #
      # @since 0.4.0
      #
      # @example
      #   # Given last migrations is:
      #   #  20150610133853_create_books.rb
      #
      #   Hanami::Model::Migrator.version # => "20150610133853"
      #
      # NOTE: Class level interface SHOULD be removed in Hanami 2.0
      def self.version
        new.version
      end

      # Instantiate a new migrator
      #
      # @param configuration [Hanami::Model::Configuration] framework configuration
      #
      # @return [Hanami::Model::Migrator] a new instance
      #
      # @since 0.7.0
      # @api private
      def initialize(configuration: self.class.configuration)
        @configuration = configuration
        @adapter       = Adapter.for(configuration)
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.create
      def create
        adapter.create
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.drop
      def drop
        adapter.drop
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.migrate
      def migrate(version: nil)
        adapter.migrate(migrations, version) if migrations?
      end

      # @since 1.1.0
      # @api private
      #
      # @see Hanami::Model::Migrator.rollback
      def rollback(steps: 1)
        adapter.rollback(migrations, steps.abs) if migrations?
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.apply
      def apply
        migrate
        adapter.dump
        delete_migrations
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.prepare
      def prepare
        drop
      rescue # rubocop:disable Lint/SuppressedException
      ensure
        create
        adapter.load
        migrate
      end

      # @since 0.7.0
      # @api private
      #
      # @see Hanami::Model::Migrator.version
      def version
        adapter.version
      end

      # Hanami::Model configuration
      #
      # @since 0.4.0
      # @api private
      def self.configuration
        Model.configuration
      end

      private

      # @since 0.7.0
      # @api private
      attr_reader :configuration

      # @since 0.7.0
      # @api private
      attr_reader :connection

      # @since 0.7.0
      # @api private
      attr_reader :adapter

      # Migrations directory
      #
      # @since 0.7.0
      # @api private
      def migrations
        configuration.migrations
      end

      # Check if there are migrations
      #
      # @since 0.7.0
      # @api private
      def migrations?
        Dir["#{migrations}/*.rb"].any?
      end

      # Delete all the migrations
      #
      # @since 0.7.0
      # @api private
      def delete_migrations
        migrations.each_child(&:delete)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/plugins/mapping.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    module Plugins
      # Transform output into model domain types (entities).
      #
      # @since 0.7.0
      # @api private
      module Mapping
        # Takes the output and applies the transformations
        #
        # @since 0.7.0
        # @api private
        class InputWithMapping < WrappingInput
          # @since 0.7.0
          # @api private
          def initialize(relation, input)
            super
            @mapping = Hanami::Model.configuration.mappings[relation.name.to_sym]
          end

          # Processes the output
          #
          # @since 0.7.0
          # @api private
          def [](value)
            @input[@mapping.process(value)]
          end
        end

        # Class interface
        #
        # @since 0.7.0
        # @api private
        module ClassMethods
          # Builds the output processor
          #
          # @since 0.7.0
          # @api private
          def build(relation, options = {})
            wrapped_input = InputWithMapping.new(relation, options.fetch(:input) { input })
            super(relation, options.merge(input: wrapped_input))
          end
        end

        # @since 0.7.0
        # @api private
        def self.included(klass)
          super

          klass.extend ClassMethods
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/plugins/schema.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    module Plugins
      # Transform input values into database specific types (primitives).
      #
      # @since 0.7.0
      # @api private
      module Schema
        # Takes the input and applies the values transformations.
        #
        # @since 0.7.0
        # @api private
        class InputWithSchema < WrappingInput
          # @since 0.7.0
          # @api private
          def initialize(relation, input)
            super
            @schema = relation.input_schema
          end

          # Processes the input
          #
          # @since 0.7.0
          # @api private
          def [](value)
            @schema[@input[value]]
          end
        end

        # Class interface
        #
        # @since 0.7.0
        # @api private
        module ClassMethods
          # Builds the input processor
          #
          # @since 0.7.0
          # @api private
          def build(relation, options = {})
            wrapped_input = InputWithSchema.new(relation, options.fetch(:input) { input })
            super(relation, options.merge(input: wrapped_input))
          end
        end

        # @since 0.7.0
        # @api private
        def self.included(klass)
          super

          klass.extend ClassMethods
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/plugins/timestamps.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    module Plugins
      # Automatically set/update timestamp columns for create/update commands
      #
      # @since 0.7.0
      # @api private
      module Timestamps
        # Takes the input and applies the timestamp transformation.
        # This is an "abstract class", please look at the subclasses for
        # specific behaviors.
        #
        # @since 0.7.0
        # @api private
        class InputWithTimestamp < WrappingInput
          # Conventional timestamp names
          #
          # @since 0.7.0
          # @api private
          TIMESTAMPS = %i[created_at updated_at].freeze

          # @since 0.7.0
          # @api private
          def initialize(relation, input)
            super
            @timestamps = relation.columns & TIMESTAMPS
          end

          # Processes the input
          #
          # @since 0.7.0
          # @api private
          def [](value)
            return @input[value] unless timestamps?

            _touch(@input[value], Time.now)
          end

          protected

          # @since 0.7.0
          # @api private
          def _touch(_value)
            raise NoMethodError
          end

          private

          # @since 0.7.0
          # @api private
          def timestamps?
            !@timestamps.empty?
          end
        end

        # Updates <tt>updated_at</tt> timestamp for update commands
        #
        # @since 0.7.0
        # @api private
        class InputWithUpdateTimestamp < InputWithTimestamp
          protected

          # @since 0.7.0
          # @api private
          def _touch(value, now)
            value[:updated_at] ||= now if @timestamps.include?(:updated_at)
            value
          end
        end

        # Sets <tt>created_at</tt> and <tt>updated_at</tt> timestamps for create commands
        #
        # @since 0.7.0
        # @api private
        class InputWithCreateTimestamp < InputWithUpdateTimestamp
          protected

          # @since 0.7.0
          # @api private
          def _touch(value, now)
            super
            value[:created_at] ||= now if @timestamps.include?(:created_at)
            value
          end
        end

        # Class interface
        #
        # @since 0.7.0
        # @api private
        module ClassMethods
          # Build an input processor according to the current command (create or update).
          #
          # @since 0.7.0
          # @api private
          def build(relation, options = {})
            plugin = if self < ROM::Commands::Create
                       InputWithCreateTimestamp
                     else
                       InputWithUpdateTimestamp
                     end

            wrapped_input = plugin.new(relation, options.fetch(:input) { input })
            super(relation, options.merge(input: wrapped_input))
          end
        end

        # @since 0.7.0
        # @api private
        def self.included(klass)
          super

          klass.extend ClassMethods
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/plugins.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Plugins to extend read/write operations from/to the database
    #
    # @since 0.7.0
    # @api private
    module Plugins
      # Wrapping input
      #
      # @since 0.7.0
      # @api private
      class WrappingInput
        # @since 0.7.0
        # @api private
        def initialize(_relation, input)
          @input = input || Hash
        end
      end

      require "hanami/model/plugins/mapping"
      require "hanami/model/plugins/schema"
      require "hanami/model/plugins/timestamps"
    end
  end
end


================================================
FILE: lib/hanami/model/relation_name.rb
================================================
# frozen_string_literal: true

require_relative "entity_name"
require "hanami/utils/string"

module Hanami
  module Model
    # Conventional name for relations.
    #
    # Given a repository named <tt>SourceFileRepository</tt>, the associated
    # relation will be <tt>:source_files</tt>.
    #
    # @since 0.7.0
    # @api private
    class RelationName < EntityName
      # @param name [Class,String] the class or its name
      # @return [String] the relation name
      #
      # @since 0.7.0
      # @api private
      def self.new(name)
        Utils::String.transform(super, :underscore, :pluralize)
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/console.rb
================================================
# frozen_string_literal: true

require "uri"

module Hanami
  module Model
    module Sql
      # SQL console
      #
      # @since 0.7.0
      # @api private
      class Console
        extend Forwardable

        # @since 0.7.0
        # @api private
        def_delegator :console, :connection_string

        # @since 0.7.0
        # @api private
        def initialize(uri)
          @uri = URI.parse(uri)
        end

        private

        # @since 0.7.0
        # @api private
        def console
          case @uri.scheme
          when "sqlite"
            require "hanami/model/sql/consoles/sqlite"
            Sql::Consoles::Sqlite.new(@uri)
          when "postgres", "postgresql"
            require "hanami/model/sql/consoles/postgresql"
            Sql::Consoles::Postgresql.new(@uri)
          when "mysql", "mysql2"
            require "hanami/model/sql/consoles/mysql"
            Sql::Consoles::Mysql.new(@uri)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/consoles/abstract.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    module Sql
      module Consoles
        # Abstract adapter
        #
        # @since 0.7.0
        # @api private
        class Abstract
          # @since 0.7.0
          # @api private
          def initialize(uri)
            @uri = uri
          end

          private

          # @since 0.7.0
          # @api private
          def database_name
            @uri.path.sub(/^\//, "")
          end

          # @since 0.7.0
          # @api private
          def concat(*tokens)
            tokens.join
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/consoles/mysql.rb
================================================
# frozen_string_literal: true

require_relative "abstract"

module Hanami
  module Model
    module Sql
      module Consoles
        # MySQL adapter
        #
        # @since 0.7.0
        # @api private
        class Mysql < Abstract
          # @since 0.7.0
          # @api private
          COMMAND = "mysql"

          # @since 0.7.0
          # @api private
          def connection_string
            concat(command, host, database, port, username, password)
          end

          private

          # @since 0.7.0
          # @api private
          def command
            COMMAND
          end

          # @since 0.7.0
          # @api private
          def host
            " -h #{@uri.host}"
          end

          # @since 0.7.0
          # @api private
          def database
            " -D #{database_name}"
          end

          # @since 0.7.0
          # @api private
          def port
            " -P #{@uri.port}" unless @uri.port.nil?
          end

          # @since 0.7.0
          # @api private
          def username
            " -u #{@uri.user}" unless @uri.user.nil?
          end

          # @since 0.7.0
          # @api private
          def password
            " -p #{@uri.password}" unless @uri.password.nil?
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/consoles/postgresql.rb
================================================
# frozen_string_literal: true

require_relative "abstract"
require "cgi"

module Hanami
  module Model
    module Sql
      module Consoles
        # PostgreSQL adapter
        #
        # @since 0.7.0
        # @api private
        class Postgresql < Abstract
          # @since 0.7.0
          # @api private
          COMMAND = "psql"

          # @since 0.7.0
          # @api private
          PASSWORD = "PGPASSWORD"

          # @since 0.7.0
          # @api private
          def connection_string
            configure_password
            concat(command, host, database, port, username)
          end

          private

          # @since 0.7.0
          # @api private
          def command
            COMMAND
          end

          # @since 0.7.0
          # @api private
          def host
            " -h #{query['host'] || @uri.host}"
          end

          # @since 0.7.0
          # @api private
          def database
            " -d #{database_name}"
          end

          # @since 0.7.0
          # @api private
          def port
            port = query["port"] || @uri.port
            " -p #{port}" if port
          end

          # @since 0.7.0
          # @api private
          def username
            username = query["user"] || @uri.user
            " -U #{username}" if username
          end

          # @since 0.7.0
          # @api private
          def configure_password
            password = query["password"] || @uri.password
            ENV[PASSWORD] = CGI.unescape(query["password"] || @uri.password) if password
          end

          # @since 1.1.0
          # @api private
          def query
            return {} if @uri.query.nil? || @uri.query.empty?

            parsed_query = @uri.query.split("&").map { |a| a.split("=") }
            @query ||= Hash[parsed_query]
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/consoles/sqlite.rb
================================================
# frozen_string_literal: true

require_relative "abstract"
require "shellwords"

module Hanami
  module Model
    module Sql
      module Consoles
        # SQLite adapter
        #
        # @since 0.7.0
        # @api private
        class Sqlite < Abstract
          # @since 0.7.0
          # @api private
          COMMAND = "sqlite3"

          # @since 0.7.0
          # @api private
          def connection_string
            concat(command, " ", host, database)
          end

          private

          # @since 0.7.0
          # @api private
          def command
            COMMAND
          end

          # @since 0.7.0
          # @api private
          def host
            @uri.host unless @uri.host.nil?
          end

          # @since 0.7.0
          # @api private
          def database
            Shellwords.escape(@uri.path)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/entity/schema.rb
================================================
# frozen_string_literal: true

require "hanami/entity/schema"
require "hanami/model/types"
require "hanami/model/association"

module Hanami
  module Model
    module Sql
      module Entity
        # SQL Entity schema
        #
        # This schema setup is automatic.
        #
        # Hanami looks at the database columns, associations and potentially to
        # the mapping in the repository (optional, only for legacy databases).
        #
        # @since 0.7.0
        # @api private
        #
        # @see Hanami::Entity::Schema
        class Schema < Hanami::Entity::Schema
          # Build a new instance of Schema according to database columns,
          # associations and potentially to mapping defined by the repository.
          #
          # @param registry [Hash] a registry that keeps reference between
          #   entities class and their underscored names
          # @param relation [ROM::Relation] the database relation
          # @param mapping [Hanami::Model::Mapping] the optional repository
          #   mapping
          #
          # @return [Hanami::Model::Sql::Entity::Schema] the schema
          #
          # @since 0.7.0
          # @api private
          def initialize(registry, relation, mapping)
            attributes  = build(registry, relation, mapping)
            @schema     = Types::Coercible::Hash.schema(attributes)
            @attributes = Hash[attributes.map { |k, _| [k, true] }]
            freeze
          end

          # Process attributes
          #
          # @param attributes [#to_hash] the attributes hash
          #
          # @raise [TypeError] if the process fails
          #
          # @since 1.0.1
          # @api private
          def call(attributes)
            schema.call(attributes)
          end

          # @since 1.0.1
          # @api private
          alias_method :[], :call

          # Check if the attribute is known
          #
          # @param name [Symbol] the attribute name
          #
          # @return [TrueClass,FalseClass] the result of the check
          #
          # @since 0.7.0
          # @api private
          def attribute?(name)
            attributes.key?(name)
          end

          private

          # @since 0.7.0
          # @api private
          attr_reader :attributes

          # Build the schema
          #
          # @param registry [Hash] a registry that keeps reference between
          #   entities class and their underscored names
          # @param relation [ROM::Relation] the database relation
          # @param mapping [Hanami::Model::Mapping] the optional repository
          #   mapping
          #
          # @return [Dry::Types::Constructor] the inner schema
          #
          # @since 0.7.0
          # @api private
          def build(registry, relation, mapping)
            build_attributes(relation, mapping).merge(
              build_associations(registry, relation.associations)
            )
          end

          # Extract a set of attributes from the database table or from the
          # optional repository mapping.
          #
          # @param relation [ROM::Relation] the database relation
          # @param mapping [Hanami::Model::Mapping] the optional repository
          #   mapping
          #
          # @return [Hash] a set of attributes
          #
          # @since 0.7.0
          # @api private
          def build_attributes(relation, mapping)
            schema = relation.schema.to_h
            schema.each_with_object({}) do |(attribute, type), result|
              attribute = mapping.translate(attribute) if mapping.reverse?
              result[attribute] = coercible(type)
            end
          end

          # Merge attributes and associations
          #
          # @param registry [Hash] a registry that keeps reference between
          #   entities class and their underscored names
          # @param associations [ROM::AssociationSet] a set of associations for
          #   the current relation
          #
          # @return [Hash] attributes with associations
          #
          # @since 0.7.0
          # @api private
          def build_associations(registry, associations)
            associations.each_with_object({}) do |(name, association), result|
              target       = registry.fetch(association.target.to_sym)
              result[name] = Association.lookup(association).schema_type(target)
            end
          end

          # Converts given ROM type into coercible type for entity attribute
          #
          # @since 0.7.0
          # @api private
          def coercible(type)
            Types::Schema.coercible(type)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/types/schema/coercions.rb
================================================
# frozen_string_literal: true

require "hanami/utils/string"
require "hanami/utils/hash"

module Hanami
  module Model
    module Sql
      module Types
        module Schema
          # Coercions for schema types
          #
          # @since 0.7.0
          # @api private
          #
          # rubocop:disable Metrics/ModuleLength
          module Coercions
            # Coerces given argument into Integer
            #
            # @param arg [#to_i,#to_int] the argument to coerce
            #
            # @return [Integer] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.int(arg)
              case arg
              when ::Integer
                arg
              when ::Float, ::BigDecimal, ::String, ::Hanami::Utils::String, ->(a) { a.respond_to?(:to_int) }
                ::Kernel.Integer(arg)
              else
                raise ArgumentError.new("invalid value for Integer(): #{arg.inspect}")
              end
            end

            # Coerces given argument into Float
            #
            # @param arg [#to_f] the argument to coerce
            #
            # @return [Float] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.float(arg)
              case arg
              when ::Float
                arg
              when ::Integer, ::BigDecimal, ::String, ::Hanami::Utils::String, ->(a) { a.respond_to?(:to_f) && !a.is_a?(::Time) }
                ::Kernel.Float(arg)
              else
                raise ArgumentError.new("invalid value for Float(): #{arg.inspect}")
              end
            end

            # Coerces given argument into BigDecimal
            #
            # @param arg [#to_d] the argument to coerce
            #
            # @return [BigDecimal] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.decimal(arg)
              case arg
              when ::BigDecimal
                arg
              when ::Integer, ::Float, ::String, ::Hanami::Utils::String
                ::Kernel.BigDecimal(arg, ::Float::DIG)
              when ->(a) { a.respond_to?(:to_d) }
                arg.to_d
              else
                raise ArgumentError.new("invalid value for BigDecimal(): #{arg.inspect}")
              end
            end

            # Coerces given argument into Date
            #
            # @param arg [#to_date,String] the argument to coerce
            #
            # @return [Date] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.date(arg)
              case arg
              when ::Date
                arg
              when ::String, ::Hanami::Utils::String
                ::Date.parse(arg)
              when ::Time, ::DateTime, ->(a) { a.respond_to?(:to_date) }
                arg.to_date
              else
                raise ArgumentError.new("invalid value for Date(): #{arg.inspect}")
              end
            end

            # Coerces given argument into DateTime
            #
            # @param arg [#to_datetime,String] the argument to coerce
            #
            # @return [DateTime] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.datetime(arg)
              case arg
              when ::DateTime
                arg
              when ::String, ::Hanami::Utils::String
                ::DateTime.parse(arg)
              when ::Date, ::Time, ->(a) { a.respond_to?(:to_datetime) }
                arg.to_datetime
              else
                raise ArgumentError.new("invalid value for DateTime(): #{arg.inspect}")
              end
            end

            # Coerces given argument into Time
            #
            # @param arg [#to_time,String] the argument to coerce
            #
            # @return [Time] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.time(arg)
              case arg
              when ::Time
                arg
              when ::String, ::Hanami::Utils::String
                ::Time.parse(arg)
              when ::Date, ::DateTime, ->(a) { a.respond_to?(:to_time) }
                arg.to_time
              when ::Integer
                ::Time.at(arg)
              else
                raise ArgumentError.new("invalid value for Time(): #{arg.inspect}")
              end
            end

            # Coerces given argument into Array
            #
            # @param arg [#to_ary] the argument to coerce
            #
            # @return [Array] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.array(arg)
              case arg
              when ::Array
                arg
              when ->(a) { a.respond_to?(:to_ary) }
                ::Kernel.Array(arg)
              else
                raise ArgumentError.new("invalid value for Array(): #{arg.inspect}")
              end
            end

            # Coerces given argument into Hash
            #
            # @param arg [#to_hash] the argument to coerce
            #
            # @return [Hash] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 0.7.0
            # @api private
            def self.hash(arg)
              case arg
              when ::Hash
                arg
              when ->(a) { a.respond_to?(:to_hash) }
                Utils::Hash.deep_symbolize(
                  ::Kernel.Hash(arg)
                )
              else
                raise ArgumentError.new("invalid value for Hash(): #{arg.inspect}")
              end
            end

            # Coerces given argument to appropriate Postgres JSON(B) type, i.e. Hash or Array
            #
            # @param arg [Object] the object to coerce
            #
            # @return [Hash, Array] the result of the coercion
            #
            # @raise [ArgumentError] if the coercion fails
            #
            # @since 1.0.2
            # @api private
            def self.pg_json(arg)
              case arg
              when ->(a) { a.respond_to?(:to_hash) }
                hash(arg)
              when ->(a) { a.respond_to?(:to_a) }
                array(arg)
              else
                raise ArgumentError.new("invalid value for PG_JSON(): #{arg.inspect}")
              end
            end
          end

          # rubocop:enable Metrics/ModuleLength
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql/types.rb
================================================
# frozen_string_literal: true

require "hanami/model/types"
require "rom/types"

module Hanami
  module Model
    module Sql
      # Types definitions for SQL databases
      #
      # @since 0.7.0
      module Types
        include Dry::Types.module

        # Types for schema definitions
        #
        # @since 0.7.0
        module Schema
          require "hanami/model/sql/types/schema/coercions"

          String   = Types::Optional::Coercible::String

          Int      = Types::Strict::Nil | Types::Int.constructor(Coercions.method(:int))
          Float    = Types::Strict::Nil | Types::Float.constructor(Coercions.method(:float))
          Decimal  = Types::Strict::Nil | Types::Float.constructor(Coercions.method(:decimal))

          Bool     = Types::Strict::Nil | Types::Strict::Bool

          Date     = Types::Strict::Nil | Types::Date.constructor(Coercions.method(:date))
          DateTime = Types::Strict::Nil | Types::DateTime.constructor(Coercions.method(:datetime))
          Time     = Types::Strict::Nil | Types::Time.constructor(Coercions.method(:time))

          Array    = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:array))
          Hash     = Types::Strict::Nil | Types::Hash.constructor(Coercions.method(:hash))

          PG_JSON  = Types::Strict::Nil | Types::Any.constructor(Coercions.method(:pg_json))

          # @since 0.7.0
          # @api private
          MAPPING = {
            Types::String.pristine => Schema::String,
            Types::Int.pristine => Schema::Int,
            Types::Float.pristine => Schema::Float,
            Types::Decimal.pristine => Schema::Decimal,
            Types::Bool.pristine => Schema::Bool,
            Types::Date.pristine => Schema::Date,
            Types::DateTime.pristine => Schema::DateTime,
            Types::Time.pristine => Schema::Time,
            Types::Array.pristine => Schema::Array,
            Types::Hash.pristine => Schema::Hash,
            Types::String.optional.pristine => Schema::String,
            Types::Int.optional.pristine => Schema::Int,
            Types::Float.optional.pristine => Schema::Float,
            Types::Decimal.optional.pristine => Schema::Decimal,
            Types::Bool.optional.pristine => Schema::Bool,
            Types::Date.optional.pristine => Schema::Date,
            Types::DateTime.optional.pristine => Schema::DateTime,
            Types::Time.optional.pristine => Schema::Time,
            Types::Array.optional.pristine => Schema::Array,
            Types::Hash.optional.pristine => Schema::Hash
          }.freeze

          # Convert given type into coercible
          #
          # @since 0.7.0
          # @api private
          def self.coercible(attribute)
            return attribute if attribute.constrained?

            type      = attribute.type
            unwrapped = type.optional? ? type.right : type

            # NOTE: In the future rom-sql should be able to always return Ruby
            # types instead of Sequel types. When that will happen we can get
            # rid of this logic in the block and fall back to:
            #
            #  MAPPING.fetch(unwrapped.pristine, attribute)
            MAPPING.fetch(unwrapped.pristine) do
              if pg_json?(unwrapped.pristine)
                Schema::PG_JSON
              else
                attribute
              end
            end
          end

          # @since 1.0.4
          # @api private
          def self.pg_json_pristines
            @pg_json_pristines ||= ::Hash.new do |hash, type|
              hash[type] = (ROM::SQL::Types::PG.const_get(type).pristine if defined?(ROM::SQL::Types::PG))
            end
          end

          # @since 1.0.2
          # @api private
          def self.pg_json?(pristine)
            pristine == pg_json_pristines["JSONB"] || # rubocop:disable Style/MultipleComparison
              pristine == pg_json_pristines["JSON"]
          end

          private_class_method :pg_json?

          # Coercer for SQL associations target
          #
          # @since 0.7.0
          # @api private
          class AssociationType < Hanami::Model::Types::Schema::CoercibleType
            # Check if value can be coerced
            #
            # @param value [Object] the value
            #
            # @return [TrueClass,FalseClass] the result of the check
            #
            # @since 0.7.0
            # @api private
            def valid?(value)
              value.inspect =~ /\[#{primitive}\]/ || super
            end

            # @since 0.7.0
            # @api private
            def success(*args)
              result(Dry::Types::Result::Success, primitive.new(args.first.to_h))
            end
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/sql.rb
================================================
# frozen_string_literal: true

require "rom-sql"
require "hanami/utils"

module Hanami
  # Hanami::Model migrations
  module Model
    require "hanami/model/error"
    require "hanami/model/association"
    require "hanami/model/migration"

    # Define a migration
    #
    # It must define an up/down strategy to write schema changes (up) and to
    # rollback them (down).
    #
    # We can use <tt>up</tt> and <tt>down</tt> blocks for custom strategies, or
    # only one <tt>change</tt> block that automatically implements "down" strategy.
    #
    # @param blk [Proc] a block that defines up/down or change database migration
    #
    # @since 0.4.0
    #
    # @example Use up/down blocks
    #   Hanami::Model.migration do
    #     up do
    #       create_table :books do
    #         primary_key :id
    #         column :book, String
    #       end
    #     end
    #
    #     down do
    #       drop_table :books
    #     end
    #   end
    #
    # @example Use change block
    #   Hanami::Model.migration do
    #     change do
    #       create_table :books do
    #         primary_key :id
    #         column :book, String
    #       end
    #     end
    #
    #     # DOWN strategy is automatically generated
    #   end
    def self.migration(&blk)
      Migration.new(configuration.gateways[:default], &blk)
    end

    # SQL adapter
    #
    # @since 0.7.0
    module Sql
      require "hanami/model/sql/types"
      require "hanami/model/sql/entity/schema"

      # Returns a SQL fragment that references a database function by the given name
      # This is useful for database migrations
      #
      # @param name [String,Symbol] the function name
      # @return [String] the SQL fragment
      #
      # @since 0.7.0
      #
      # @example
      #   Hanami::Model.migration do
      #     up do
      #       execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
      #
      #       create_table :source_files do
      #         column :id, 'uuid', primary_key: true, default: Hanami::Model::Sql.function(:uuid_generate_v4)
      #         # ...
      #       end
      #     end
      #
      #     down do
      #       drop_table :source_files
      #       execute 'DROP EXTENSION "uuid-ossp"'
      #     end
      #   end
      def self.function(name)
        Sequel.function(name)
      end

      # Returns a literal SQL fragment for the given SQL fragment.
      # This is useful for database migrations
      #
      # @param string [String] the SQL fragment
      # @return [String] the literal SQL fragment
      #
      # @since 0.7.0
      #
      # @example
      #   Hanami::Model.migration do
      #     up do
      #       execute %{
      #         CREATE TYPE inventory_item AS (
      #           name            text,
      #           supplier_id     integer,
      #           price           numeric
      #         );
      #       }
      #
      #       create_table :items do
      #         column :item, 'inventory_item', default: Hanami::Model::Sql.literal("ROW('fuzzy dice', 42, 1.99)")
      #         # ...
      #       end
      #     end
      #
      #     down do
      #       drop_table :items
      #       execute 'DROP TYPE inventory_item'
      #     end
      #   end
      def self.literal(string)
        Sequel.lit(string)
      end

      # Returns SQL fragment for ascending order for the given column
      #
      # @param column [Symbol] the column name
      # @return [String] the SQL fragment
      #
      # @since 0.7.0
      def self.asc(column)
        Sequel.asc(column)
      end

      # Returns SQL fragment for descending order for the given column
      #
      # @param column [Symbol] the column name
      # @return [String] the SQL fragment
      #
      # @since 0.7.0
      def self.desc(column)
        Sequel.desc(column)
      end
    end

    Error.register(ROM::SQL::DatabaseError,             DatabaseError)
    Error.register(ROM::SQL::ConstraintError,           ConstraintViolationError)
    Error.register(ROM::SQL::NotNullConstraintError,    NotNullConstraintViolationError)
    Error.register(ROM::SQL::UniqueConstraintError,     UniqueConstraintViolationError)
    Error.register(ROM::SQL::CheckConstraintError,      CheckConstraintViolationError)
    Error.register(ROM::SQL::ForeignKeyConstraintError, ForeignKeyConstraintViolationError)
    Error.register(ROM::SQL::UnknownDBTypeError,        UnknownDatabaseTypeError)
    Error.register(ROM::SQL::MissingPrimaryKeyError,    MissingPrimaryKeyError)

    Error.register(Java::JavaSql::SQLException, DatabaseError) if Utils.jruby?
  end
end

Sequel.default_timezone = :utc

ROM.plugins do
  adapter :sql do
    register :mapping,    Hanami::Model::Plugins::Mapping,    type: :command
    register :schema,     Hanami::Model::Plugins::Schema,     type: :command
    register :timestamps, Hanami::Model::Plugins::Timestamps, type: :command
  end
end


================================================
FILE: lib/hanami/model/types.rb
================================================
# frozen_string_literal: true

require "rom/types"

module Hanami
  module Model
    # Types definitions
    #
    # @since 0.7.0
    module Types
      include ROM::Types

      # @since 0.7.0
      # @api private
      def self.included(mod)
        mod.extend(ClassMethods)
      end

      # Class level interface
      #
      # @since 0.7.0
      module ClassMethods
        # Define an entity of the given type
        #
        # @param type [Hanami::Entity] an entity
        #
        # @since 1.1.0
        #
        # @example
        #   require "hanami/model"
        #
        #   class Account < Hanami::Entity
        #     attributes do
        #       # ...
        #       attribute :owner, Types::Entity(User)
        #     end
        #   end
        #
        #   account = Account.new(owner: User.new(name: "Luca"))
        #   account.owner.class # => User
        #   account.owner.name  # => "Luca"
        #
        #   account = Account.new(owner: { name: "MG" })
        #   account.owner.class # => User
        #   account.owner.name  # => "MG"
        def Entity(type)
          type = Schema::CoercibleType.new(type) unless type.is_a?(Dry::Types::Definition)
          type
        end

        # Define an array of given type
        #
        # @param type [Object] an object
        #
        # @since 0.7.0
        #
        # @example
        #   require "hanami/model"
        #
        #   class Account < Hanami::Entity
        #     attributes do
        #       # ...
        #       attribute :users, Types::Collection(User)
        #     end
        #   end
        #
        #   account = Account.new(users: [User.new(name: "Luca")])
        #   user    = account.users.first
        #   user.class # => User
        #   user.name  # => "Luca"
        #
        #   account = Account.new(users: [{ name: "MG" }])
        #   user    = account.users.first
        #   user.class # => User
        #   user.name  # => "MG"
        def Collection(type)
          type = Schema::CoercibleType.new(type) unless type.is_a?(Dry::Types::Definition)
          Types::Array.member(type)
        end
      end

      # Types for schema definitions
      #
      # @since 0.7.0
      module Schema
        # Coercer for objects within custom schema definition
        #
        # @since 0.7.0
        # @api private
        class CoercibleType < Dry::Types::Definition
          # Coerce given value into the wrapped object type
          #
          # @param value [Object] the value
          #
          # @return [Object] the coerced value of `object` type
          #
          # @raise [TypeError] if value can't be coerced
          #
          # @since 0.7.0
          # @api private
          def call(value)
            return if value.nil?

            if valid?(value)
              coerce(value)
            else
              raise TypeError.new("#{value.inspect} must be coercible into #{object}")
            end
          end

          # Check if value can be coerced
          #
          # It is true if value is an instance of `object` type or if value
          # responds to `#to_hash`.
          #
          # @param value [Object] the value
          #
          # @return [TrueClass,FalseClass] the result of the check
          #
          # @since 0.7.0
          # @api private
          def valid?(value)
            value.is_a?(object) ||
              value.respond_to?(:to_hash)
          end

          # Coerce given value into an instance of `object` type
          #
          # @param value [Object] the value
          #
          # @return [Object] the coerced value of `object` type
          def coerce(value)
            case value
            when object
              value
            else
              object.new(value.to_hash)
            end
          end

          # @since 0.7.0
          # @api private
          def object
            result = primitive
            return result unless result.respond_to?(:primitive)

            result.primitive
          end
        end
      end
    end
  end
end


================================================
FILE: lib/hanami/model/version.rb
================================================
# frozen_string_literal: true

module Hanami
  module Model
    # Defines the version
    #
    # @since 0.1.0
    VERSION = "1.3.3"
  end
end


================================================
FILE: lib/hanami/model.rb
================================================
# frozen_string_literal: true

require "rom"
require "concurrent"
require "hanami/entity"
require "hanami/repository"

# Hanami
#
# @since 0.1.0
module Hanami
  # Hanami persistence
  #
  # @since 0.1.0
  module Model
    require "hanami/model/version"
    require "hanami/model/error"
    require "hanami/model/configuration"
    require "hanami/model/configurator"
    require "hanami/model/mapping"
    require "hanami/model/plugins"

    # @api private
    # @since 0.7.0
    @__repositories__ = Concurrent::Array.new

    class << self
      # @since 0.7.0
      # @api private
      attr_reader :config

      # @since 0.7.0
      # @api private
      attr_reader :loaded

      # @since 0.7.0
      # @api private
      alias_method :loaded?, :loaded
    end

    # Configure the framework
    #
    # @since 0.1.0
    #
    # @example
    #   require 'hanami/model'
    #
    #   Hanami::Model.configure do
    #     adapter :sql, ENV['DATABASE_URL']
    #
    #     migrations 'db/migrations'
    #     schema     'db/schema.sql'
    #   end
    def self.configure(&block)
      @config = Configurator.build(&block)
      self
    end

    # Current configuration
    #
    # @since 0.1.0
    def self.configuration
      @configuration ||= Configuration.new(config)
    end

    # @since 0.7.0
    # @api private
    def self.repositories
      @__repositories__
    end

    # @since 0.7.0
    # @api private
    def self.container
      raise "Not loaded" unless loaded?

      @container
    end

    # @since 0.1.0
    def self.load!(&blk)
      @container = configuration.load!(repositories, &blk)
      @loaded    = true
    end

    # Disconnect from the database
    #
    # This is useful for rebooting applications in production and to ensure that
    # the framework prunes stale connections.
    #
    # @since 1.0.0
    #
    # @example With Full Stack Hanami Project
    #   # config/puma.rb
    #   # ...
    #   on_worker_boot do
    #     Hanami.boot
    #   end
    #
    # @example With Standalone Hanami::Model
    #   # config/puma.rb
    #   # ...
    #   on_worker_boot do
    #     Hanami::Model.disconnect
    #     Hanami::Model.load!
    #   end
    def self.disconnect
      configuration.connection&.disconnect
    end
  end
end


================================================
FILE: lib/hanami/repository.rb
================================================
# frozen_string_literal: true

require "rom-repository"
require "hanami/model/entity_name"
require "hanami/model/relation_name"
require "hanami/model/mapped_relation"
require "hanami/model/associations/dsl"
require "hanami/model/association"
require "hanami/utils/class"
require "hanami/utils/class_attribute"
require "hanami/utils/io"

module Hanami
  # Mediates between the entities and the persistence layer, by offering an API
  # to query and execute commands on a database.
  #
  #
  #
  # By default, a repository is named after an entity, by appending the
  # `Repository` suffix to the entity class name.
  #
  # @example
  #   require 'hanami/model'
  #
  #   class Article < Hanami::Entity
  #   end
  #
  #   # valid
  #   class ArticleRepository < Hanami::Repository
  #   end
  #
  #   # not valid for Article
  #   class PostRepository < Hanami::Repository
  #   end
  #
  # A repository is storage independent.
  # All the queries and commands are delegated to the current adapter.
  #
  # This architecture has several advantages:
  #
  #   * Applications depend on an abstract API, instead of low level details
  #     (Dependency Inversion principle)
  #
  #   * Applications depend on a stable API, that doesn't change if the
  #     storage changes
  #
  #   * Developers can postpone storage decisions
  #
  #   * Isolates the persistence logic at a low level
  #
  # Hanami::Model is shipped with one adapter:
  #
  #   * SqlAdapter
  #
  #
  #
  # All the queries and commands are private.
  # This decision forces developers to define intention revealing API, instead
  # of leaking storage API details outside of a repository.
  #
  # @example
  #   require 'hanami/model'
  #
  #   # This is bad for several reasons:
  #   #
  #   #  * The caller has an intimate knowledge of the internal mechanisms
  #   #      of the Repository.
  #   #
  #   #  * The caller works on several levels of abstraction.
  #   #
  #   #  * It doesn't express a clear intent, it's just a chain of methods.
  #   #
  #   #  * The caller can't be easily tested in isolation.
  #   #
  #   #  * If we change the storage, we are forced to change the code of the
  #   #    caller(s).
  #
  #   ArticleRepository.new.where(author_id: 23).order(:published_at).limit(8)
  #
  #
  #
  #   # This is a huge improvement:
  #   #
  #   #  * The caller doesn't know how the repository fetches the entities.
  #   #
  #   #  * The caller works on a single level of abstraction.
  #   #    It doesn't even know about records, only works with entities.
  #   #
  #   #  * It expresses a clear intent.
  #   #
  #   #  * The caller can be easily tested in isolation.
  #   #    It's just a matter of stubbing this method.
  #   #
  #   #  * If we change the storage, the callers aren't affected.
  #
  #   ArticleRepository.new.most_recent_by_author(author)
  #
  #   class ArticleRepository < Hanami::Repository
  #     def most_recent_by_author(author, limit = 8)
  #       articles.
  #         where(author_id: author.id).
  #           order(:published_at).
  #           limit(limit)
  #     end
  #   end
  #
  # @since 0.1.0
  #
  # @see Hanami::Entity
  # @see http://martinfowler.com/eaaCatalog/repository.html
  # @see http://en.wikipedia.org/wiki/Dependency_inversion_principle
  class Repository < ROM::Repository::Root
    # Plugins for database commands
    #
    # @since 0.7.0
    # @api private
    #
    # @see Hanami::Model::Plugins
    COMMAND_PLUGINS = %i[schema mapping timestamps].freeze

    # Configuration
    #
    # @since 0.7.0
    # @api private
    def self.configuration
      Hanami::Model.configuration
    end

    # Container
    #
    # @since 0.7.0
    # @api private
    def self.container
      Hanami::Model.container
    end

    # Define a new ROM::Command while preserving the defaults used by Hanami itself.
    #
    # It allows the user to define a new command to, for example,
    # create many records at the same time and still get entities back.
    #
    # The first argument is the command and relation it will operate on.
    #
    # @return [ROM::Command] the created command
    #
    # @example
    #   # In this example, calling the create_many method with and array of data,
    #   # would result in the creation of records and return an Array of Task entities.
    #
    #   class TaskRepository < Hanami::Repository
    #     def create_many(data)
    #       command(create: :tasks, result: :many).call(data)
    #     end
    #   end
    #
    # @since 1.2.0
    def command(*args, **opts, &block)
      opts[:use] = COMMAND_PLUGINS | Array(opts[:use])
      opts[:mapper] = opts.fetch(:mapper, Model::MappedRelation.mapper_name)
      super(*args, **opts, &block)
    end

    # Define a database relation, which describes how data is fetched from the
    # database.
    #
    # It auto-infers the underlying database table.
    #
    # @since 0.7.0
    # @api private
    #
    def self.define_relation
      a = @associations
      s = @schema

      configuration.relation(relation) do
        if s.nil?
          schema(infer: true) do
            associations(&a) unless a.nil?
          end
        else
          schema(&s)
        end
      end

      relations(relation)
      root(relation)
      class_eval %{
        def #{relation}
          Hanami::Model::MappedRelation.new(@#{relation})
        end
      }, __FILE__, __LINE__ - 4
    end

    # Defines the mapping between a database table and an entity.
    #
    # It's also responsible to associate table columns to entity attributes.
    #
    # @since 0.7.0
    # @api private
    #
    def self.define_mapping
      self.entity = Utils::Class.load!(entity_name)
      e = entity
      m = @mapping

      blk = lambda do |_|
        model       e
        register_as Model::MappedRelation.mapper_name
        instance_exec(&m) unless m.nil?
      end

      root = self.root
      configuration.mappers { define(root, &blk) }
      configuration.define_mappings(root, &blk)
      configuration.register_entity(relation, entity_name.underscore, e)
    end

    # It defines associations, by adding relations to the repository
    #
    # @since 0.7.0
    # @api private
    #
    # @see Hanami::Model::Associations::Dsl
    def self.define_associations
      Model::Associations::Dsl.new(self, &@associations) unless @associations.nil?
    end

    # Declare associations for the repository
    #
    # NOTE: This is an experimental feature
    #
    # @since 0.7.0
    # @api private
    #
    # @example
    #   class BookRepository < Hanami::Repository
    #     associations do
    #       has_many :books
    #     end
    #   end
    def self.associations(&blk)
      @associations = blk
    end

    # Declare database schema
    #
    # NOTE: This should be used **only** when Hanami can't find a corresponding Ruby type for your column.
    #
    # @since 1.0.0
    #
    # @example
    #   # In this example `name` is a PostgreSQL Enum type that we want to treat like a string.
    #
    #   class ColorRepository < Hanami::Repository
    #     schema do
    #       attribute :id,         Hanami::Model::Sql::Types::Int
    #       attribute :name,       Hanami::Model::Sql::Types::String
    #       attribute :created_at, Hanami::Model::Sql::Types::DateTime
    #       attribute :updated_at, Hanami::Model::Sql::Types::DateTime
    #     end
    #   end
    def self.schema(&blk)
      @schema = blk
    end

    # Declare mapping between database columns and entity's attributes
    #
    # NOTE: This should be used **only** when there is a name mismatch (eg. in legacy databases).
    #
    # @since 0.7.0
    #
    # @example
    #   class BookRepository < Hanami::Repository
    #     self.relation = :t_operator
    #
    #     mapping do
    #       attribute :id,   from: :operator_id
    #       attribute :name, from: :s_name
    #     end
    #   end
    def self.mapping(&blk)
      @mapping = blk
    end

    # Define relations, mapping and associations
    #
    # @since 0.7.0
    # @api private
    def self.load!
      define_relation
      define_mapping
      define_associations
    end

    # @since 0.7.0
    # @api private
    #
    def self.inherited(klass)
      klass.class_eval do
        include Utils::ClassAttribute
        auto_struct true

        @associations = nil
        @mapping      = nil
        @schema       = nil

        class_attribute :entity
        class_attribute :entity_name
        class_attribute :relation

        Hanami::Utils::IO.silence_warnings do
          def self.relation=(name)
            @relation = name.to_sym
          end
        end

        self.entity_name = Model::EntityName.new(name)
        self.relation    = Model::RelationName.new(name)

        commands :create, update: :by_pk, delete: :by_pk, mapper: Model::MappedRelation.mapper_name, use: COMMAND_PLUGINS
        prepend Commands
      end

      Hanami::Model.repositories << klass
    end

    # Extend commands from ROM::Repository with error management
    #
    # @since 0.7.0
    module Commands
      # Create a new record
      #
      # @return [Hanami::Entity] a new created entity
      #
      # @raise [Hanami::Model::Error] an error in case the command fails
      #
      # @since 0.7.0
      #
      # @example Create From Hash
      #   user = UserRepository.new.create(name: 'Luca')
      #
      # @example Create From Entity
      #   entity = User.new(name: 'Luca')
      #   user   = UserRepository.new.create(entity)
      #
      #   user.id   # => 23
      #   entity.id # => nil - It doesn't mutate original entity
      def create(*args)
        super
      rescue => exception
        raise Hanami::Model::Error.for(exception)
      end

      # Update a record
      #
      # @return [Hanami::Entity] an updated entity
      #
      # @raise [Hanami::Model::Error] an error in case the command fails
      #
      # @since 0.7.0
      #
      # @example Update From Data
      #   repository = UserRepository.new
      #   user       = repository.create(name: 'Luca')
      #
      #   user       = repository.update(user.id, age: 34)
      #
      # @example Update From Entity
      #   repository = UserRepository.new
      #   user       = repository.create(name: 'Luca')
      #
      #   entity     = User.new(age: 34)
      #   user       = repository.update(user.id, entity)
      #
      #   user.age  # => 34
      #   entity.id # => nil - It doesn't mutate original entity
      def update(*args)
        super
      rescue => exception
        raise Hanami::Model::Error.for(exception)
      end

      # Delete a record
      #
      # @return [Hanami::Entity] a deleted entity
      #
      # @raise [Hanami::Model::Error] an error in case the command fails
      #
      # @since 0.7.0
      #
      # @example
      #   repository = UserRepository.new
      #   user       = repository.create(name: 'Luca')
      #
      #   user       = repository.delete(user.id)
      def delete(*args)
        super
      rescue => exception
        raise Hanami::Model::Error.for(exception)
      end
    end

    # Initialize a new instance
    #
    # @return [Hanami::Repository] the new instance
    #
    # @since 0.7.0
    def initialize
      super(self.class.container)
    end

    # Find by primary key
    #
    # @return [Hanami::Entity,NilClass] the entity, if found
    #
    # @raise [Hanami::Model::MissingPrimaryKeyError] if the table doesn't
    #   define a primary key
    #
    # @since 0.7.0
    #
    # @example
    #   repository = UserRepository.new
    #   user       = repository.create(name: 'Luca')
    #
    #   user       = repository.find(user.id)
    def find(id)
      root.by_pk(id).as(:entity).one
    rescue => exception
      raise Hanami::Model::Error.for(exception)
    end

    # Return all the records for the relation
    #
    # @return [Array<Hanami::Entity>] all the entities
    #
    # @since 0.7.0
    #
    # @example
    #   UserRepository.new.all
    def all
      root.as(:entity).to_a
    end

    # Returns the first record for the relation
    #
    # @return [Hanami::Entity,NilClass] first entity, if any
    #
    # @since 0.7.0
    #
    # @example
    #   UserRepository.new.first
    def first
      root.as(:entity).limit(1).one
    end

    # Returns the last record for the relation
    #
    # @return [Hanami::Entity,NilClass] last entity, if any
    #
    # @since 0.7.0
    #
    # @example
    #   UserRepository.new.last
    def last
      root.as(:entity).limit(1).reverse.one
    end

    # Deletes all the records from the relation
    #
    # @since 0.7.0
    #
    # @example
    #   UserRepository.new.clear
    def clear
      root.delete
    end

    private

    # Returns an association
    #
    # NOTE: This is an experimental feature
    #
    # @since 0.7.0
    # @api private
    def assoc(target, subject = nil)
      Hanami::Model::Association.build(self, target, subject)
    end
  end
end


================================================
FILE: lib/hanami-model.rb
================================================
# frozen_string_literal: true

require "hanami/model"


================================================
FILE: script/ci
================================================
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

prepare_build() {
  if [ -d coverage ]; then
    rm -rf coverage
  fi
}

print_ruby_version() {
  echo "Using $(ruby -v)"
  echo
}

run_code_quality_checks() {
  bundle exec rubocop .
}

run_unit_tests() {
  bundle exec rake spec:unit --trace
}

upload_code_coverage() {
  bundle exec rake codecov:upload
}

main() {
  prepare_build
  print_ruby_version
  run_code_quality_checks
  run_unit_tests
  upload_code_coverage
}

main


================================================
FILE: spec/integration/hanami/model/associations/belongs_to_spec.rb
================================================
# frozen_string_literal: true

RSpec.describe "Associations (belongs_to)" do
  it "returns nil if association wasn't preloaded" do
    repository = BookRepository.new
    book       = repository.create(name: "L")
    found      = repository.find(book.id)

    expect(found.author).to be(nil)
  end

  it "preloads the associated record" do
    repository = BookRepository.new
    author = AuthorRepository.new.create(name: "Michel Foucault")
    book   = repository.create(author_id: author.id, title: "Surveiller et punir")
    found = repository.find_with_author(book.id)

    expect(found).to eq(book)
    expect(found.author).to eq(author)
  end

  it "returns an author" do
    repository = BookRepository.new
    author = AuthorRepository.new.create(name: "Maurice Leblanc")
    book   = repository.create(author_id: author.id, title: "L'Aguille Creuse")
    found = repository.author_for(book)

    expect(found).to eq(author)
  end

  it "returns nil if there's no associated record" do
    repository = BookRepository.new
    book = repository.create(title: "The no author book")

    expect { repository.find_with_author(book.id) }.to_not raise_error
  end
end


================================================
FILE: spec/integration/hanami/model/associations/has_many_spec.rb
================================================
# frozen_string_literal: true

RSpec.describe "Associations (has_many)" do
  let(:authors) { AuthorRepository.new }
  let(:books) { BookRepository.new }

  it "returns nil if association wasn't preloaded" do
    author = authors.create(name: "L")
    found = authors.find(author.id)

    expect(found.books).to be_nil
  end

  it "preloads associated records" do
    author = authors.create(name: "Umberto Eco")
    book = books.create(author_id: author.id, title: "Foucault Pendulum")

    found = authors.find_with_books(author.id)

    expect(found).to eq(author)
    expect(found.books).to eq([book])
  end

  it "creates an object with a collection of associated objects" do
    author = authors.create_with_books(name: "Henry Thoreau", books: [{title: "Walden"}])

    expect(author).to be_an_instance_of(Author)
    expect(author.name).to eq("Henry Thoreau")
    expect(author.books).to be_an_instance_of(Array)
    expect(author.books.first).to be_an_instance_of(Book)
    expect(author.books.first.title).to eq("Walden")
  end

  it "creates associated records when it receives a collection of serializable data" do
    author = authors.create_with_books(name: "Sandi Metz", books: [BaseParams.new(title: "Practical Object-Oriented Design in Ruby")])

    expect(author).to be_an_instance_of(Author)
    expect(author.name).to eq("Sandi Metz")
    expect(author.books).to be_an_instance_of(Array)
    expect(author.books.first).to be_an_instance_of(Book)
    expect(author.books.first.title).to eq("Practical Object-Oriented Design in Ruby")
  end

  ##############################################################################
  # OPERATIONS                                                                 #
  ##############################################################################

  ##
  # ADD
  #
  it "adds an object to the collection" do
    author = authors.create(name: "Alexandre Dumas")
    book = authors.add_book(author, title: "The Count of Monte Cristo")

    expect(book.id).to_not be_nil
    expect(book.title).to eq("The Count of Monte Cristo")
    expect(book.author_id).to eq(author.id)
  end

  it "adds an object to the collection with serializable data" do
    author = authors.create(name: "David Foster Wallace")
    book = authors.add_book(author, BaseParams.new(title: "Infinite Jest"))

    expect(book.id).to_not be_nil
    expect(book.title).to eq("Infinite Jest")
    expect(book.author_id).to eq(author.id)
  end

  ##
  # REMOVE
  #
  it "removes an object from the collection" do
    authors = AuthorRepository.new
    books = BookRepository.new

    # Book under test
    author = authors.create(name: "Douglas Adams")
    book = books.create(author_id: author.id, title: "The Hitchhiker's Guide to the Galaxy")

    # Different book
    a = authors.create(name: "William Finnegan")
    b = books.create(author_id: a.id, title: "Barbarian Days: A Surfing Life")

    authors.remove_book(author, book.id)

    # Check the book under test has removed foreign key
    found_book = books.find(book.id)
    expect(found_book).to_not be_nil
    expect(found_book.author_id).to be_nil

    found_author = authors.find_with_books(author.id)
    expect(found_author.books.map(&:id)).to_not include(found_book.id)

    # Check that the other book was left untouched
    found_b = books.find(b.id)
    expect(found_b.author_id).to eq(a.id)
  end

  ##
  # TO_A
  #
  it "returns an array of books" do
    author = authors.create(name: "Nikolai Gogol")
    expected = books.create(author_id: author.id, title: "Dead Souls")
    expect(expected).to be_an_instance_of(Book)

    actual = authors.books_for(author).to_a
    expect(actual).to eq([expected])
  end

  ##
  # EACH
  #
  it "iterates through the books" do
    author = authors.create(name: "José Saramago")
    expected = books.create(author_id: author.id, title: "The Cave")

    actual = []
    authors.books_for(author).each do |book|
      expect(book).to be_an_instance_of(Book)
      actual << book
    end

    expect(actual).to eq([expected])
  end

  ##
  # MAP
  #
  it "iterates through the books and returns an array" do
    author = authors.create(name: "José Saramago")
    expected = books.create(author_id: author.id, title: "The Cave")
    expect(expected).to be_an_instance_of(Book)

    actual = authors.books_for(author).map { |book| book }
    expect(actual).to eq([expected])
  end

  ##
  # COUNT
  #
  it "returns the count of the associated books" do
    author = authors.create(name: "Fyodor Dostoevsky")
    books.create(author_id: author.id, title: "Crime and Punishment")
    books.create(author_id: author.id, title: "The Brothers Karamazov")

    expect(authors.books_count(author)).to eq(2)
  end

  it "returns the count of on sale associated books" do
    author = authors.create(name: "Steven Pinker")
    books.create(author_id: author.id, title: "The Sense of Style", on_sale: true)

    expect(authors.on_sales_books_count(author)).to eq(1)
  end

  ##
  # DELETE
  #
  it "deletes all the books" do
    author = authors.create(name: "Grazia Deledda")
    book = books.create(author_id: author.id, title: "Reeds In The Wind")

    authors.delete_books(author)

    expect(books.find(book.id)).to be_nil
  end

  it "deletes scoped books" do
    author = authors.create(name: "Harper Lee")
    book = books.create(author_id: author.id, title: "To Kill A Mockingbird")
    on_sale = books.create(author_id: author.id, title: "Go Set A Watchman", on_sale: true)

    authors.delete_on_sales_books(author)

    expect(books.find(book.id)).to eq(book)
    expect(books.find(on_sale.id)).to be_nil
  end

  context "raises a Hanami::Model::Error wrapped exception on" do
    it "#create" do
      expect do
        authors.create_with_books(name: "Noam Chomsky")
      end.to raise_error Hanami::Model::Error
    end

    it "#add" do
      author = authors.create(name: "Machado de Assis")
      expect do
        authors.add_book(author, title: "O Alienista", on_sale: nil)
      end.to raise_error Hanami::Model::NotNullConstraintViolationError
    end

    # skipped spec
    it "#remove"
  end
end


================================================
FILE: spec/integration/hanami/model/associations/has_one_spec.rb
================================================
# frozen_string_literal: true

require "spec_helper"

RSpec.describe "Associations (has_one)" do
  extend PlatformHelpers

  let(:users) { UserRepository.new }
  let(:avatars) { AvatarRepository.new }

  it "returns nil if the association wasn't preloaded" do
    user       = users.create(name: "John Doe")
    found      = users.find(user.id)

    expect(found.avatar).to be_nil
  end

  it "preloads the associated record" do
    user       = users.create(name: "Baruch Spinoza")
    avatar     = avatars.create(user_id: user.id, url: "http://www.notarealurl.com/avatar.png")
    found      = users.find_with_avatar(user.id)
    expect(found).to eq(user)
    expect(found.avatar).to eq(avatar)
  end

  it "returns an Avatar" do
    user       = users.create(name: "Simone de Beauvoir")
    avatar     = avatars.create(user_id: user.id, url: "http://www.notarealurl.com/simone.png")
    found      = users.avatar_for(user)

    expect(found).to eq(avatar)
  end

  it "returns nil if the association was preloaded but no associated object is set" do
    user       = users.create(name: "Henry Jenkins")
    found      = users.find_with_avatar(user.id)

    expect(found).to eq(user)
    expect(found.avatar).to be_nil
  end

  context "#add" do
    it "adds an an Avatar to an existing User" do
      user = users.create(name: "Jean Paul-Sartre")
      avatar = users.add_avatar(user, url: "http://www.notarealurl.com/sartre.png")
      found = users.find_with_avatar(user.id)

      expect(found).to eq(user)
      expect(found.avatar.id).to eq(avatar.id)
      expect(found.avatar.url).to eq("http://www.notarealurl.com/sartre.png")
    end

    it "adds an an Avatar to an existing User when serializable data is received" do
      user = users.create(name: "Jean Paul-Sartre")
      avatar = users.add_avatar(user, BaseParams.new(url: "http://www.notarealurl.com/sartre.png"))
      found = users.find_with_avatar(user.id)

      expect(found).to eq(user)
      expect(found.avatar.id).to eq(avatar.id)
      expect(found.avatar.url).to eq("http://www.notarealurl.com/sartre.png")
    end
  end

  context "#update" do
    it "updates the avatar" do
      user = users.create_with_avatar(name: "Bakunin", avatar: {url: "bakunin.jpg"})
      users.update_avatar(user, url: url = "http://history.com/bakunin.png")

      found = users.find_with_avatar(user.id)

      expect(found).to eq(user)
      expect(found.avatar).to eq(user.avatar)
      expect(found.avatar.url).to eq(url)
    end

    it "updates the avatar when serializable data is received" do
      user = users.create_with_avatar(name: "Bakunin", avatar: {url: "bakunin.jpg"})
      users.update_avatar(user, BaseParams.new(url: url = "http://history.com/bakunin.png"))

      found = users.find_with_avatar(user.id)

      expect(found).to eq(user)
      expect(found.avatar).to eq(user.avatar)
      expect(found.avatar.url).to eq(url)
    end
  end

  context "#create" do
    it "creates a User and an Avatar" do
      user = users.create_with_avatar(name: "Lao Tse", avatar: {url: "http://lao-tse.io/me.jpg"})
      found = users.find_with_avatar(user.id)

      expect(found.name).to eq(user.name)
      expect(found.avatar).to eq(user.avatar)
      expect(found.avatar.url).to eq("http://lao-tse.io/me.jpg")
    end

    it "creates a User and an Avatar when serializable data is received" do
      user = users.create_with_avatar(name: "Lao Tse", avatar: BaseParams.new(url: "http://lao-tse.io/me.jpg"))
      found = users.find_with_avatar(user.id)

      expect(found.name).to eq(user.name)
      expect(found.avatar).to eq(user.avatar)
      expect(found.avatar.url).to eq("http://lao-tse.io/me.jpg")
    end
  end

  context "#delete" do
    it "removes the Avatar" do
      user = users.create_with_avatar(name: "Bob Ross", avatar: {url: "http://bobross/happy_little_avatar.jpg"})
      other = users.create_with_avatar(name: "Candido Portinari", avatar: {url: "some_mugshot.jpg"})
      users.remove_avatar(user)
      found = users.find_with_avatar(user.id)
      other_found = users.find_with_avatar(other.id)

      expect(found.avatar).to be_nil
      expect(other_found.avatar).to be_an Avatar
    end
  end

  context "#replace" do
    it "replaces the associated object" do
      user = users.create_with_avatar(name: "Frank Herbert", avatar: {url: "http://not-real.com/avatar.jpg"})
      users.replace_avatar(user, url: "http://totally-correct.com/avatar.jpg")
      found = users.find_with_avatar(user.id)

      expect(found.avatar).to_not eq(user.avatar)

      expect(avatars.by_user(user.id).size).to eq(1)
    end

    it "replaces the associated object when serializable data is received" do
      user = users.create_with_avatar(name: "Frank Herbert", avatar: {url: "http://not-real.com/avatar.jpg"})
      users.replace_avatar(user, BaseParams.new(url: "http://totally-correct.com/avatar.jpg"))
      found = users.find_with_avatar(user.id)

      expect(found.avatar).to_not eq(user.avatar)

      expect(avatars.by_user(user.id).size).to eq(1)
    end
  end

  context "raises a Hanami::Model::Error wrapped exception on" do
    it "#create" do
      expect do
        users.create_with_avatar(name: "Noam Chomsky")
      end.to raise_error Hanami::Model::Error
    end

    it "#add" do
      user = users.create_with_avatar(name: "Stephen Fry", avatar: {url: "fry_mugshot.png"})
      expect { users.add_avatar(user, url: "new_mugshot.png") }.to raise_error Hanami::Model::UniqueConstraintViolationError
    end

    # by default it seems that MySQL allows you to update a NOT NULL column to a NULL value
    unless_platform(db: :mysql) do
      it "#update" do
        user = users.create_with_avatar(name: "Dan North", avatar: {url: "bdd_creator.png"})

        expect do
          users.update_avatar(user, url: nil)
        end.to raise_error Hanami::Model::NotNullConstraintViolationError
      end
    end

    it "#replace" do
      user = users.create_with_avatar(name: "Eric Evans", avatar: {url: "ddd_man.png"})
      expect { users.replace_avatar(user, url: nil) }.to raise_error Hanami::Model::NotNullConstraintViolationError
    end
  end
end


================================================
FILE: spec/integration/hanami/model/associations/many_to_many_spec.rb
================================================
# frozen_string_literal: true

RSpec.describe "Associations (has_many :through)" do
  #### REPOS
  let(:books) { BookRepository.new }
  let(:categories) { CategoryRepository.new }
  let(:ontologies) { BookOntologyRepository.new }

  ### ENTITIES
  let(:book) { books.create(title: "Ontology: Encyclopedia of Database Systems") }
  let(:category) { categories.create(name: "information science") }

  it "returns nil if association wasn't preloaded" do
    found = books.find(book.id)
    expect(found.categories).to be(nil)
  end

  it "preloads the associated record" do
    ontologies.create(book_id: book.id, category_id: category.id)
    found = books.find_with_categories(book.id)

    expect(found).to eq(book)
    expect(found.categories).to eq([category])
  end

  it "returns an array of Categories" do
    ontologies.create(book_id: book.id, category_id: category.id)

    found = books.categories_for(book)
    expect(found).to eq([category])
  end

  it "returns the count of on sale associated books" do
    on_sale = books.create(title: "The Sense of Style", on_sale: true)
    ontologies.create(book_id: on_sale.id, category_id: category.id)

    expect(categories.on_sales_books_count(category)).to eq(1)
  end

  context "#add" do
    it "adds an object to the collection" do
      books.add_category(book, category)

      found_book = books.find_with_categories(book.id)
      found_category = categories.find_with_books(category.id)

      expect(found_book).to eq(book)
      expect(found_book.categories).to eq([category])
      expect(found_category).to eq(category)
      expect(found_category.books).to eq([book])
    end

    it "associates a collection of records" do
      other_book = books.create(title: "Ontological Engineering")
      categories.add_books(category, book, other_book)
      found = categories.find_with_books(category.id)

      expect(found.books).to match_array([book, other_book])
    end
  end

  context "#delete" do
    it "removes all association information" do
      books.add_category(book, category)
      categorized = books.find_with_categories(book.id)
      books.clear_categories(book)
      found = books.find_with_categories(book.id)

      expect(categorized.categories).to be_an Array
      expect(categorized.categories).to match_array([category])
      expect(found.categories).to be_empty
      expect(found).to eq(categorized)
    end

    it "does not touch other books" do
      other_book = books.create(title: "Do not meddle with")
      books.add_category(other_book, category)
      books.add_category(book, category)

      books.clear_categories(book)
      found = books.find_with_categories(book.id)
      other_found = books.find_with_categories(other_book.id)

      expect(found).to eq(book)
      expect(other_book).to eq(other_found)
      expect(other_found.categories).to eq([category])
      expect(found.categories).to be_empty
    end
  end

  context "#remove" do
    it "removes the desired association" do
      to_remove = books.create(title: "The Life of a Stoic")
      books.add_category(to_remove, category)

      categories.remove_book(category, to_remove.id)
      found = categories.find_with_books(category.id)

      expect(found.books).to_not include(to_remove)
    end
  end

  context "collection methods" do
    it "returns an array of books" do
      ontologies.create(book_id: book.id, category_id: category.id)

      actual = categories.books_for(category).to_a
      expect(actual).to eq([book])
    end

    it "iterates through the categories" do
      ontologies.create(book_id: book.id, category_id: category.id)
      actual = []

      categories.books_for(category).each do |book|
        expect(book).to be_an_instance_of(Book)
        actual << book
      end

      expect(actual).to eq([book])
    end

    it "iterates through the books and returns an array" do
      ontologies.create(book_id: book.id, category_id: category.id)

      actual = categories.books_for(category).map(&:id)
      expect(actual).to eq([book.id])
    end

    it "returns the count of the associated books" do
      other_book = books.create(title: "Practical Ontologies for Information Professionals")
      ontologies.create(book_id: book.id, category_id: category.id)
      ontologies.create(book_id: other_book.id, category_id: category.id)

      expect(categories.books_count(category)).to eq(2)
    end
  end

  context "raises a Hanami::Model::Error wrapped exception on" do
    it "#add" do
      expect do
        categories.add_books(category, id: -2)
      end.to raise_error Hanami::Model::ForeignKeyConstraintViolationError
    end
  end
end


================================================
FILE: spec/integration/hanami/model/associations/relation_alias_spec.rb
================================================
# frozen_string_literal: true

RSpec.describe "Alias (:as)  support for associations" do
  let(:users) { UserRepository.new }
  let(:posts) { PostRepository.new }
  let(:comments) { CommentRepository.new }

  it "the attribute is named after the association" do
    user = users.create(name: "Jules Verne")
    post = posts.create(title: "World Traveling made easy", user_id: user.id)

    post_found = posts.find_with_author(post.id)
    expect(post_found.author).to eq(user)

    user_found = users.find_with_threads(user.id)
    expect(user_found.threads).to match_array([post])
  end

  it "it works with nested aggregates" do
    user = users.create(name: "Jules Verne")
    post = posts.create(title: "World Traveling made easy", user_id: user.id)
    commenter = users.create(name: "Thomas Reid")
    comments.create(user_id: commenter.id, post_id: post.id)

    found = posts.feed_for(post.id)
    expect(found.author).to eq(user)
    expect(found.comments[0].user).to eq(commenter)
  end

  context "#assoc support (calling assoc by the alias)" do
    it "for #belongs_to" do
      user = users.create(name: "Jules Verne")
      post = posts.create(title: "World Traveling made easy", user_id: user.id)
      commenter = users.create(name: "Thomas Reid")
      comment = comments.create(user_id: commenter.id, post_id: post.id)

      found_author = posts.author_for(post)
      expect(found_author).to eq(user)

      found_commenter = comments.commenter_for(comment)
      expect(found_commenter).to eq(commenter)
    end

    it "for #has_many" do
      user = users.create(name: "Jules Verne")
      post = posts.create(title: "World Traveling made easy", user_id: user.id)

      found_threads = users.threads_for(user)
      expect(found_threads).to match_array [post]
    end

    it "for #has_many :through" do
      user = users.create(name: "Jules Verne")
      post = posts.create(title: "World Traveling made easy", user_id: user.id)
      commenter = users.create(name: "Thomas Reid")
      comments.create(user_id: commenter.id, post_id: post.id)

      commenters = posts.commenters_for(post)

      expect(commenters).to match_array([commenter])
    end
  end
end


================================================
FILE: spec/integration/hanami/model/migration/mysql.rb
================================================
# frozen_string_literal: true

RSpec.shared_examples "migration_integration_mysql" do
  before do
    @schema = Pathname.new("#{__dir__}/../../../../../tmp/schema.sql").expand_path
    @connection = Sequel.connect(ENV["HANAMI_DATABASE_URL"])

    Hanami::Model::Migrator::Adapter.for(Hanami::Model.configuration).dump
  end

  describe "columns" do
    it "defines column types" do
      table = @connection.schema(:column_types)

      name, options = table[0]
      expect(name).to eq(:integer1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[1]
      expect(name).to eq(:integer2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[2]
      expect(name).to eq(:integer3)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[3]
      expect(name).to eq(:string1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("varchar(255)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[4]
      expect(name).to eq(:string2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("varchar(3)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[5]
      expect(name).to eq(:string5)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("varchar(50)")
      expect(options.fetch(:max_length)).to eq(50)
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[6]
      expect(name).to eq(:string6)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("char(255)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[7]
      expect(name).to eq(:string7)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("char(64)")
      expect(options.fetch(:max_length)).to eq(64)
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[8]
      expect(name).to eq(:string8)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("text")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[9]
      expect(name).to eq(:file1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:blob)
      expect(options.fetch(:db_type)).to eq("blob")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[10]
      expect(name).to eq(:file2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:blob)
      expect(options.fetch(:db_type)).to eq("blob")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[11]
      expect(name).to eq(:number1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[12]
      expect(name).to eq(:number2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("bigint")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[13]
      expect(name).to eq(:number3)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:float)
      expect(options.fetch(:db_type)).to eq("double")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[14]
      expect(name).to eq(:number4)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("decimal(10,0)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[15]
      expect(name).to eq(:number5)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      # expect(options.fetch(:type)).to eq(:decimal)
      expect(options.fetch(:db_type)).to eq("decimal(10,0)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[16]
      expect(name).to eq(:number6)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:decimal)
      expect(options.fetch(:db_type)).to eq("decimal(10,2)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[17]
      expect(name).to eq(:number7)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("decimal(10,0)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[18]
      expect(name).to eq(:date1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:date)
      expect(options.fetch(:db_type)).to eq("date")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[19]
      expect(name).to eq(:date2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:datetime)
      expect(options.fetch(:db_type)).to eq("datetime")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[20]
      expect(name).to eq(:time1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:datetime)
      expect(options.fetch(:db_type)).to eq("datetime")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[21]
      expect(name).to eq(:time2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:time)
      expect(options.fetch(:db_type)).to eq("time")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[22]
      expect(name).to eq(:boolean1)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:boolean)
      expect(options.fetch(:db_type)).to eq("tinyint(1)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[23]
      expect(name).to eq(:boolean2)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq(nil)
      expect(options.fetch(:type)).to eq(:boolean)
      expect(options.fetch(:db_type)).to eq("tinyint(1)")
      expect(options.fetch(:primary_key)).to eq(false)
    end

    it "defines column defaults" do
      table = @connection.schema(:default_values)

      name, options = table[0]
      expect(name).to eq(:a)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("23")
      expect(options.fetch(:ruby_default)).to eq(23)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[1]
      expect(name).to eq(:b)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("Hanami")
      expect(options.fetch(:ruby_default)).to eq("Hanami")
      expect(options.fetch(:type)).to eq(:string)
      expect(options.fetch(:db_type)).to eq("varchar(255)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[2]
      expect(name).to eq(:c)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("-1")
      expect(options.fetch(:ruby_default)).to eq(-1)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("int")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[3]
      expect(name).to eq(:d)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("0")
      expect(options.fetch(:ruby_default)).to eq(0)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("bigint")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[4]
      expect(name).to eq(:e)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("3.14")
      expect(options.fetch(:ruby_default)).to eq(3.14)
      expect(options.fetch(:type)).to eq(:float)
      expect(options.fetch(:db_type)).to eq("double")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[5]
      expect(name).to eq(:f)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("1")
      expect(options.fetch(:ruby_default)).to eq(1.0)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("decimal(10,0)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[6]
      expect(name).to eq(:g)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("943943")
      expect(options.fetch(:ruby_default)).to eq(943_943)
      expect(options.fetch(:type)).to eq(:integer)
      expect(options.fetch(:db_type)).to eq("decimal(10,0)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[10]
      expect(name).to eq(:k)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("1")
      expect(options.fetch(:ruby_default)).to eq(true)
      expect(options.fetch(:type)).to eq(:boolean)
      expect(options.fetch(:db_type)).to eq("tinyint(1)")
      expect(options.fetch(:primary_key)).to eq(false)

      name, options = table[11]
      expect(name).to eq(:l)

      expect(options.fetch(:allow_null)).to eq(true)
      expect(options.fetch(:default)).to eq("0")
      expect(options.fetch(:ruby_default)).to eq(false)
      expect(options.fetch(:type)).to
Download .txt
gitextract_p2apyb1u/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .jrubyrc
├── .rspec
├── .rubocop.yml
├── .yardopts
├── CHANGELOG.md
├── Gemfile
├── LICENSE.md
├── README.md
├── Rakefile
├── hanami-model.gemspec
├── lib/
│   ├── hanami/
│   │   ├── entity/
│   │   │   └── schema.rb
│   │   ├── entity.rb
│   │   ├── model/
│   │   │   ├── association.rb
│   │   │   ├── associations/
│   │   │   │   ├── belongs_to.rb
│   │   │   │   ├── dsl.rb
│   │   │   │   ├── has_many.rb
│   │   │   │   ├── has_one.rb
│   │   │   │   └── many_to_many.rb
│   │   │   ├── configuration.rb
│   │   │   ├── configurator.rb
│   │   │   ├── entity_name.rb
│   │   │   ├── error.rb
│   │   │   ├── mapped_relation.rb
│   │   │   ├── mapping.rb
│   │   │   ├── migration.rb
│   │   │   ├── migrator/
│   │   │   │   ├── adapter.rb
│   │   │   │   ├── connection.rb
│   │   │   │   ├── logger.rb
│   │   │   │   ├── mysql_adapter.rb
│   │   │   │   ├── postgres_adapter.rb
│   │   │   │   └── sqlite_adapter.rb
│   │   │   ├── migrator.rb
│   │   │   ├── plugins/
│   │   │   │   ├── mapping.rb
│   │   │   │   ├── schema.rb
│   │   │   │   └── timestamps.rb
│   │   │   ├── plugins.rb
│   │   │   ├── relation_name.rb
│   │   │   ├── sql/
│   │   │   │   ├── console.rb
│   │   │   │   ├── consoles/
│   │   │   │   │   ├── abstract.rb
│   │   │   │   │   ├── mysql.rb
│   │   │   │   │   ├── postgresql.rb
│   │   │   │   │   └── sqlite.rb
│   │   │   │   ├── entity/
│   │   │   │   │   └── schema.rb
│   │   │   │   ├── types/
│   │   │   │   │   └── schema/
│   │   │   │   │       └── coercions.rb
│   │   │   │   └── types.rb
│   │   │   ├── sql.rb
│   │   │   ├── types.rb
│   │   │   └── version.rb
│   │   ├── model.rb
│   │   └── repository.rb
│   └── hanami-model.rb
├── script/
│   └── ci
└── spec/
    ├── integration/
    │   └── hanami/
    │       └── model/
    │           ├── associations/
    │           │   ├── belongs_to_spec.rb
    │           │   ├── has_many_spec.rb
    │           │   ├── has_one_spec.rb
    │           │   ├── many_to_many_spec.rb
    │           │   └── relation_alias_spec.rb
    │           ├── migration/
    │           │   ├── mysql.rb
    │           │   ├── postgresql.rb
    │           │   └── sqlite.rb
    │           ├── migration_spec.rb
    │           └── repository/
    │               ├── base_spec.rb
    │               ├── command_spec.rb
    │               └── legacy_spec.rb
    ├── spec_helper.rb
    ├── support/
    │   ├── database/
    │   │   └── strategies/
    │   │       ├── abstract.rb
    │   │       ├── mysql.rb
    │   │       ├── postgresql.rb
    │   │       ├── sql.rb
    │   │       └── sqlite.rb
    │   ├── database.rb
    │   ├── fixtures/
    │   │   ├── database_migrations/
    │   │   │   ├── 20150612081248_column_types.rb
    │   │   │   ├── 20150612084656_default_values.rb
    │   │   │   ├── 20150612093458_null_constraints.rb
    │   │   │   ├── 20150612093810_column_indexes.rb
    │   │   │   ├── 20150612094740_primary_keys.rb
    │   │   │   ├── 20150612115204_foreign_keys.rb
    │   │   │   ├── 20150612122233_table_constraints.rb
    │   │   │   ├── 20150612124205_table_alterations.rb
    │   │   │   ├── 20160830094800_create_users.rb
    │   │   │   ├── 20160830094851_create_authors.rb
    │   │   │   ├── 20160830094941_create_books.rb
    │   │   │   ├── 20160830095033_create_t_operator.rb
    │   │   │   ├── 20160905125728_create_source_files.rb
    │   │   │   ├── 20160909150704_create_avatars.rb
    │   │   │   ├── 20161104143844_create_warehouses.rb
    │   │   │   ├── 20161114094644_create_products.rb
    │   │   │   ├── 20170103142428_create_colors.rb
    │   │   │   ├── 20170124081339_create_labels.rb
    │   │   │   ├── 20170517115243_create_tokens.rb
    │   │   │   ├── 20170519172332_create_categories.rb
    │   │   │   └── 20171002201227_create_posts_and_comments.rb
    │   │   ├── empty_migrations/
    │   │   │   └── .gitkeep
    │   │   └── migrations/
    │   │       ├── 20160831073534_create_reviews.rb
    │   │       └── 20160831090612_add_rating_to_reviews.rb
    │   ├── fixtures.rb
    │   ├── platform/
    │   │   ├── ci.rb
    │   │   ├── db.rb
    │   │   ├── engine.rb
    │   │   ├── matcher.rb
    │   │   └── os.rb
    │   ├── platform.rb
    │   ├── rspec.rb
    │   └── test_io.rb
    └── unit/
        └── hanami/
            ├── entity/
            │   ├── automatic_schema_spec.rb
            │   ├── manual_schema/
            │   │   ├── base_spec.rb
            │   │   ├── strict_spec.rb
            │   │   └── types_spec.rb
            │   ├── schema/
            │   │   ├── definition_spec.rb
            │   │   └── schemaless_spec.rb
            │   ├── schema_spec.rb
            │   └── schemaless_spec.rb
            ├── entity_spec.rb
            └── model/
                ├── check_constraint_validation_error_spec.rb
                ├── configuration_spec.rb
                ├── constraint_violation_error_spec.rb
                ├── disconnect_spec.rb
                ├── error_spec.rb
                ├── foreign_key_constraint_violation_error_spec.rb
                ├── load_spec.rb
                ├── mapped_relation_spec.rb
                ├── migrator/
                │   ├── adapter_spec.rb
                │   ├── connection_spec.rb
                │   ├── mysql.rb
                │   ├── postgresql.rb
                │   └── sqlite.rb
                ├── migrator_spec.rb
                ├── not_null_constraint_violation_error_spec.rb
                ├── sql/
                │   ├── console/
                │   │   ├── mysql.rb
                │   │   ├── postgresql.rb
                │   │   └── sqlite.rb
                │   ├── console_spec.rb
                │   ├── entity/
                │   │   └── schema/
                │   │       ├── automatic_spec.rb
                │   │       └── mapping_spec.rb
                │   └── schema/
                │       ├── array_spec.rb
                │       ├── bool_spec.rb
                │       ├── date_spec.rb
                │       ├── date_time_spec.rb
                │       ├── decimal_spec.rb
                │       ├── float_spec.rb
                │       ├── hash_spec.rb
                │       ├── int_spec.rb
                │       ├── string_spec.rb
                │       └── time_spec.rb
                ├── sql_spec.rb
                ├── unique_constraint_violation_error_spec.rb
                └── version_spec.rb
Download .txt
SYMBOL INDEX (773 symbols across 69 files)

FILE: lib/hanami/entity.rb
  type Hanami (line 5) | module Hanami
    class Entity (line 54) | class Entity
      type Types (line 60) | module Types
      type ClassMethods (line 68) | module ClassMethods
        function attributes (line 86) | def attributes(type = nil, &blk)
        function schema= (line 97) | def schema=(value)
      method inherited (line 110) | def self.inherited(klass)
      method initialize (line 126) | def initialize(attributes = nil)
      method id (line 136) | def id
      method method_missing (line 146) | def method_missing(method_name, *)
      method == (line 161) | def ==(other)
      method hash (line 171) | def hash
      method freeze (line 178) | def freeze
      method to_h (line 188) | def to_h
      method attribute? (line 201) | def attribute?(name)
      method respond_to_missing? (line 213) | def respond_to_missing?(name, _include_all)

FILE: lib/hanami/entity/schema.rb
  type Hanami (line 6) | module Hanami
    class Entity (line 7) | class Entity
      class Schema (line 56) | class Schema
        class Schemaless (line 61) | class Schemaless
          method initialize (line 64) | def initialize
          method call (line 74) | def call(attributes)
          method attribute? (line 84) | def attribute?(_name)
        class Definition (line 93) | class Definition
          class Dsl (line 97) | class Dsl
            method build (line 108) | def self.build(type, &blk)
            method initialize (line 118) | def initialize(&blk)
            method attribute (line 149) | def attribute(name, type)
            method to_h (line 155) | def to_h
          method initialize (line 168) | def initialize(type = nil, &blk)
          method call (line 185) | def call(attributes)
          method attribute? (line 201) | def attribute?(name)
        method initialize (line 224) | def initialize(type = nil, &blk)
        method call (line 240) | def call(attributes)
        method attribute? (line 258) | def attribute?(name)

FILE: lib/hanami/model.rb
  type Hanami (line 11) | module Hanami
    type Model (line 15) | module Model
      function configure (line 54) | def self.configure(&block)
      function configuration (line 62) | def self.configuration
      function repositories (line 68) | def self.repositories
      function container (line 74) | def self.container
      function load! (line 81) | def self.load!(&blk)
      function disconnect (line 107) | def self.disconnect

FILE: lib/hanami/model/association.rb
  type Hanami (line 9) | module Hanami
    type Model (line 10) | module Model
      class Association (line 15) | class Association
        method build (line 20) | def self.build(repository, target, subject)
        method lookup (line 29) | def self.lookup(association)

FILE: lib/hanami/model/associations/belongs_to.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Associations (line 7) | module Associations
        class BelongsTo (line 12) | class BelongsTo
          method schema_type (line 15) | def self.schema_type(entity)
          method initialize (line 41) | def initialize(repository, source, target, subject, scope = nil)
          method one (line 52) | def one
          method container (line 60) | def container
          method primary_key (line 66) | def primary_key
          method relation (line 72) | def relation(name)
          method foreign_key (line 78) | def foreign_key
          method association_keys (line 86) | def association_keys
          method association (line 95) | def association
          method _build_scope (line 101) | def _build_scope

FILE: lib/hanami/model/associations/dsl.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Associations (line 5) | module Associations
        class Dsl (line 11) | class Dsl
          method initialize (line 14) | def initialize(repository, &blk)
          method has_many (line 21) | def has_many(relation, **args)
          method has_one (line 28) | def has_one(relation, *)
          method belongs_to (line 34) | def belongs_to(relation, *)

FILE: lib/hanami/model/associations/has_many.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Associations (line 7) | module Associations
        class HasMany (line 12) | class HasMany
          method schema_type (line 15) | def self.schema_type(entity)
          method initialize (line 42) | def initialize(repository, source, target, subject, scope = nil)
          method create (line 53) | def create(data)
          method add (line 62) | def add(data)
          method remove (line 71) | def remove(id)
          method delete (line 79) | def delete
          method each (line 85) | def each(&blk)
          method map (line 91) | def map(&blk)
          method to_a (line 97) | def to_a
          method where (line 103) | def where(condition)
          method count (line 109) | def count
          method command (line 117) | def command(target, relation, options = {})
          method entity (line 123) | def entity
          method relation (line 129) | def relation(name)
          method aggregate (line 135) | def aggregate(name)
          method association (line 141) | def association(name)
          method associate (line 147) | def associate(data)
          method unassociate (line 155) | def unassociate
          method container (line 161) | def container
          method primary_key (line 167) | def primary_key
          method foreign_key (line 173) | def foreign_key
          method association_keys (line 181) | def association_keys
          method target_association (line 190) | def target_association
          method _build_scope (line 196) | def _build_scope
          method __new__ (line 204) | def __new__(new_scope)
          method serialize (line 208) | def serialize(data)

FILE: lib/hanami/model/associations/has_one.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Associations (line 7) | module Associations
        class HasOne (line 12) | class HasOne
          method schema_type (line 15) | def self.schema_type(entity)
          method initialize (line 41) | def initialize(repository, source, target, subject, scope = nil)
          method one (line 50) | def one
          method create (line 54) | def create(data)
          method add (line 62) | def add(data)
          method update (line 68) | def update(data)
          method delete (line 77) | def delete
          method replace (line 82) | def replace(data)
          method entity (line 93) | def entity
          method aggregate (line 99) | def aggregate(name)
          method command (line 105) | def command(target, relation, options = {})
          method relation (line 111) | def relation(name)
          method container (line 117) | def container
          method primary_key (line 123) | def primary_key
          method foreign_key (line 129) | def foreign_key
          method associate (line 135) | def associate(data)
          method association_keys (line 145) | def association_keys
          method _build_scope (line 153) | def _build_scope
          method serialize (line 161) | def serialize(data)

FILE: lib/hanami/model/associations/many_to_many.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Associations (line 7) | module Associations
        class ManyToMany (line 12) | class ManyToMany
          method schema_type (line 15) | def self.schema_type(entity)
          method initialize (line 44) | def initialize(repository, source, target, subject, scope = nil)
          method to_a (line 54) | def to_a
          method map (line 58) | def map(&blk)
          method each (line 62) | def each(&blk)
          method count (line 66) | def count
          method where (line 70) | def where(condition)
          method add (line 78) | def add(*data)
          method delete (line 87) | def delete
          method remove (line 93) | def remove(target_id)
          method container (line 108) | def container
          method relation (line 114) | def relation(name)
          method command (line 120) | def command(target, relation, options = {})
          method associate (line 126) | def associate(data)
          method source_primary_key (line 134) | def source_primary_key
          method source_foreign_key (line 140) | def source_foreign_key
          method association_keys (line 146) | def association_keys
          method target_foreign_key (line 154) | def target_foreign_key
          method target_primary_key (line 160) | def target_primary_key
          method association (line 168) | def association
          method _build_scope (line 175) | def _build_scope
          method __new__ (line 187) | def __new__(new_scope)
          method serialize (line 193) | def serialize(data)

FILE: lib/hanami/model/configuration.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Configuration (line 13) | class Configuration
        method initialize (line 32) | def initialize(configurator)
        method connection (line 57) | def connection
        method gateway (line 68) | def gateway
        method root (line 76) | def root
        method migrations (line 83) | def migrations
        method schema (line 90) | def schema
        method define_mappings (line 96) | def define_mappings(root, &blk)
        method register_entity (line 102) | def register_entity(plural, singular, klass)
        method define_entities_mappings (line 109) | def define_entities_mappings(container, repositories)
        method configure_gateway (line 122) | def configure_gateway
        method logger= (line 128) | def logger=(value)
        method rom (line 139) | def rom
        method load! (line 152) | def load!(repositories, &blk)
        method method_missing (line 168) | def method_missing(method_name, *args, &blk)
        method respond_to_missing? (line 178) | def respond_to_missing?(method_name, include_all)

FILE: lib/hanami/model/configurator.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      class Configurator (line 9) | class Configurator
        method build (line 40) | def self.build(&block)
        method migrations_logger (line 46) | def migrations_logger(stream = $stdout)
        method adapter (line 55) | def adapter(backend, url)
        method path (line 62) | def path(path)
        method migrations (line 68) | def migrations(path)
        method schema (line 74) | def schema(path)
        method logger (line 80) | def logger(stream, options = {})
        method gateway (line 89) | def gateway(&blk)

FILE: lib/hanami/model/entity_name.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      class EntityName (line 12) | class EntityName
        method initialize (line 22) | def initialize(name)
        method underscore (line 28) | def underscore
        method to_s (line 34) | def to_s

FILE: lib/hanami/model/error.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Error (line 10) | class Error < ::StandardError
        method for (line 17) | def self.for(exception)
        method register (line 23) | def self.register(external, internal)
        method mapping (line 29) | def self.mapping
      class DatabaseError (line 37) | class DatabaseError < Error
      class InvalidCommandError (line 43) | class InvalidCommandError < Error
        method initialize (line 46) | def initialize(message = "Invalid command")
      class ConstraintViolationError (line 54) | class ConstraintViolationError < Error
        method initialize (line 57) | def initialize(message = "Constraint has been violated")
      class UniqueConstraintViolationError (line 65) | class UniqueConstraintViolationError < ConstraintViolationError
        method initialize (line 68) | def initialize(message = "Unique constraint has been violated")
      class ForeignKeyConstraintViolationError (line 76) | class ForeignKeyConstraintViolationError < ConstraintViolationError
        method initialize (line 79) | def initialize(message = "Foreign key constraint has been violated")
      class NotNullConstraintViolationError (line 87) | class NotNullConstraintViolationError < ConstraintViolationError
        method initialize (line 90) | def initialize(message = "NOT NULL constraint has been violated")
      class CheckConstraintViolationError (line 98) | class CheckConstraintViolationError < ConstraintViolationError
        method initialize (line 101) | def initialize(message = "Check constraint has been violated")
      class UnknownDatabaseTypeError (line 109) | class UnknownDatabaseTypeError < Error
      class MissingPrimaryKeyError (line 115) | class MissingPrimaryKeyError < Error
      class UnknownAttributeError (line 121) | class UnknownAttributeError < Error
      class UnknownDatabaseAdapterError (line 127) | class UnknownDatabaseAdapterError < Error
        method initialize (line 128) | def initialize(url)

FILE: lib/hanami/model/mapped_relation.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      class MappedRelation (line 11) | class MappedRelation < SimpleDelegator
        method mapper_name (line 24) | def self.mapper_name
        method initialize (line 30) | def initialize(relation)
        method [] (line 54) | def [](attribute)

FILE: lib/hanami/model/mapping.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Mapping (line 11) | class Mapping
        method initialize (line 18) | def initialize(&blk)
        method t (line 26) | def t(name, *args)
        method model (line 31) | def model(entity)
        method register_as (line 35) | def register_as(name)
        method attribute (line 39) | def attribute(name, options)
        method process (line 47) | def process(input)
        method reverse? (line 52) | def reverse?
        method translate (line 57) | def translate(attribute)

FILE: lib/hanami/model/migration.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      class Migration (line 9) | class Migration
        method initialize (line 20) | def initialize(gateway, &block)
        method run (line 28) | def run(direction = :up)

FILE: lib/hanami/model/migrator.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      class MigrationError (line 11) | class MigrationError < Hanami::Model::Error
      class Migrator (line 17) | class Migrator
        method create (line 47) | def self.create
        method drop (line 77) | def self.drop
        method migrate (line 126) | def self.migrate(version: nil)
        method rollback (line 162) | def self.rollback(steps: 1)
        method apply (line 206) | def self.apply
        method prepare (line 248) | def self.prepare
        method version (line 267) | def self.version
        method initialize (line 279) | def initialize(configuration: self.class.configuration)
        method create (line 288) | def create
        method drop (line 296) | def drop
        method migrate (line 304) | def migrate(version: nil)
        method rollback (line 312) | def rollback(steps: 1)
        method apply (line 320) | def apply
        method prepare (line 330) | def prepare
        method version (line 343) | def version
        method configuration (line 351) | def self.configuration
        method migrations (line 373) | def migrations
        method migrations? (line 381) | def migrations?
        method delete_migrations (line 389) | def delete_migrations

FILE: lib/hanami/model/migrator/adapter.rb
  type Hanami (line 7) | module Hanami
    type Model (line 8) | module Model
      class Migrator (line 9) | class Migrator
        class Adapter (line 14) | class Adapter
          method for (line 31) | def self.for(configuration)
          method initialize (line 53) | def initialize(connection)
          method create (line 64) | def create
          method drop (line 75) | def drop
          method migrate (line 81) | def migrate(migrations, version)
          method rollback (line 91) | def rollback(migrations, steps)
          method load (line 107) | def load
          method version (line 115) | def version
          method version_to_rollback (line 133) | def version_to_rollback(table, steps)
          method migrations_table_dataset (line 142) | def migrations_table_dataset
          method schema (line 152) | def schema
          method new_connection (line 166) | def new_connection(global: false)
          method database (line 174) | def database
          method port (line 180) | def port
          method host (line 186) | def host
          method username (line 192) | def username
          method password (line 198) | def password
          method migrations_table (line 204) | def migrations_table
          method escape (line 210) | def escape(string)
          method execute (line 216) | def execute(command, env: {}, error: ->(err) { raise MigrationEr...

FILE: lib/hanami/model/migrator/connection.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Migrator (line 7) | class Migrator
        class Connection (line 14) | class Connection
          method initialize (line 17) | def initialize(configuration)
          method raw (line 23) | def raw
          method host (line 40) | def host
          method port (line 50) | def port
          method database (line 60) | def database
          method database_type (line 72) | def database_type
          method user (line 89) | def user
          method password (line 99) | def password
          method uri (line 107) | def uri
          method global_uri (line 115) | def global_uri
          method jdbc? (line 123) | def jdbc?
          method parsed_uri (line 131) | def parsed_uri
          method schema (line 136) | def schema
          method table (line 144) | def table(name)
          method parsed_opt (line 160) | def parsed_opt(option, query: parsed_uri.query)

FILE: lib/hanami/model/migrator/logger.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Migrator (line 7) | class Migrator
        class Logger (line 12) | class Logger < Hanami::Logger
          class Formatter (line 17) | class Formatter < Hanami::Logger::Formatter
            method _format (line 22) | def _format(hash)
          method initialize (line 29) | def initialize(stream)

FILE: lib/hanami/model/migrator/mysql_adapter.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      class Migrator (line 5) | class Migrator
        class MySQLAdapter (line 10) | class MySQLAdapter < Adapter
          method create (line 27) | def create
          method drop (line 41) | def drop
          method dump (line 55) | def dump
          method load (line 62) | def load
          method password (line 70) | def password
          method port (line 74) | def port
          method dump_structure (line 80) | def dump_structure
          method load_structure (line 86) | def load_structure
          method dump_migrations_data (line 92) | def dump_migrations_data

FILE: lib/hanami/model/migrator/postgres_adapter.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      class Migrator (line 7) | class Migrator
        class PostgresAdapter (line 12) | class PostgresAdapter < Adapter
          method create (line 37) | def create
          method drop (line 43) | def drop
          method dump (line 49) | def dump
          method load (line 56) | def load
          method environment_variables (line 64) | def environment_variables
          method dump_structure (line 75) | def dump_structure
          method load_structure (line 81) | def load_structure
          method dump_migrations_data (line 89) | def dump_migrations_data
          method call_db_command (line 96) | def call_db_command(command)
          method modified_message (line 110) | def modified_message(original_message)

FILE: lib/hanami/model/migrator/sqlite_adapter.rb
  type Hanami (line 7) | module Hanami
    type Model (line 8) | module Model
      class Migrator (line 9) | class Migrator
        class SQLiteAdapter (line 14) | class SQLiteAdapter < Adapter
          type Memory (line 19) | module Memory
            function create (line 22) | def create
            function drop (line 27) | def drop
          method initialize (line 35) | def initialize(configuration)
          method create (line 42) | def create
          method drop (line 51) | def drop
          method dump (line 59) | def dump
          method load (line 66) | def load
          method path (line 74) | def path
          method root (line 82) | def root
          method memory? (line 88) | def memory?
          method dump_structure (line 96) | def dump_structure
          method load_structure (line 102) | def load_structure
          method dump_migrations_data (line 109) | def dump_migrations_data

FILE: lib/hanami/model/plugins.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Plugins (line 9) | module Plugins
        class WrappingInput (line 14) | class WrappingInput
          method initialize (line 17) | def initialize(_relation, input)

FILE: lib/hanami/model/plugins/mapping.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Plugins (line 5) | module Plugins
        type Mapping (line 10) | module Mapping
          class InputWithMapping (line 15) | class InputWithMapping < WrappingInput
            method initialize (line 18) | def initialize(relation, input)
            method [] (line 27) | def [](value)
          type ClassMethods (line 36) | module ClassMethods
            function build (line 41) | def build(relation, options = {})
          function included (line 49) | def self.included(klass)

FILE: lib/hanami/model/plugins/schema.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Plugins (line 5) | module Plugins
        type Schema (line 10) | module Schema
          class InputWithSchema (line 15) | class InputWithSchema < WrappingInput
            method initialize (line 18) | def initialize(relation, input)
            method [] (line 27) | def [](value)
          type ClassMethods (line 36) | module ClassMethods
            function build (line 41) | def build(relation, options = {})
          function included (line 49) | def self.included(klass)

FILE: lib/hanami/model/plugins/timestamps.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Plugins (line 5) | module Plugins
        type Timestamps (line 10) | module Timestamps
          class InputWithTimestamp (line 17) | class InputWithTimestamp < WrappingInput
            method initialize (line 26) | def initialize(relation, input)
            method [] (line 35) | def [](value)
            method _touch (line 45) | def _touch(_value)
            method timestamps? (line 53) | def timestamps?
          class InputWithUpdateTimestamp (line 62) | class InputWithUpdateTimestamp < InputWithTimestamp
            method _touch (line 67) | def _touch(value, now)
          class InputWithCreateTimestamp (line 77) | class InputWithCreateTimestamp < InputWithUpdateTimestamp
            method _touch (line 82) | def _touch(value, now)
          type ClassMethods (line 93) | module ClassMethods
            function build (line 98) | def build(relation, options = {})
          function included (line 112) | def self.included(klass)

FILE: lib/hanami/model/relation_name.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      class RelationName (line 15) | class RelationName < EntityName
        method new (line 21) | def self.new(name)

FILE: lib/hanami/model/sql.rb
  type Hanami (line 6) | module Hanami
    type Model (line 8) | module Model
      function migration (line 50) | def self.migration(&blk)
      type Sql (line 57) | module Sql
        function function (line 85) | def self.function(name)
        function literal (line 119) | def self.literal(string)
        function asc (line 129) | def self.asc(column)
        function desc (line 139) | def self.desc(column)

FILE: lib/hanami/model/sql/console.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Sql (line 7) | module Sql
        class Console (line 12) | class Console
          method initialize (line 21) | def initialize(uri)
          method console (line 29) | def console

FILE: lib/hanami/model/sql/consoles/abstract.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model
      type Sql (line 5) | module Sql
        type Consoles (line 6) | module Consoles
          class Abstract (line 11) | class Abstract
            method initialize (line 14) | def initialize(uri)
            method database_name (line 22) | def database_name
            method concat (line 28) | def concat(*tokens)

FILE: lib/hanami/model/sql/consoles/mysql.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Sql (line 7) | module Sql
        type Consoles (line 8) | module Consoles
          class Mysql (line 13) | class Mysql < Abstract
            method connection_string (line 20) | def connection_string
            method command (line 28) | def command
            method host (line 34) | def host
            method database (line 40) | def database
            method port (line 46) | def port
            method username (line 52) | def username
            method password (line 58) | def password

FILE: lib/hanami/model/sql/consoles/postgresql.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      type Sql (line 8) | module Sql
        type Consoles (line 9) | module Consoles
          class Postgresql (line 14) | class Postgresql < Abstract
            method connection_string (line 25) | def connection_string
            method command (line 34) | def command
            method host (line 40) | def host
            method database (line 46) | def database
            method port (line 52) | def port
            method username (line 59) | def username
            method configure_password (line 66) | def configure_password
            method query (line 73) | def query

FILE: lib/hanami/model/sql/consoles/sqlite.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      type Sql (line 8) | module Sql
        type Consoles (line 9) | module Consoles
          class Sqlite (line 14) | class Sqlite < Abstract
            method connection_string (line 21) | def connection_string
            method command (line 29) | def command
            method host (line 35) | def host
            method database (line 41) | def database

FILE: lib/hanami/model/sql/entity/schema.rb
  type Hanami (line 7) | module Hanami
    type Model (line 8) | module Model
      type Sql (line 9) | module Sql
        type Entity (line 10) | module Entity
          class Schema (line 22) | class Schema < Hanami::Entity::Schema
            method initialize (line 36) | def initialize(registry, relation, mapping)
            method call (line 51) | def call(attributes)
            method attribute? (line 67) | def attribute?(name)
            method build (line 89) | def build(registry, relation, mapping)
            method build_attributes (line 106) | def build_attributes(relation, mapping)
            method build_associations (line 125) | def build_associations(registry, associations)
            method coercible (line 136) | def coercible(type)

FILE: lib/hanami/model/sql/types.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      type Sql (line 8) | module Sql
        type Types (line 12) | module Types
          type Schema (line 18) | module Schema
            function coercible (line 67) | def self.coercible(attribute)
            function pg_json_pristines (line 89) | def self.pg_json_pristines
            function pg_json? (line 97) | def self.pg_json?(pristine)
            class AssociationType (line 108) | class AssociationType < Hanami::Model::Types::Schema::Coercibl...
              method valid? (line 117) | def valid?(value)
              method success (line 123) | def success(*args)

FILE: lib/hanami/model/sql/types/schema/coercions.rb
  type Hanami (line 6) | module Hanami
    type Model (line 7) | module Model
      type Sql (line 8) | module Sql
        type Types (line 9) | module Types
          type Schema (line 10) | module Schema
            type Coercions (line 17) | module Coercions
              function int (line 28) | def self.int(arg)
              function float (line 49) | def self.float(arg)
              function decimal (line 70) | def self.decimal(arg)
              function date (line 93) | def self.date(arg)
              function datetime (line 116) | def self.datetime(arg)
              function time (line 139) | def self.time(arg)
              function array (line 164) | def self.array(arg)
              function hash (line 185) | def self.hash(arg)
              function pg_json (line 208) | def self.pg_json(arg)

FILE: lib/hanami/model/types.rb
  type Hanami (line 5) | module Hanami
    type Model (line 6) | module Model
      type Types (line 10) | module Types
        function included (line 15) | def self.included(mod)
        type ClassMethods (line 22) | module ClassMethods
          function Entity (line 46) | def Entity(type)
          function Collection (line 76) | def Collection(type)
        type Schema (line 85) | module Schema
          class CoercibleType (line 90) | class CoercibleType < Dry::Types::Definition
            method call (line 101) | def call(value)
            method valid? (line 122) | def valid?(value)
            method coerce (line 132) | def coerce(value)
            method object (line 143) | def object

FILE: lib/hanami/model/version.rb
  type Hanami (line 3) | module Hanami
    type Model (line 4) | module Model

FILE: lib/hanami/repository.rb
  type Hanami (line 13) | module Hanami
    class Repository (line 112) | class Repository < ROM::Repository::Root
      method configuration (line 125) | def self.configuration
      method container (line 133) | def self.container
      method command (line 157) | def command(*args, **opts, &block)
      method define_relation (line 171) | def self.define_relation
      method define_mapping (line 201) | def self.define_mapping
      method define_associations (line 224) | def self.define_associations
      method associations (line 241) | def self.associations(&blk)
      method schema (line 262) | def self.schema(&blk)
      method mapping (line 281) | def self.mapping(&blk)
      method load! (line 289) | def self.load!
      method inherited (line 298) | def self.inherited(klass)
      type Commands (line 330) | module Commands
        function create (line 348) | def create(*args)
        function update (line 377) | def update(*args)
        function delete (line 396) | def delete(*args)
      method initialize (line 408) | def initialize
      method find (line 426) | def find(id)
      method all (line 440) | def all
      method first (line 452) | def first
      method last (line 464) | def last
      method clear (line 474) | def clear
      method assoc (line 486) | def assoc(target, subject = nil)

FILE: spec/support/database.rb
  type Database (line 3) | module Database
    class Setup (line 4) | class Setup
      method initialize (line 7) | def initialize(adapter: ENV["DB"])
      method run (line 11) | def run
    type Strategies (line 16) | module Strategies
      function strategies (line 21) | def self.strategies
    class Strategy (line 28) | class Strategy
      method for (line 30) | def for(adapter)
      method strategies (line 38) | def strategies
    function engine (line 44) | def self.engine
    function engine? (line 48) | def self.engine?(name)

FILE: spec/support/database/strategies/abstract.rb
  type Database (line 3) | module Database
    type Strategies (line 4) | module Strategies
      class Abstract (line 5) | class Abstract
        method eligible? (line 6) | def self.eligible?(_adapter)
        method run (line 10) | def run
        method before (line 22) | def before
        method database_name (line 26) | def database_name
        method load_dependencies (line 30) | def load_dependencies
        method export_env (line 34) | def export_env
        method create_database (line 38) | def create_database
        method configure (line 42) | def configure
        method after (line 50) | def after
        method jruby? (line 56) | def jruby?
        method ci? (line 60) | def ci?

FILE: spec/support/database/strategies/mysql.rb
  type Database (line 5) | module Database
    type Strategies (line 6) | module Strategies
      class Mysql (line 7) | class Mysql < Sql
        type JrubyImplementation (line 8) | module JrubyImplementation
          function load_dependencies (line 11) | def load_dependencies
          function export_env (line 16) | def export_env
          function host (line 21) | def host
          function credentials (line 25) | def credentials
        type TravisCiImplementation (line 36) | module TravisCiImplementation
          function export_env (line 39) | def export_env
          function create_database (line 45) | def create_database
          function run_command (line 53) | def run_command(command)
        type CircleCiImplementation (line 59) | module CircleCiImplementation
          function export_env (line 62) | def export_env
          function create_database (line 68) | def create_database
          function run_command (line 75) | def run_command(command)
        method eligible? (line 81) | def self.eligible?(adapter)
        method initialize (line 85) | def initialize
        method load_dependencies (line 98) | def load_dependencies
        method export_env (line 103) | def export_env
        method create_database (line 111) | def create_database
        method run_command (line 119) | def run_command(command)

FILE: spec/support/database/strategies/postgresql.rb
  type Database (line 5) | module Database
    type Strategies (line 6) | module Strategies
      class Postgresql (line 7) | class Postgresql < Sql
        type JrubyImplementation (line 8) | module JrubyImplementation
          function load_dependencies (line 11) | def load_dependencies
          function export_env (line 18) | def export_env
        type TravisCiImplementation (line 24) | module TravisCiImplementation
          function export_env (line 27) | def export_env
        type CircleCiImplementation (line 33) | module CircleCiImplementation
          function create_database (line 36) | def create_database
        type GithubActionsImplementation (line 47) | module GithubActionsImplementation
          function export_env (line 50) | def export_env
          function create_database (line 56) | def create_database
        method eligible? (line 67) | def self.eligible?(adapter)
        method initialize (line 71) | def initialize
        method load_dependencies (line 85) | def load_dependencies
        method create_database (line 90) | def create_database
        method export_env (line 106) | def export_env
        method try (line 115) | def try(message)

FILE: spec/support/database/strategies/sql.rb
  type Database (line 8) | module Database
    type Strategies (line 9) | module Strategies
      class Sql (line 10) | class Sql < Abstract
        method eligible? (line 11) | def self.eligible?(_adapter)
        method before (line 17) | def before
        method export_env (line 23) | def export_env
        method configure (line 29) | def configure
        method after (line 44) | def after
        method migrate (line 50) | def migrate
        method credentials (line 57) | def credentials
        method host (line 63) | def host
        method host_and_credentials (line 67) | def host_and_credentials
        method logger (line 73) | def logger

FILE: spec/support/database/strategies/sqlite.rb
  type Database (line 6) | module Database
    type Strategies (line 7) | module Strategies
      class Sqlite (line 8) | class Sqlite < Sql
        type JrubyImplementation (line 9) | module JrubyImplementation
          function load_dependencies (line 12) | def load_dependencies
          function export_env (line 18) | def export_env
        type CiImplementation (line 24) | module CiImplementation
        method eligible? (line 27) | def self.eligible?(adapter)
        method initialize (line 31) | def initialize
        method database_name (line 38) | def database_name
        method load_dependencies (line 42) | def load_dependencies
        method create_database (line 47) | def create_database
        method export_env (line 54) | def export_env

FILE: spec/support/fixtures.rb
  class BaseParams (line 5) | class BaseParams < OpenStruct
    method to_hash (line 6) | def to_hash
  class User (line 11) | class User < Hanami::Entity
  class Avatar (line 14) | class Avatar < Hanami::Entity
  class Author (line 17) | class Author < Hanami::Entity
  class Book (line 20) | class Book < Hanami::Entity
  class Category (line 23) | class Category < Hanami::Entity
  class BookOntology (line 26) | class BookOntology < Hanami::Entity
  class Operator (line 29) | class Operator < Hanami::Entity
  class AccessToken (line 32) | class AccessToken < Hanami::Entity
  class SourceFile (line 35) | class SourceFile < Hanami::Entity
  class Post (line 38) | class Post < Hanami::Entity
  class Comment (line 41) | class Comment < Hanami::Entity
  class Warehouse (line 44) | class Warehouse < Hanami::Entity
  class Account (line 52) | class Account < Hanami::Entity
  class PageVisit (line 64) | class PageVisit < Hanami::Entity
  class Person (line 78) | class Person < Hanami::Entity
  class Product (line 85) | class Product < Hanami::Entity
  class Color (line 88) | class Color < Hanami::Entity
  class Label (line 91) | class Label < Hanami::Entity
  class PostRepository (line 94) | class PostRepository < Hanami::Repository
    method find_with_commenters (line 101) | def find_with_commenters(id)
    method commenters_for (line 105) | def commenters_for(post)
    method find_with_author (line 109) | def find_with_author(id)
    method feed_for (line 113) | def feed_for(id)
    method author_for (line 117) | def author_for(post)
  class CommentRepository (line 122) | class CommentRepository < Hanami::Repository
    method commenter_for (line 128) | def commenter_for(comment)
  class AvatarRepository (line 133) | class AvatarRepository < Hanami::Repository
    method by_user (line 138) | def by_user(id)
  class UserRepository (line 143) | class UserRepository < Hanami::Repository
    method find_with_threads (line 150) | def find_with_threads(id)
    method threads_for (line 154) | def threads_for(user)
    method find_with_avatar (line 158) | def find_with_avatar(id)
    method create_with_avatar (line 162) | def create_with_avatar(data)
    method remove_avatar (line 166) | def remove_avatar(user)
    method add_avatar (line 170) | def add_avatar(user, data)
    method update_avatar (line 174) | def update_avatar(user, data)
    method replace_avatar (line 178) | def replace_avatar(user, data)
    method avatar_for (line 182) | def avatar_for(user)
    method by_name (line 186) | def by_name(name)
    method by_matching_name (line 190) | def by_matching_name(name)
    method by_name_with_root (line 194) | def by_name_with_root(name)
    method find_all_by_manual_query (line 198) | def find_all_by_manual_query
    method ids (line 202) | def ids
    method select_id_and_name (line 206) | def select_id_and_name
  class AvatarRepository (line 211) | class AvatarRepository < Hanami::Repository
    method by_user (line 138) | def by_user(id)
  class AuthorRepository (line 214) | class AuthorRepository < Hanami::Repository
    method create_many (line 219) | def create_many(data, opts: {})
    method create_with_books (line 223) | def create_with_books(data)
    method find_with_books (line 227) | def find_with_books(id)
    method books_for (line 231) | def books_for(author)
    method add_book (line 235) | def add_book(author, data)
    method remove_book (line 239) | def remove_book(author, id)
    method delete_books (line 243) | def delete_books(author)
    method delete_on_sales_books (line 247) | def delete_on_sales_books(author)
    method books_count (line 251) | def books_count(author)
    method on_sales_books_count (line 255) | def on_sales_books_count(author)
    method find_book (line 259) | def find_book(author, id)
    method book_exists? (line 263) | def book_exists?(author, id)
    method book_for (line 269) | def book_for(author, id)
  class BookOntologyRepository (line 274) | class BookOntologyRepository < Hanami::Repository
  class CategoryRepository (line 281) | class CategoryRepository < Hanami::Repository
    method books_for (line 286) | def books_for(category)
    method on_sales_books_count (line 290) | def on_sales_books_count(category)
    method books_count (line 294) | def books_count(category)
    method find_with_books (line 298) | def find_with_books(id)
    method add_books (line 302) | def add_books(category, *books)
    method remove_book (line 306) | def remove_book(category, book_id)
  class BookRepository (line 311) | class BookRepository < Hanami::Repository
    method add_category (line 317) | def add_category(book, category)
    method clear_categories (line 321) | def clear_categories(book)
    method categories_for (line 325) | def categories_for(book)
    method find_with_categories (line 329) | def find_with_categories(id)
    method find_with_author (line 333) | def find_with_author(id)
    method author_for (line 337) | def author_for(book)
  class OperatorRepository (line 342) | class OperatorRepository < Hanami::Repository
  class AccessTokenRepository (line 351) | class AccessTokenRepository < Hanami::Repository
  class SourceFileRepository (line 355) | class SourceFileRepository < Hanami::Repository
  class WarehouseRepository (line 358) | class WarehouseRepository < Hanami::Repository
  class ProductRepository (line 361) | class ProductRepository < Hanami::Repository
  class ColorRepository (line 364) | class ColorRepository < Hanami::Repository
  class LabelRepository (line 373) | class LabelRepository < Hanami::Repository

FILE: spec/support/platform.rb
  type Platform (line 3) | module Platform
    function ci? (line 10) | def self.ci?
    function match (line 14) | def self.match(&blk)
    function match? (line 18) | def self.match?(**args)
  type PlatformHelpers (line 23) | module PlatformHelpers
    function with_platform (line 24) | def with_platform(**args)
    function unless_platform (line 28) | def unless_platform(**args)

FILE: spec/support/platform/ci.rb
  type Platform (line 3) | module Platform
    type Ci (line 4) | module Ci
      function ci? (line 5) | def self.ci?(name)
      function current (line 9) | def self.current
      function travis? (line 20) | def travis?
      function circle? (line 24) | def circle?
      function drone? (line 28) | def drone?
      function github? (line 32) | def github?

FILE: spec/support/platform/db.rb
  type Platform (line 3) | module Platform
    type Db (line 4) | module Db
      function db? (line 5) | def self.db?(name)
      function current (line 9) | def self.current

FILE: spec/support/platform/engine.rb
  type Platform (line 5) | module Platform
    type Engine (line 6) | module Engine
      function engine? (line 7) | def self.engine?(name)
      function current (line 11) | def self.current
      function ruby? (line 20) | def ruby?
      function jruby? (line 24) | def jruby?

FILE: spec/support/platform/matcher.rb
  type Platform (line 5) | module Platform
    class Matcher (line 6) | class Matcher
      class Nope (line 7) | class Nope < Hanami::Utils::BasicObject
        method or (line 8) | def or(other, &blk)
        method method_missing (line 14) | def method_missing(*)
      method match (line 21) | def self.match(&blk)
      method match? (line 27) | def self.match?(os: Os.current, ci: Ci.current, engine: Engine.curre...
      method initialize (line 33) | def initialize
      method os (line 37) | def os(name, &blk)
      method ci (line 43) | def ci(name, &blk)
      method engine (line 49) | def engine(name, &blk)
      method db (line 55) | def db(name, &blk)
      method default (line 61) | def default(&blk)
      method match (line 67) | def match(&blk)
      method nope (line 71) | def nope
      method yep (line 75) | def yep
      method resolve (line 79) | def resolve
      method os? (line 83) | def os?(name)
      method ci? (line 87) | def ci?(name)
      method engine? (line 91) | def engine?(name)
      method db? (line 95) | def db?(name)

FILE: spec/support/platform/os.rb
  type Platform (line 5) | module Platform
    type Os (line 6) | module Os
      function os? (line 7) | def self.os?(name)
      function current (line 11) | def self.current

FILE: spec/support/test_io.rb
  type TestIO (line 3) | module TestIO
    function with_stdout (line 4) | def self.with_stdout
    function stream (line 13) | def self.stream

FILE: spec/unit/hanami/entity/automatic_schema_spec.rb
  function to_hash (line 9) | def to_hash

FILE: spec/unit/hanami/entity/manual_schema/base_spec.rb
  function to_hash (line 9) | def to_hash

FILE: spec/unit/hanami/entity/manual_schema/strict_spec.rb
  function to_hash (line 9) | def to_hash

FILE: spec/unit/hanami/entity/schemaless_spec.rb
  function to_hash (line 11) | def to_hash

FILE: spec/unit/hanami/model/migrator/mysql.rb
  function prepare_migrations_directory (line 457) | def prepare_migrations_directory
  function clean_migrations (line 462) | def clean_migrations

FILE: spec/unit/hanami/model/migrator/postgresql.rb
  function prepare_migrations_directory (line 535) | def prepare_migrations_directory
  function clean_migrations (line 540) | def clean_migrations

FILE: spec/unit/hanami/model/migrator/sqlite.rb
  function prepare_migrations_directory (line 409) | def prepare_migrations_directory
  function clean_migrations (line 414) | def clean_migrations

FILE: spec/unit/hanami/model/sql/schema/array_spec.rb
  function to_ary (line 8) | def to_ary

FILE: spec/unit/hanami/model/sql/schema/date_spec.rb
  function to_date (line 8) | def to_date

FILE: spec/unit/hanami/model/sql/schema/date_time_spec.rb
  function to_datetime (line 8) | def to_datetime

FILE: spec/unit/hanami/model/sql/schema/decimal_spec.rb
  function to_d (line 8) | def to_d

FILE: spec/unit/hanami/model/sql/schema/float_spec.rb
  function to_f (line 8) | def to_f

FILE: spec/unit/hanami/model/sql/schema/hash_spec.rb
  function to_hash (line 8) | def to_hash

FILE: spec/unit/hanami/model/sql/schema/int_spec.rb
  function to_int (line 8) | def to_int

FILE: spec/unit/hanami/model/sql/schema/time_spec.rb
  function to_time (line 8) | def to_time
Condensed preview — 150 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (455K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 15,
    "preview": "github: hanami\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1812,
    "preview": "name: ci\n\n\"on\":\n  push:\n    paths:\n      - \".github/workflows/ci.yml\"\n      - \"lib/**\"\n      - \"*.gemspec\"\n      - \"spec"
  },
  {
    "path": ".gitignore",
    "chars": 199,
    "preview": "*.gem\n*.rbc\n.bundle\n.config\n.DS_Store\n.greenbar\n.ruby-version\n.yardoc\n.rubocop-*\n_yardoc\ncoverage\ndoc/\nGemfile.lock\nInst"
  },
  {
    "path": ".jrubyrc",
    "chars": 21,
    "preview": "debug.fullTrace=true\n"
  },
  {
    "path": ".rspec",
    "chars": 30,
    "preview": "--color\n--require spec_helper\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 438,
    "preview": "# Please keep AllCops, Bundler, Style, Metrics groups and then order cops\n# alphabetically\ninherit_from:\n  - https://raw"
  },
  {
    "path": ".yardopts",
    "chars": 47,
    "preview": "--protected\n--private\n-\nLICENSE.md\nlib/**/*.rb\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 14704,
    "preview": "# Hanami::Model\nA persistence layer for Hanami\n\n## v1.3.3 - 2021-05-22\n### Fixed\n- [Sean Collins] Specify dependency on "
  },
  {
    "path": "Gemfile",
    "chars": 786,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\ngemspec\n\nunless ENV[\"CI\"]\n  gem \"byebug\", require: false, p"
  },
  {
    "path": "LICENSE.md",
    "chars": 1070,
    "preview": "Copyright © 2014-2021 Luca Guidi\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na c"
  },
  {
    "path": "README.md",
    "chars": 7849,
    "preview": "# Hanami::Model (deprecated)\n\n## _Important notice_\n**NOTE**: Hanami::Model was the persistence layer for Hanami 1.x. Th"
  },
  {
    "path": "Rakefile",
    "chars": 293,
    "preview": "# frozen_string_literal: true\n\nrequire \"rake\"\nrequire \"bundler/gem_tasks\"\nrequire \"rspec/core/rake_task\"\nrequire \"hanami"
  },
  {
    "path": "hanami-model.gemspec",
    "chars": 1692,
    "preview": "# frozen_string_literal: true\n\nlib = File.expand_path(\"../lib\", __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.incl"
  },
  {
    "path": "lib/hanami/entity/schema.rb",
    "chars": 7170,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/types\"\nrequire \"hanami/utils/hash\"\n\nmodule Hanami\n  class Entity\n  "
  },
  {
    "path": "lib/hanami/entity.rb",
    "chars": 5475,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/types\"\n\nmodule Hanami\n  # An object that is defined by its identity"
  },
  {
    "path": "lib/hanami/model/association.rb",
    "chars": 1236,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom-sql\"\nrequire \"hanami/model/associations/belongs_to\"\nrequire \"hanami/model/as"
  },
  {
    "path": "lib/hanami/model/associations/belongs_to.rb",
    "chars": 2458,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/types\"\n\nmodule Hanami\n  module Model\n    module Associations\n      "
  },
  {
    "path": "lib/hanami/model/associations/dsl.rb",
    "chars": 1016,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    module Associations\n      # Auto-infer relations linked "
  },
  {
    "path": "lib/hanami/model/associations/has_many.rb",
    "chars": 4910,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/types\"\n\nmodule Hanami\n  module Model\n    module Associations\n      "
  },
  {
    "path": "lib/hanami/model/associations/has_one.rb",
    "chars": 3940,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils/hash\"\n\nmodule Hanami\n  module Model\n    module Associations\n      #"
  },
  {
    "path": "lib/hanami/model/associations/many_to_many.rb",
    "chars": 4917,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils/hash\"\n\nmodule Hanami\n  module Model\n    module Associations\n      #"
  },
  {
    "path": "lib/hanami/model/configuration.rb",
    "chars": 4780,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom/configuration\"\n\nmodule Hanami\n  module Model\n    # Configuration for the fra"
  },
  {
    "path": "lib/hanami/model/configurator.rb",
    "chars": 1809,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Configuration DSL\n    #\n    # @since 0.7.0\n    # @api "
  },
  {
    "path": "lib/hanami/model/entity_name.rb",
    "chars": 811,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Conventional name for entities.\n    #\n    # Given a re"
  },
  {
    "path": "lib/hanami/model/error.rb",
    "chars": 3025,
    "preview": "# frozen_string_literal: true\n\nrequire \"concurrent\"\n\nmodule Hanami\n  module Model\n    # Default Error class\n    #\n    # "
  },
  {
    "path": "lib/hanami/model/mapped_relation.rb",
    "chars": 1552,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Mapped proxy for ROM relations.\n    #\n    # It elimina"
  },
  {
    "path": "lib/hanami/model/mapping.rb",
    "chars": 1147,
    "preview": "# frozen_string_literal: true\n\nrequire \"transproc/all\"\n\nmodule Hanami\n  module Model\n    # Mapping\n    #\n    # @since 0."
  },
  {
    "path": "lib/hanami/model/migration.rb",
    "chars": 627,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Database migration\n    #\n    # @since 0.7.0\n    # @api"
  },
  {
    "path": "lib/hanami/model/migrator/adapter.rb",
    "chars": 6172,
    "preview": "# frozen_string_literal: true\n\nrequire \"uri\"\nrequire \"shellwords\"\nrequire \"open3\"\n\nmodule Hanami\n  module Model\n    clas"
  },
  {
    "path": "lib/hanami/model/migrator/connection.rb",
    "chars": 4261,
    "preview": "# frozen_string_literal: true\n\nrequire \"cgi\"\n\nmodule Hanami\n  module Model\n    class Migrator\n      # Sequel connection "
  },
  {
    "path": "lib/hanami/model/migrator/logger.rb",
    "chars": 760,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/logger\"\n\nmodule Hanami\n  module Model\n    class Migrator\n      # Automati"
  },
  {
    "path": "lib/hanami/model/migrator/mysql_adapter.rb",
    "chars": 2782,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    class Migrator\n      # MySQL adapter\n      #\n      # @si"
  },
  {
    "path": "lib/hanami/model/migrator/postgres_adapter.rb",
    "chars": 3422,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils/blank\"\n\nmodule Hanami\n  module Model\n    class Migrator\n      # Pos"
  },
  {
    "path": "lib/hanami/model/migrator/sqlite_adapter.rb",
    "chars": 2944,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"hanami/utils\"\nrequire \"English\"\n\nmodule Hanami\n  module Model"
  },
  {
    "path": "lib/hanami/model/migrator.rb",
    "chars": 10732,
    "preview": "# frozen_string_literal: true\n\nrequire \"sequel\"\nrequire \"sequel/extensions/migration\"\n\nmodule Hanami\n  module Model\n    "
  },
  {
    "path": "lib/hanami/model/plugins/mapping.rb",
    "chars": 1382,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    module Plugins\n      # Transform output into model domai"
  },
  {
    "path": "lib/hanami/model/plugins/schema.rb",
    "chars": 1350,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    module Plugins\n      # Transform input values into datab"
  },
  {
    "path": "lib/hanami/model/plugins/timestamps.rb",
    "chars": 3096,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    module Plugins\n      # Automatically set/update timestam"
  },
  {
    "path": "lib/hanami/model/plugins.rb",
    "chars": 587,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Plugins to extend read/write operations from/to the da"
  },
  {
    "path": "lib/hanami/model/relation_name.rb",
    "chars": 638,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"entity_name\"\nrequire \"hanami/utils/string\"\n\nmodule Hanami\n  module Mode"
  },
  {
    "path": "lib/hanami/model/sql/console.rb",
    "chars": 989,
    "preview": "# frozen_string_literal: true\n\nrequire \"uri\"\n\nmodule Hanami\n  module Model\n    module Sql\n      # SQL console\n      #\n  "
  },
  {
    "path": "lib/hanami/model/sql/consoles/abstract.rb",
    "chars": 628,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    module Sql\n      module Consoles\n        # Abstract adap"
  },
  {
    "path": "lib/hanami/model/sql/consoles/mysql.rb",
    "chars": 1313,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"abstract\"\n\nmodule Hanami\n  module Model\n    module Sql\n      module Con"
  },
  {
    "path": "lib/hanami/model/sql/consoles/postgresql.rb",
    "chars": 1885,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"abstract\"\nrequire \"cgi\"\n\nmodule Hanami\n  module Model\n    module Sql\n  "
  },
  {
    "path": "lib/hanami/model/sql/consoles/sqlite.rb",
    "chars": 909,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"abstract\"\nrequire \"shellwords\"\n\nmodule Hanami\n  module Model\n    module"
  },
  {
    "path": "lib/hanami/model/sql/entity/schema.rb",
    "chars": 4733,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/entity/schema\"\nrequire \"hanami/model/types\"\nrequire \"hanami/model/associa"
  },
  {
    "path": "lib/hanami/model/sql/types/schema/coercions.rb",
    "chars": 7233,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils/string\"\nrequire \"hanami/utils/hash\"\n\nmodule Hanami\n  module Model\n "
  },
  {
    "path": "lib/hanami/model/sql/types.rb",
    "chars": 4772,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/types\"\nrequire \"rom/types\"\n\nmodule Hanami\n  module Model\n    module"
  },
  {
    "path": "lib/hanami/model/sql.rb",
    "chars": 4935,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom-sql\"\nrequire \"hanami/utils\"\n\nmodule Hanami\n  # Hanami::Model migrations\n  mo"
  },
  {
    "path": "lib/hanami/model/types.rb",
    "chars": 4092,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom/types\"\n\nmodule Hanami\n  module Model\n    # Types definitions\n    #\n    # @si"
  },
  {
    "path": "lib/hanami/model/version.rb",
    "chars": 143,
    "preview": "# frozen_string_literal: true\n\nmodule Hanami\n  module Model\n    # Defines the version\n    #\n    # @since 0.1.0\n    VERSI"
  },
  {
    "path": "lib/hanami/model.rb",
    "chars": 2268,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom\"\nrequire \"concurrent\"\nrequire \"hanami/entity\"\nrequire \"hanami/repository\"\n\n#"
  },
  {
    "path": "lib/hanami/repository.rb",
    "chars": 12993,
    "preview": "# frozen_string_literal: true\n\nrequire \"rom-repository\"\nrequire \"hanami/model/entity_name\"\nrequire \"hanami/model/relatio"
  },
  {
    "path": "lib/hanami-model.rb",
    "chars": 54,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model\"\n"
  },
  {
    "path": "script/ci",
    "chars": 471,
    "preview": "#!/bin/bash\nset -euo pipefail\nIFS=$'\\n\\t'\n\nprepare_build() {\n  if [ -d coverage ]; then\n    rm -rf coverage\n  fi\n}\n\nprin"
  },
  {
    "path": "spec/integration/hanami/model/associations/belongs_to_spec.rb",
    "chars": 1171,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Associations (belongs_to)\" do\n  it \"returns nil if association wasn't pre"
  },
  {
    "path": "spec/integration/hanami/model/associations/has_many_spec.rb",
    "chars": 6135,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Associations (has_many)\" do\n  let(:authors) { AuthorRepository.new }\n  le"
  },
  {
    "path": "spec/integration/hanami/model/associations/has_one_spec.rb",
    "chars": 6162,
    "preview": "# frozen_string_literal: true\n\nrequire \"spec_helper\"\n\nRSpec.describe \"Associations (has_one)\" do\n  extend PlatformHelper"
  },
  {
    "path": "spec/integration/hanami/model/associations/many_to_many_spec.rb",
    "chars": 4661,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Associations (has_many :through)\" do\n  #### REPOS\n  let(:books) { BookRep"
  },
  {
    "path": "spec/integration/hanami/model/associations/relation_alias_spec.rb",
    "chars": 2189,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Alias (:as)  support for associations\" do\n  let(:users) { UserRepository."
  },
  {
    "path": "spec/integration/hanami/model/migration/mysql.rb",
    "chars": 16568,
    "preview": "# frozen_string_literal: true\n\nRSpec.shared_examples \"migration_integration_mysql\" do\n  before do\n    @schema = Pathname"
  },
  {
    "path": "spec/integration/hanami/model/migration/postgresql.rb",
    "chars": 22759,
    "preview": "# frozen_string_literal: true\n\nRSpec.shared_examples \"migration_integration_postgresql\" do\n  before do\n    @schema = Pat"
  },
  {
    "path": "spec/integration/hanami/model/migration/sqlite.rb",
    "chars": 17047,
    "preview": "# frozen_string_literal: true\n\nRSpec.shared_examples \"migration_integration_sqlite\" do\n  before do\n    @schema = Pathnam"
  },
  {
    "path": "spec/integration/hanami/model/migration_spec.rb",
    "chars": 195,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"./migration/#{Database.engine}.rb\"\n\nRSpec.describe \"Hanami::Model.migra"
  },
  {
    "path": "spec/integration/hanami/model/repository/base_spec.rb",
    "chars": 28250,
    "preview": "# frozen_string_literal: true\n\nrequire \"securerandom\"\n\nRSpec.describe \"Repository (base)\" do\n  extend PlatformHelpers\n\n "
  },
  {
    "path": "spec/integration/hanami/model/repository/command_spec.rb",
    "chars": 745,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Customized commands\" do\n  subject(:authors) { AuthorRepository.new }\n\n  l"
  },
  {
    "path": "spec/integration/hanami/model/repository/legacy_spec.rb",
    "chars": 3070,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Repository (legacy)\" do\n  describe \"#find\" do\n    it \"finds record by pri"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 297,
    "preview": "# frozen_string_literal: true\n\n$LOAD_PATH.unshift \"lib\"\nrequire \"hanami/devtools/unit\"\nrequire \"hanami/model\"\n\nrequire_r"
  },
  {
    "path": "spec/support/database/strategies/abstract.rb",
    "chars": 1145,
    "preview": "# frozen_string_literal: true\n\nmodule Database\n  module Strategies\n    class Abstract\n      def self.eligible?(_adapter)"
  },
  {
    "path": "spec/support/database/strategies/mysql.rb",
    "chars": 3506,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"sql\"\n\nmodule Database\n  module Strategies\n    class Mysql < Sql\n      m"
  },
  {
    "path": "spec/support/database/strategies/postgresql.rb",
    "chars": 3474,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"sql\"\n\nmodule Database\n  module Strategies\n    class Postgresql < Sql\n  "
  },
  {
    "path": "spec/support/database/strategies/sql.rb",
    "chars": 1973,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"abstract\"\nrequire \"hanami/utils/blank\"\nrequire \"pathname\"\nrequire \"stri"
  },
  {
    "path": "spec/support/database/strategies/sqlite.rb",
    "chars": 1347,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"sql\"\nrequire \"pathname\"\n\nmodule Database\n  module Strategies\n    class "
  },
  {
    "path": "spec/support/database.rb",
    "chars": 934,
    "preview": "# frozen_string_literal: true\n\nmodule Database\n  class Setup\n    DEFAULT_ADAPTER = \"sqlite\"\n\n    def initialize(adapter:"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612081248_column_types.rb",
    "chars": 4280,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case Database.engine\n    when :sqlite\n      cr"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612084656_default_values.rb",
    "chars": 2159,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case Database.engine\n    when :sqlite\n      cr"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612093458_null_constraints.rb",
    "chars": 226,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    create_table :null_constraints do\n      column"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612093810_column_indexes.rb",
    "chars": 412,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    create_table :column_indexes do\n      column :"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612094740_primary_keys.rb",
    "chars": 413,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    create_table :primary_keys_1 do\n      primary_"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612115204_foreign_keys.rb",
    "chars": 287,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    create_table :artists do\n      primary_key :id"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612122233_table_constraints.rb",
    "chars": 839,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case ENV[\"HANAMI_DATABASE_TYPE\"]\n    when \"sql"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20150612124205_table_alterations.rb",
    "chars": 1923,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case ENV[\"HANAMI_DATABASE_TYPE\"]\n    when \"sql"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160830094800_create_users.rb",
    "chars": 681,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :users\n    create_table? :users "
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160830094851_create_authors.rb",
    "chars": 296,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :authors\n    create_table? :auth"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160830094941_create_books.rb",
    "chars": 419,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :books\n    create_table? :books "
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160830095033_create_t_operator.rb",
    "chars": 211,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :t_operator\n    create_table? :t"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160905125728_create_source_files.rb",
    "chars": 693,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case Database.engine\n    when :postgresql\n    "
  },
  {
    "path": "spec/support/fixtures/database_migrations/20160909150704_create_avatars.rb",
    "chars": 325,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :avatars\n    create_table? :avat"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20161104143844_create_warehouses.rb",
    "chars": 337,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :warehouses\n    create_table? :w"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20161114094644_create_products.rb",
    "chars": 347,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case Database.engine\n    when :postgresql\n    "
  },
  {
    "path": "spec/support/fixtures/database_migrations/20170103142428_create_colors.rb",
    "chars": 518,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    case Database.engine\n    when :postgresql\n    "
  },
  {
    "path": "spec/support/fixtures/database_migrations/20170124081339_create_labels.rb",
    "chars": 142,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    create_table :labels do\n      column :id, Inte"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20170517115243_create_tokens.rb",
    "chars": 193,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :tokens\n    create_table? :token"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20170519172332_create_categories.rb",
    "chars": 449,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :categories\n    create_table? :c"
  },
  {
    "path": "spec/support/fixtures/database_migrations/20171002201227_create_posts_and_comments.rb",
    "chars": 486,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  change do\n    drop_table?   :posts\n    create_table? :posts "
  },
  {
    "path": "spec/support/fixtures/empty_migrations/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/support/fixtures/migrations/20160831073534_create_reviews.rb",
    "chars": 217,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  up do\n    create_table :reviews do\n      primary_key :id\n   "
  },
  {
    "path": "spec/support/fixtures/migrations/20160831090612_add_rating_to_reviews.rb",
    "chars": 183,
    "preview": "# frozen_string_literal: true\n\nHanami::Model.migration do\n  up do\n    add_column :reviews, :rating, \"integer\", default: "
  },
  {
    "path": "spec/support/fixtures.rb",
    "chars": 7264,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\n\nclass BaseParams < OpenStruct\n  def to_hash\n    to_h\n  end\nend\n\nclass "
  },
  {
    "path": "spec/support/platform/ci.rb",
    "chars": 586,
    "preview": "# frozen_string_literal: true\n\nmodule Platform\n  module Ci\n    def self.ci?(name)\n      current == name\n    end\n\n    def"
  },
  {
    "path": "spec/support/platform/db.rb",
    "chars": 174,
    "preview": "# frozen_string_literal: true\n\nmodule Platform\n  module Db\n    def self.db?(name)\n      current == name\n    end\n\n    def"
  },
  {
    "path": "spec/support/platform/engine.rb",
    "chars": 410,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils\"\n\nmodule Platform\n  module Engine\n    def self.engine?(name)\n      "
  },
  {
    "path": "spec/support/platform/matcher.rb",
    "chars": 1731,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/utils/basic_object\"\n\nmodule Platform\n  class Matcher\n    class Nope < Han"
  },
  {
    "path": "spec/support/platform/os.rb",
    "chars": 285,
    "preview": "# frozen_string_literal: true\n\nrequire \"rbconfig\"\n\nmodule Platform\n  module Os\n    def self.os?(name)\n      current == n"
  },
  {
    "path": "spec/support/platform.rb",
    "chars": 559,
    "preview": "# frozen_string_literal: true\n\nmodule Platform\n  require_relative \"platform/os\"\n  require_relative \"platform/ci\"\n  requi"
  },
  {
    "path": "spec/support/rspec.rb",
    "chars": 594,
    "preview": "# frozen_string_literal: true\n\nRSpec.configure do |config|\n  config.expect_with :rspec do |expectations|\n    expectation"
  },
  {
    "path": "spec/support/test_io.rb",
    "chars": 253,
    "preview": "# frozen_string_literal: true\n\nmodule TestIO\n  def self.with_stdout\n    stdout = $stdout\n    $stdout = stream\n    yield\n"
  },
  {
    "path": "spec/unit/hanami/entity/automatic_schema_spec.rb",
    "chars": 4278,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity do\n  describe \"automatic schema\" do\n    let(:described_clas"
  },
  {
    "path": "spec/unit/hanami/entity/manual_schema/base_spec.rb",
    "chars": 6516,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity do\n  describe \"manual schema (base)\" do\n    let(:described_"
  },
  {
    "path": "spec/unit/hanami/entity/manual_schema/strict_spec.rb",
    "chars": 1807,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity do\n  describe \"manual schema (strict)\" do\n    let(:describe"
  },
  {
    "path": "spec/unit/hanami/entity/manual_schema/types_spec.rb",
    "chars": 600,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity do\n  describe \"manual schema (types)\" do\n    [nil, :schema,"
  },
  {
    "path": "spec/unit/hanami/entity/schema/definition_spec.rb",
    "chars": 1491,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity::Schema::Definition do\n  let(:described_class) { Hanami::En"
  },
  {
    "path": "spec/unit/hanami/entity/schema/schemaless_spec.rb",
    "chars": 733,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity::Schema::Schemaless do\n  let(:subject) { Hanami::Entity::Sc"
  },
  {
    "path": "spec/unit/hanami/entity/schema_spec.rb",
    "chars": 1224,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity::Schema do\n  let(:described_class) { Hanami::Entity::Schema"
  },
  {
    "path": "spec/unit/hanami/entity/schemaless_spec.rb",
    "chars": 2861,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Entity do\n  describe \"schemaless\" do\n    let(:described_class) do\n"
  },
  {
    "path": "spec/unit/hanami/entity_spec.rb",
    "chars": 2558,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\n\nRSpec.describe Hanami::Entity do\n  let(:described_class) do\n    Class."
  },
  {
    "path": "spec/unit/hanami/model/check_constraint_validation_error_spec.rb",
    "chars": 544,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::CheckConstraintViolationError do\n  it \"inherits from Hanami"
  },
  {
    "path": "spec/unit/hanami/model/configuration_spec.rb",
    "chars": 2449,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Configuration do\n  before do\n    database_directory = Pathn"
  },
  {
    "path": "spec/unit/hanami/model/constraint_violation_error_spec.rb",
    "chars": 495,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::ConstraintViolationError do\n  it \"inherits from Hanami::Mod"
  },
  {
    "path": "spec/unit/hanami/model/disconnect_spec.rb",
    "chars": 1251,
    "preview": "# frozen_string_literal: true\n\n# This test is tightly coupled to Sequel\n#\n# We should improve connection management via "
  },
  {
    "path": "spec/unit/hanami/model/error_spec.rb",
    "chars": 182,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Error do\n  it \"inherits from StandardError\" do\n    expect(d"
  },
  {
    "path": "spec/unit/hanami/model/foreign_key_constraint_violation_error_spec.rb",
    "chars": 555,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::ForeignKeyConstraintViolationError do\n  it \"inherits from H"
  },
  {
    "path": "spec/unit/hanami/model/load_spec.rb",
    "chars": 439,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model.load!\" do\n  let(:message) { \"Cannot find corresponding type"
  },
  {
    "path": "spec/unit/hanami/model/mapped_relation_spec.rb",
    "chars": 499,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::MappedRelation do\n  subject { described_class.new(relation)"
  },
  {
    "path": "spec/unit/hanami/model/migrator/adapter_spec.rb",
    "chars": 2457,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Migrator::Adapter do\n  extend PlatformHelpers\n\n  subject { "
  },
  {
    "path": "spec/unit/hanami/model/migrator/connection_spec.rb",
    "chars": 6964,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Migrator::Connection do\n  extend PlatformHelpers\n\n  let(:co"
  },
  {
    "path": "spec/unit/hanami/model/migrator/mysql.rb",
    "chars": 14859,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\nrequire \"securerandom\"\n\nRSpec.shared_examples \"migrator_mysql\" do\n  let"
  },
  {
    "path": "spec/unit/hanami/model/migrator/postgresql.rb",
    "chars": 17121,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\nrequire \"securerandom\"\n\nRSpec.shared_examples \"migrator_postgresql\" do\n"
  },
  {
    "path": "spec/unit/hanami/model/migrator/sqlite.rb",
    "chars": 13458,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\nrequire \"securerandom\"\n\nRSpec.shared_examples \"migrator_sqlite\" do\n  le"
  },
  {
    "path": "spec/unit/hanami/model/migrator_spec.rb",
    "chars": 208,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/migrator\"\nrequire_relative \"./migrator/#{Database.engine}\"\n\nRSpec.d"
  },
  {
    "path": "spec/unit/hanami/model/not_null_constraint_violation_error_spec.rb",
    "chars": 549,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::NotNullConstraintViolationError do\n  it \"inherits from Hana"
  },
  {
    "path": "spec/unit/hanami/model/sql/console/mysql.rb",
    "chars": 494,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/sql/consoles/mysql\"\n\nRSpec.shared_examples \"sql_console_mysql\" do\n "
  },
  {
    "path": "spec/unit/hanami/model/sql/console/postgresql.rb",
    "chars": 1785,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/sql/consoles/postgresql\"\n\nRSpec.shared_examples \"sql_console_postgr"
  },
  {
    "path": "spec/unit/hanami/model/sql/console/sqlite.rb",
    "chars": 747,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/sql/consoles/sqlite\"\n\nRSpec.shared_examples \"sql_console_sqlite\" do"
  },
  {
    "path": "spec/unit/hanami/model/sql/console_spec.rb",
    "chars": 1727,
    "preview": "# frozen_string_literal: true\n\nrequire \"hanami/model/sql/console\"\n\nRSpec.describe Hanami::Model::Sql::Console do\n  descr"
  },
  {
    "path": "spec/unit/hanami/model/sql/entity/schema/automatic_spec.rb",
    "chars": 1068,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Sql::Entity::Schema do\n  describe \"automatic\" do\n    subjec"
  },
  {
    "path": "spec/unit/hanami/model/sql/entity/schema/mapping_spec.rb",
    "chars": 975,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Sql::Entity::Schema do\n  describe \"mapping\" do\n    subject "
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/array_spec.rb",
    "chars": 2204,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Array\" do\n  let(:described_class) { Ha"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/bool_spec.rb",
    "chars": 2652,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Bool\" do\n  let(:described_class) { Han"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/date_spec.rb",
    "chars": 2371,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Date\" do\n  let(:described_class) { Han"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/date_time_spec.rb",
    "chars": 2476,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::DateTime\" do\n  let(:described_class) {"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/decimal_spec.rb",
    "chars": 2476,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Decimal\" do\n  let(:described_class) { "
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/float_spec.rb",
    "chars": 2625,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Float\" do\n  let(:described_class) { Ha"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/hash_spec.rb",
    "chars": 2200,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Hash\" do\n  let(:described_class) { Han"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/int_spec.rb",
    "chars": 2354,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Int\" do\n  let(:described_class) { Hana"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/string_spec.rb",
    "chars": 1316,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::String\" do\n  let(:described_class) { H"
  },
  {
    "path": "spec/unit/hanami/model/sql/schema/time_spec.rb",
    "chars": 2427,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::Sql::Types::Schema::Time\" do\n  let(:described_class) { Han"
  },
  {
    "path": "spec/unit/hanami/model/sql_spec.rb",
    "chars": 1308,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::Sql do\n  describe \".migration\" do\n    it \"returns a new mig"
  },
  {
    "path": "spec/unit/hanami/model/unique_constraint_violation_error_spec.rb",
    "chars": 546,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe Hanami::Model::UniqueConstraintViolationError do\n  it \"inherits from Hanam"
  },
  {
    "path": "spec/unit/hanami/model/version_spec.rb",
    "chars": 160,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Hanami::Model::VERSION\" do\n  it \"exposes version\" do\n    expect(Hanami::M"
  }
]

About this extraction

This page contains the full source code of the hanami/model GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 150 files (414.9 KB), approximately 112.1k tokens, and a symbol index with 773 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!