Skip to content

Commit

Permalink
Merge 1e4cd63 into 0636616
Browse files Browse the repository at this point in the history
  • Loading branch information
aldesantis committed Dec 29, 2017
2 parents 0636616 + 1e4cd63 commit 743924d
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 59 deletions.
5 changes: 4 additions & 1 deletion lib/pragma/migration.rb
@@ -1,12 +1,15 @@
# frozen_string_literal: true

require 'rack'
require 'mustermann'

require 'pragma/migration/base'
require 'pragma/migration/repository'
require 'pragma/migration/version'
require 'pragma/migration/runner'
require 'pragma/migration/version_number'

module Pragma
module Migration
VERSION = '0.1.0'
end
end
6 changes: 6 additions & 0 deletions lib/pragma/migration/base.rb
Expand Up @@ -6,6 +6,12 @@ class Base
class << self
attr_reader :pattern, :description

def applies_to?(request)
request.path =~ Mustermann.new(pattern)
end

protected

def apply_to(pattern)
@pattern = pattern
end
Expand Down
51 changes: 44 additions & 7 deletions lib/pragma/migration/repository.rb
Expand Up @@ -4,25 +4,62 @@ module Pragma
module Migration
class Repository
class << self
def version(number, migrations = [])
versions << Version.new(number, migrations)
sort_versions
end

def sorted_versions
versions.dup
end

def migrations_since(user_version)
def user_version_proc
@user_version_proc ||= begin
lambda do |request|
request.get_header('X-Api-Version')
end
end
end

def migrations_since(request_or_version)
user_version = if request_or_version.is_a?(Rack::Request)
user_version_from(request_or_version)
else
request_or_version
end

@versions.select { |version| version > user_version }.flat_map(&:migrations)
end

def migration_active?(user_version, migration)
def migrations_for(request)
migrations_since(request).select do |migration|
migration.applies_to?(request)
end
end

def migration_active?(migration, request: nil, user_version: nil)
unless request || user_version
fail ArgumentError, 'You must pass one of :request or :user_version'
end

user_version ||= user_version_from(request)

@versions.any? do |version|
version > user_version && version.migration?(migration)
end
end

protected

def user_version_from(request)
user_version = user_version_proc.call(request)
sorted_versions.include?(user_version) ? user_version : sorted_versions.last
end

def version(number, migrations = [])
versions << Version.new(number, migrations)
sort_versions
end

def user_version(&block)
@user_version_proc = block
end

private

def versions
Expand Down
11 changes: 5 additions & 6 deletions lib/pragma/migration/runner.rb
Expand Up @@ -3,23 +3,22 @@
module Pragma
module Migration
class Runner
attr_reader :repository, :user_version
attr_reader :repository

def initialize(repository:, user_version:)
def initialize(repository)
@repository = repository
@user_version = user_version
end

def run_upwards(request)
repository.migrations_since(user_version).each do |migration|
repository.migrations_for(request).each do |migration|
request = migration.new.up(request)
end

request
end

def run_downwards(response)
repository.migrations_since(user_version).reverse.each do |migration|
def run_downwards(request, response)
repository.migrations_for(request).reverse.each do |migration|
response = migration.new.down(response)
end

Expand Down
7 changes: 7 additions & 0 deletions lib/pragma/migration/version_number.rb
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Pragma
module Migration
VERSION = '0.1.0'
end
end
9 changes: 5 additions & 4 deletions pragma-migration.gemspec
@@ -1,9 +1,8 @@

# frozen_string_literal: true

lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'pragma/migration'
require 'pragma/migration/version_number'

Gem::Specification.new do |spec|
spec.name = 'pragma-migration'
Expand All @@ -22,10 +21,12 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

spec.add_development_dependency 'bundler'
spec.add_dependency 'mustermann', '~> 1.0'
spec.add_dependency 'rack', '~> 2.0'

spec.add_development_dependency 'coveralls'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'rubocop'
spec.add_development_dependency 'rubocop-rspec'
spec.add_development_dependency 'coveralls'
end
27 changes: 20 additions & 7 deletions spec/pragma/migration/base_spec.rb
Expand Up @@ -2,22 +2,35 @@

RSpec.describe Pragma::Migration::Base do
subject(:migration_klass) do
Class.new(described_class)
Class.new(described_class) do
apply_to '/api/v1/articles/*'
describe 'Test migration'
end
end

describe '.apply_to' do
before { subject.apply_to('test_pattern') }

it 'sets the pattern' do
expect(migration_klass.pattern).to eq('test_pattern')
expect(migration_klass.pattern).to eq('/api/v1/articles/*')
end
end

describe '.describe' do
before { subject.describe('test_description') }

it 'sets the description' do
expect(migration_klass.description).to eq('test_description')
expect(migration_klass.description).to eq('Test migration')
end
end

describe '.applies_to?' do
it 'returns true when the pattern applies to a path' do
expect(migration_klass).to be_applies_to(
Rack::Request.new('PATH_INFO' => '/api/v1/articles/1')
)
end

it 'returns false when the pattern does not apply to a path' do
expect(migration_klass).not_to be_applies_to(
Rack::Request.new('PATH_INFO' => '/api/v1/posts/1')
)
end
end
end
68 changes: 53 additions & 15 deletions spec/pragma/migration/repository_spec.rb
Expand Up @@ -5,19 +5,25 @@

describe '.version' do
it 'adds a version' do
repository.version '2017-12-27'
repository.instance_eval do
version '2017-12-27'
end

expect(repository.sorted_versions).to match([instance_of(Pragma::Migration::Version)])
end

it 'keeps versions sorted' do
repository.version '2017-12-28'
repository.version '2017-12-27'
repository.instance_eval do
version '2017-12-28'
version '2017-12-27'
end

expect(repository.sorted_versions.map(&:number)).to eq(['2017-12-27', '2017-12-28'])
end

it 'initializes migrations' do
migration = Class.new(Pragma::Migration::Base)
repository.version '2017-12-28', [migration]
repository.send :version, '2017-12-28', [migration]
expect(repository.sorted_versions.first.migrations).to eq([migration])
end
end
Expand All @@ -28,10 +34,10 @@
let(:migration3) { Class.new(Pragma::Migration::Base) }

before do
repository.version '2017-12-24'
repository.version '2017-12-25', [migration1]
repository.version '2017-12-26', [migration2]
repository.version '2017-12-27', [migration3]
repository.send :version, '2017-12-24'
repository.send :version, '2017-12-25', [migration1]
repository.send :version, '2017-12-26', [migration2]
repository.send :version, '2017-12-27', [migration3]
end

it 'collects all the changes since the specified version' do
Expand All @@ -42,21 +48,53 @@
describe '.migration_active?' do
let(:migration1) { Class.new(Pragma::Migration::Base) }
let(:migration2) { Class.new(Pragma::Migration::Base) }
let(:migration3) { Class.new(Pragma::Migration::Base) }

before do
repository.version '2017-12-24'
repository.version '2017-12-25', [migration1]
repository.version '2017-12-26', [migration2]
repository.version '2017-12-27', [migration3]
repository.send :version, '2017-12-24'
repository.send :version, '2017-12-25', [migration1]
repository.send :version, '2017-12-26', [migration2]
end

it 'returns false when the migration is not active' do
expect(repository.migration_active?('2017-12-25', migration1)).to eq(false)
expect(repository.migration_active?(migration1, user_version: '2017-12-25')).to eq(false)
end

it 'returns true when the migration is active' do
expect(repository.migration_active?('2017-12-25', migration2)).to eq(true)
expect(repository.migration_active?(migration2, user_version: '2017-12-25')).to eq(true)
end
end

describe '.migrations_for' do
let(:migration1) do
Class.new(Pragma::Migration::Base) do
apply_to '/api/v1/articles/*'
end
end

let(:migration2) do
Class.new(Pragma::Migration::Base) do
apply_to '/api/v1/articles/*'
end
end

let(:migration3) do
Class.new(Pragma::Migration::Base) do
apply_to '/api/v1/posts/*'
end
end

before do
repository.send :version, '2017-12-24'
repository.send :version, '2017-12-25', [migration1]
repository.send :version, '2017-12-26', [migration2]
repository.send :version, '2017-12-27', [migration3]
end

it 'returns the migrations applying to the current request' do
expect(repository.migrations_for(Rack::Request.new(
'PATH_INFO' => '/api/v1/articles/1',
'X-Api-Version' => '2017-12-25'
))).to eq([migration2])
end
end
end

0 comments on commit 743924d

Please sign in to comment.