hanami-sequel 1.1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ # Hanami::Sequel
2
+
3
+ This gem is designed to replace the `hanami-model` one in your
4
+ [Hanami](https://hanamirb.org/) project. It adds an equivalent set of database
5
+ commands to the `hanami` executable, and generates Sequel models.
6
+
7
+ Please note that using this gem could be considered bad practice with regards
8
+ to Hanami's architectural goals, as it does not provide any help to separate
9
+ the model into entities and repositories. On the other hand, it does nothing to
10
+ prevent it either.
11
+
12
+ ## Installation
13
+
14
+ Follow the instructions for removing `hanami-model`:
15
+ [Use Your Own ORM](http://hanamirb.org/guides/1.1/models/use-your-own-orm/)
16
+
17
+ Add this line to your `config/environment.rb`:
18
+
19
+ ```ruby
20
+ require "hamani/sequel/model"
21
+ ```
22
+
23
+ Add this line to your application's Gemfile (adding the gem to the `plugins`
24
+ group ensures that the `hanami` executable is correctly extended):
25
+
26
+ ```ruby
27
+ group :plugins do
28
+ gem 'hanami-sequel', '~> 1.1.0'
29
+ end
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ ## Versioning
37
+
38
+ This gem's version is based on the major and minor versions of Hanami. For
39
+ `hanami-X.Y.Z`, use `hanami-sequel-X.Y.P`. This gem's patch version (denoted as
40
+ `P`) is independent from Hanami's patch version (denoted as `Z`).
41
+
42
+ ## Configuration
43
+
44
+ As of now, the paths to migrations and models are hardcoded respectively to
45
+ `db/migrations/` and `lib/#{project_name}/models/`.
46
+
47
+ ## Usage
48
+
49
+ All the commands start with the `sequel` argument:
50
+
51
+ ```text
52
+ Commands:
53
+ hanami sequel create
54
+ hanami sequel drop
55
+ hanami sequel install
56
+ hanami sequel migrate [VERSION]
57
+ hanami sequel migration NAME
58
+ hanami sequel model NAME
59
+ hanami sequel seed
60
+ ```
61
+
62
+ #### Create a database table
63
+
64
+ $ hanami sequel model NAME
65
+
66
+ Where `NAME` is the name of the model. This creates a database migration, a
67
+ Sequel model and a spec file.
68
+
69
+ #### Create a database migration
70
+
71
+ $ hanami sequel migration NAME
72
+
73
+ Where `NAME` is an arbitrary name.
74
+
75
+ #### Create the database
76
+
77
+ $ hanami sequel create
78
+
79
+ This command will fail in the `production` environment.
80
+
81
+ #### Migrate the database
82
+
83
+ $ hanami sequel migrate [VERSION]
84
+
85
+ Where `VERSION` can be:
86
+
87
+ * "up" (default value), to do all the migrations, i.e. `hanami sequel migrate`
88
+ or `hanami sequel migrate up`.
89
+ * "down", to undo all the migrations, i.e. `hanami sequel migrate down`.
90
+ * a timestamp, representing the first part of the target migration file. E.g.
91
+ `hanami sequel migrate 20180201153930` to migrate to the database version as
92
+ of 1st February 2018 at 15:39:30 (if a migration file starting with this
93
+ value is found).
94
+
95
+ #### Seed the database
96
+
97
+ $ hanami sequel seed
98
+
99
+ This command will look up your models for `Hanami:Sequel:Seed` class methods
100
+ used to import constants into your tables. If an error occurs, the whole `seed`
101
+ operation will be rolled back.
102
+
103
+ #### Drop the database
104
+
105
+ $ hanami sequel drop
106
+
107
+ This command will fail in the `production` environment.
108
+
109
+ #### Install the database
110
+
111
+ $ hanami sequel install
112
+
113
+ This command `drop`s, `create`s, `migrate`s, then `seed`s your database. It will fail in
114
+ the `production` environment.
115
+
116
+ ## Development
117
+
118
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
119
+
120
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
121
+
122
+ ## Known issues / To-do list
123
+
124
+ * hardcoded configuration values
125
+ * no tests
126
+
127
+ ## Contributing
128
+
129
+ Bug reports and pull requests are welcome on GitHub at https://github.com/malin-as/hanami-sequel.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "hanami/sequel"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "hanami/sequel/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hanami-sequel"
8
+ spec.version = Hanami::Sequel::VERSION
9
+ spec.authors = ["Malina Sulca"]
10
+ spec.email = ["malina.sulca@gmail.com"]
11
+
12
+ spec.summary = %q{Integration of Sequel into Hanami.}
13
+ spec.description = %q{Integrates Sequel into Hanami by providing database commands and generating model files.}
14
+ spec.homepage = "https://github.com/malin-as/hanami-sequel.git"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against " \
22
+ "public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{^(test|spec|features)/})
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.16"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+
36
+ spec.add_dependency "sequel", "~> 5.0"
37
+ spec.add_dependency "hanami", "~> 1.1.0"
38
+ end
@@ -0,0 +1,3 @@
1
+ require "hanami/sequel/configuration"
2
+ require "hanami/sequel/cli"
3
+ require "hanami/sequel/version"
@@ -0,0 +1,62 @@
1
+ require 'fileutils'
2
+
3
+ module Hanami
4
+ module Sequel
5
+ module CLI
6
+ def self.hanamirc
7
+ @hanamirc ||= Hanamirc.new(Pathname.new('.'))
8
+ end
9
+
10
+ def self.lib_path
11
+ @lib_path ||= "lib/#{hanamirc.options[:project]}"
12
+ end
13
+
14
+ def self.models_path
15
+ @models_path ||= File.join(lib_path, 'models')
16
+ end
17
+
18
+ def self.spec_path
19
+ @spec_path ||= "spec/#{hanamirc.options[:project]}"
20
+ end
21
+
22
+ def self.config
23
+ @config ||= Hanami::Sequel::Configuration.new
24
+ end
25
+
26
+ def self.template(name)
27
+ File.join(File.dirname(__FILE__), 'templates', "#{name}.erb")
28
+ end
29
+
30
+ class ErBinding
31
+ def initialize(**vars)
32
+ @vars = vars
33
+ end
34
+
35
+ def bind
36
+ @vars.each_with_object(binding) do |(k, v), b|
37
+ b.local_variable_set(k.to_sym, v)
38
+ end
39
+ end
40
+ end
41
+
42
+ def self.generate(template, erbinding, destination)
43
+ raise "File #{destination} already exists" if File.exist?(destination)
44
+
45
+ dirname = File.dirname(destination)
46
+ FileUtils.mkdir_p(dirname) unless Dir.exist?(dirname)
47
+
48
+ content = ERB.new(File.read(template))
49
+ .result(erbinding&.bind)
50
+ File.write(destination, content)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ require_relative 'commands/create'
57
+ require_relative 'commands/drop'
58
+ require_relative 'commands/install'
59
+ require_relative 'commands/migrate'
60
+ require_relative 'commands/migration'
61
+ require_relative 'commands/model'
62
+ require_relative 'commands/seed'
@@ -0,0 +1,31 @@
1
+ module Hanami
2
+ module Sequel
3
+ module CLI
4
+ class Create < Hanami::CLI::Command
5
+ def call(**options)
6
+ Command.create
7
+ end
8
+ end
9
+ end
10
+
11
+ module Command
12
+ def self.create
13
+ env = Hanami::Environment.new
14
+ if env.environment == 'production'
15
+ raise 'Command unavailable in the production environment.'
16
+ end
17
+
18
+ db_url = ENV.fetch('DATABASE_URL')
19
+ db_conn, _, db_name = db_url.rpartition('/')
20
+
21
+ require 'sequel'
22
+
23
+ db = ::Sequel.connect("#{db_conn}/postgres",
24
+ loggers: Logger.new($stdout))
25
+ db.run("CREATE DATABASE #{db_name}")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Hanami::CLI.register 'sequel create', Hanami::Sequel::CLI::Create
@@ -0,0 +1,31 @@
1
+ module Hanami
2
+ module Sequel
3
+ module CLI
4
+ class Drop < Hanami::CLI::Command
5
+ def call(**options)
6
+ Command.drop
7
+ end
8
+ end
9
+ end
10
+
11
+ module Command
12
+ def self.drop
13
+ env = Hanami::Environment.new
14
+ if env.environment == 'production'
15
+ raise 'Command unavailable in the production environment.'
16
+ end
17
+
18
+ db_url = ENV.fetch('DATABASE_URL')
19
+ db_conn, _, db_name = db_url.rpartition('/')
20
+
21
+ require 'sequel'
22
+
23
+ db = ::Sequel.connect("#{db_conn}/postgres",
24
+ loggers: Logger.new($stdout))
25
+ db.run("DROP DATABASE IF EXISTS #{db_name}")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Hanami::CLI.register 'sequel drop', Hanami::Sequel::CLI::Drop
@@ -0,0 +1,16 @@
1
+ module Hanami
2
+ module Sequel
3
+ module CLI
4
+ class Install < Hanami::CLI::Command
5
+ def call(**options)
6
+ Command.drop
7
+ Command.create
8
+ Command.migrate
9
+ Command.seed
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ Hanami::CLI.register 'sequel install', Hanami::Sequel::CLI::Install
@@ -0,0 +1,42 @@
1
+ module Hanami
2
+ module Sequel
3
+ module CLI
4
+ class Migrate < Hanami::CLI::Command
5
+ argument :version,
6
+ required: false,
7
+ default: 'up',
8
+ desc: 'Version of the migration (number, offset, timestamp, "up" or "down"). Default: "up"'
9
+
10
+ def call(**options)
11
+ Command.migrate(options)
12
+ end
13
+ end
14
+ end
15
+
16
+ module Command
17
+ def self.migrate(**options)
18
+ Hanami::Environment.new # load DATABASE_URL
19
+
20
+ args = {}
21
+
22
+ if (v = options[:version])
23
+ case
24
+ when v == 'up' then;
25
+ when v == 'down' then args[:target] = 0
26
+ else args[:target] = Integer(v)
27
+ end
28
+ end
29
+
30
+ require 'sequel'
31
+ ::Sequel.extension :migration
32
+
33
+ db = ::Sequel.connect(ENV.fetch('DATABASE_URL'),
34
+ loggers: Logger.new($stdout))
35
+
36
+ ::Sequel::Migrator.run(db, CLI.config.migrations, **args)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ Hanami::CLI.register 'sequel migrate', Hanami::Sequel::CLI::Migrate
@@ -0,0 +1,23 @@
1
+ require 'erb'
2
+
3
+ module Hanami
4
+ module Sequel
5
+ module CLI
6
+ class Migration < Hanami::CLI::Command
7
+ argument :name, required: true, desc: 'Name of the migration'
8
+
9
+ def call(name:, **options)
10
+ now = Time.now.strftime('%Y%m%d%H%M%S')
11
+ name = Utils::String.underscore(name)
12
+ destination = File.join('./',
13
+ CLI.config.migrations,
14
+ "#{now}_#{name}.rb")
15
+
16
+ CLI.generate(CLI.template('migration'), nil, destination)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ Hanami::CLI.register 'sequel migration', Hanami::Sequel::CLI::Migration
@@ -0,0 +1,48 @@
1
+ require 'erb'
2
+
3
+ module Hanami
4
+ module Sequel
5
+ module CLI
6
+ class Model < Hanami::CLI::Command
7
+ argument :name, required: true, desc: 'Name of the model'
8
+
9
+ def call(name:, **options)
10
+ under_name = Utils::String.underscore(name)
11
+ table_name = Utils::String.pluralize(under_name)
12
+
13
+ camel_name = Utils::String.classify(name)
14
+ model_name = "#{camel_name}Model"
15
+
16
+ b = ErBinding.new(model_name: model_name,
17
+ table_name: table_name)
18
+
19
+ # db/migrations/date-create-table_name.rb
20
+
21
+ now = Time.now.strftime('%Y%m%d%H%M%S')
22
+ destination = File.join(CLI.config.migrations,
23
+ "#{now}_create_#{table_name}.rb")
24
+
25
+ CLI.generate(CLI.template('model-migration'), b, destination)
26
+
27
+ # lib/project_name/models/model_name.rb
28
+
29
+ destination = File.join(CLI.lib_path,
30
+ 'models',
31
+ "/#{under_name}_model.rb")
32
+
33
+ CLI.generate(CLI.template('model-sequel'), b, destination)
34
+
35
+ # spec/project_name/models/model_name_spec.rb
36
+
37
+ destination = File.join(CLI.spec_path,
38
+ 'models',
39
+ "/#{under_name}_model_spec.rb")
40
+
41
+ CLI.generate(CLI.template('model-spec'), b, destination)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ Hanami::CLI.register 'sequel model', Hanami::Sequel::CLI::Model