spectacles 1.0.1 → 6.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 93b01de9ec07bd98a69b60b3c1b15ae85a8e3b12
4
- data.tar.gz: d25a236871d3d35208e157419b69f25f935a1437
2
+ SHA256:
3
+ metadata.gz: e2459706103157e49b71cf2cc254abd49a98a547c0e997c2a1fe7329d368c8e6
4
+ data.tar.gz: c65c091166383559ff45c37886b48c8a6252082765bb18c2ea40a63f351318d6
5
5
  SHA512:
6
- metadata.gz: 315b5606b2b1fb645b81846c4e3a49e8a018b9cfef29593094272636e7a31667e6a45121bc970952acbbd3c1f28197a05ab49dfebc166c3492cff2502b5a8401
7
- data.tar.gz: aef7db4bcfdd525337c5744f1d45962eff3edd691cd281157ddc87e432f03adffcc420a61a585732b776aa79f5053a13fb2b007a8b681bf56f872882803ec1e4
6
+ metadata.gz: 55a1ff8f400aa2d5d91bab39cde96f81e6bfe1d78e39a298896f830bd34469ec687c34744b463f769cbecb66031d12551b98f5aa08241c9cf492b4aab58b546f
7
+ data.tar.gz: 65440da01035016a79411268ff5239a5329b9c6227112a9b69760a662e6f41def749f1f0d844a6cd60f8a028685f23a1024a98f832256cff385a639f6b04db95
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ jdk:
3
+ - openjdk8
4
+ rvm:
5
+ - 2.2
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ - jruby
11
+ cache: bundler
12
+ services:
13
+ - mysql
14
+ - postgresql
data/Gemfile CHANGED
@@ -10,7 +10,6 @@ platforms :jruby do
10
10
  end
11
11
 
12
12
  platforms :ruby do
13
- gem "mysql"
14
13
  gem "mysql2"
15
14
  gem "pg"
16
15
  gem "sqlite3"
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2012 Adam Hutchison, Brandon Dewitt
3
+ Copyright (c) 2012-2019 Adam Hutchison, Brandon Dewitt
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require "bundler/gem_tasks"
2
2
  require 'rake/testtask'
3
3
 
4
4
  namespace :test do
5
- adapters = [ :mysql, :mysql2, :postgresql, :sqlite3 ]
5
+ adapters = [ :mysql2, :postgresql, :sqlite3 ]
6
6
  task :all => [ :spectacles ] + adapters
7
7
 
8
8
  adapters.each do |adapter|
data/Readme.rdoc CHANGED
@@ -1,6 +1,8 @@
1
+ {<img src="https://travis-ci.org/liveh2o/spectacles.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/liveh2o/spectacles] {<img src="https://badge.fury.io/rb/spectacles.svg" alt="Gem Version" />}[https://badge.fury.io/rb/spectacles]
2
+
1
3
  = Spectacles
2
4
 
3
- Spectacles adds database view functionality to ActiveRecord. It is heavily inspired by Rails SQL Views (http://github.com/aeden/rails_sql_views/) and built from the ground-up to work with Rails 3.2+.
5
+ Spectacles adds database view functionality to ActiveRecord. It is heavily inspired by Rails SQL Views (created by https://github.com/aeden but no longer maintained) and built from the ground up to work with Rails 3.2+.
4
6
 
5
7
  Spectacles provides the ability to create views in migrations using a similar format to creating tables. It also provides an abstract view class that inherits from ActiveRecord::Base that can be used to create view-backed models.
6
8
 
@@ -57,7 +59,7 @@ they are kind of a cross between tables (which persist data) and views
57
59
  # just like Spectacles::View
58
60
  end
59
61
 
60
- Because these materialized views cache a snapshot of the data as it
62
+ Because materialized views cache a snapshot of the data as it
61
63
  exists at a point in time (typically when the view was created), you
62
64
  need to manually _refresh_ the view when new data is added to the
63
65
  original tables. You can do this with the +#refresh!+ method on
@@ -115,4 +117,4 @@ to affect how the new view is created:
115
117
 
116
118
  = License
117
119
 
118
- Spectacles is licensed under MIT license (Read lib/spectactles.rb for full license)
120
+ Spectacles is licensed under MIT license (Read the LICENSE file for full license)
@@ -0,0 +1,10 @@
1
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
2
+ class << self
3
+ alias_method(:_spectacles_orig_inherited, :inherited) if method_defined?(:inherited)
4
+
5
+ def inherited(_subclass)
6
+ ::Spectacles::load_adapters
7
+ _spectacles_orig_inherited(_subclass) if methods.include?(:_spectacles_orig_inherited)
8
+ end
9
+ end
10
+ end
@@ -1,9 +1,10 @@
1
1
  module Spectacles
2
2
  class Configuration
3
- attr_accessor :enable_schema_dump
3
+ attr_accessor :enable_schema_dump, :skip_views
4
4
 
5
5
  def initialize
6
6
  @enable_schema_dump = true
7
+ @skip_views = []
7
8
  end
8
9
  end
9
10
  end
@@ -3,15 +3,23 @@ module Spectacles
3
3
  self.abstract_class = true
4
4
 
5
5
  def self.new(*)
6
- raise NotImplementedError
6
+ raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
7
7
  end
8
8
 
9
9
  def self.materialized_view_exists?
10
10
  self.connection.materialized_view_exists?(self.view_name)
11
11
  end
12
12
 
13
- def self.refresh!
14
- self.connection.refresh_materialized_view(self.view_name)
13
+ def self.refresh!(concurrently: false)
14
+ if concurrently
15
+ self.connection.refresh_materialized_view_concurrently(self.view_name)
16
+ else
17
+ self.connection.refresh_materialized_view(self.view_name)
18
+ end
19
+ end
20
+
21
+ def self.refresh_concurrently!
22
+ refresh!(concurrently: true)
15
23
  end
16
24
 
17
25
  class << self
@@ -5,11 +5,14 @@ module Spectacles
5
5
  class Railtie < ::Rails::Railtie
6
6
  config.spectacles = ::ActiveSupport::OrderedOptions.new
7
7
 
8
- initializer "spectacles.configure" do |app|
8
+ initializer 'spectacles.configure' do |app|
9
9
  Spectacles.configure do |config|
10
- if app.config.spectacles.has_key?(:enable_schema_dump)
10
+ if app.config.spectacles.key?(:enable_schema_dump)
11
11
  config.enable_schema_dump = app.config.spectacles[:enable_schema_dump]
12
12
  end
13
+ if app.config.spectacles.key?(:skip_views)
14
+ config.skip_views = app.config.spectacles[:skip_views]
15
+ end
13
16
  end
14
17
  end
15
18
  end
@@ -1,18 +1,21 @@
1
1
  module Spectacles
2
2
  module SchemaDumper
3
3
  def self.dump_views(stream, connection)
4
- unless (Spectacles.config.enable_schema_dump == false)
4
+ unless Spectacles.config.enable_schema_dump == false
5
5
  connection.views.sort.each do |view|
6
+ next if skip_view?(view)
6
7
  dump_view(stream, connection, view)
7
8
  end
8
9
  end
9
10
  end
10
11
 
11
- def self.dump_materialized_views(stream, connection)
12
- unless (Spectacles.config.enable_schema_dump == false)
12
+ def self.dump_materialized_views(dumper, stream, connection)
13
+ unless Spectacles.config.enable_schema_dump == false
13
14
  if connection.supports_materialized_views?
14
15
  connection.materialized_views.sort.each do |view|
16
+ next if skip_view?(view)
15
17
  dump_materialized_view(stream, connection, view)
18
+ dumper.send(:indexes, view, stream)
16
19
  end
17
20
  end
18
21
  end
@@ -45,7 +48,7 @@ module Spectacles
45
48
  def self.format_option_hash(hash)
46
49
  hash.map do |key, value|
47
50
  "#{key}: #{format_option_value(value)}"
48
- end.join(", ")
51
+ end.join(', ')
49
52
  end
50
53
 
51
54
  def self.format_option_value(value)
@@ -57,5 +60,9 @@ module Spectacles
57
60
  else raise "can't format #{value.inspect}"
58
61
  end
59
62
  end
63
+
64
+ def self.skip_view?(view)
65
+ Spectacles.config.skip_views.any? { |item| item === view }
66
+ end
60
67
  end
61
68
  end
@@ -19,8 +19,8 @@ module Spectacles
19
19
  end
20
20
 
21
21
  def create_view_statement(view_name, create_query)
22
- query = "CREATE VIEW ? AS #{create_query}"
23
- query_array = [query, view_name.to_s]
22
+ #query = "CREATE VIEW ? AS #{create_query}"
23
+ #query_array = [query, view_name.to_s]
24
24
 
25
25
  #return ActiveRecord::Base.__send__(:sanitize_sql_array, query_array)
26
26
  "CREATE VIEW #{view_name} AS #{create_query}"
@@ -32,8 +32,8 @@ module Spectacles
32
32
  end
33
33
 
34
34
  def drop_view_statement(view_name)
35
- query = "DROP VIEW IF EXISTS ? "
36
- query_array = [query, view_name.to_s]
35
+ #query = "DROP VIEW IF EXISTS ? "
36
+ #query_array = [query, view_name.to_s]
37
37
 
38
38
  #return ActiveRecord::Base.__send__(:sanitize_sql_array, query_array)
39
39
  "DROP VIEW IF EXISTS #{view_name} "
@@ -74,6 +74,10 @@ module Spectacles
74
74
  def refresh_materialized_view(view_name)
75
75
  raise NotImplementedError, "Override refresh_materialized_view for your db adapter in #{self.class}"
76
76
  end
77
+
78
+ def refresh_materialized_view_concurrently(view_name)
79
+ raise NotImplementedError, "Override refresh_materialized_view_concurrently for your db adapter in #{self.class}"
80
+ end
77
81
  end
78
82
  end
79
83
  end
@@ -1,9 +1,47 @@
1
- require 'spectacles/schema_statements/mysql_adapter'
2
-
3
1
  module Spectacles
4
2
  module SchemaStatements
5
3
  module Mysql2Adapter
6
- include Spectacles::SchemaStatements::MysqlAdapter
4
+ include Spectacles::SchemaStatements::AbstractAdapter
5
+
6
+ # overrides the #tables method from ActiveRecord's MysqlAdapter
7
+ # to return only tables, and not views.
8
+ def tables(name = nil, database = nil, like = nil)
9
+ database = database ? quote_table_name(database) : "DATABASE()"
10
+ by_name = like ? "AND table_name LIKE #{quote(like)}" : ""
11
+
12
+ sql = <<-SQL.squish
13
+ SELECT table_name, table_type
14
+ FROM information_schema.tables
15
+ WHERE table_schema = #{database}
16
+ AND table_type = 'BASE TABLE'
17
+ #{by_name}
18
+ SQL
19
+
20
+ execute_and_free(sql, 'SCHEMA') do |result|
21
+ rows_from(result).map(&:first)
22
+ end
23
+ end
24
+
25
+ def views(name = nil) #:nodoc:
26
+ result = execute("SHOW FULL TABLES WHERE TABLE_TYPE='VIEW'")
27
+
28
+ rows_from(result).map(&:first)
29
+ end
30
+
31
+ def view_build_query(view, name = nil)
32
+ result = execute("SHOW CREATE VIEW #{view}", name)
33
+ algorithm_string = rows_from(result).first[1]
34
+
35
+ algorithm_string.gsub(/CREATE .*? (AS)+/i, "")
36
+ rescue ActiveRecord::StatementInvalid => e
37
+ raise "No view called #{view} found, #{e}"
38
+ end
39
+
40
+ private
41
+
42
+ def rows_from(result)
43
+ result.respond_to?(:rows) ? result.rows : result
44
+ end
7
45
  end
8
46
  end
9
47
  end
@@ -7,10 +7,12 @@ module Spectacles
7
7
 
8
8
  def views(name = nil) #:nodoc:
9
9
  q = <<-SQL
10
- SELECT table_name, table_type
11
- FROM information_schema.tables
12
- WHERE table_schema = ANY(current_schemas(false))
13
- AND table_type = 'VIEW'
10
+ SELECT t.table_name, t.table_type
11
+ FROM information_schema.tables AS t
12
+ INNER JOIN pg_class AS c ON c.relname = t.table_name
13
+ WHERE t.table_schema = ANY(current_schemas(false))
14
+ AND t.table_type = 'VIEW'
15
+ AND pg_catalog.pg_get_userbyid(c.relowner) = #{quote(database_username)}
14
16
  SQL
15
17
 
16
18
  execute(q, name).map { |row| row['table_name'] }
@@ -66,7 +68,7 @@ module Spectacles
66
68
  definition = row["definition"].strip.sub(/;$/, "")
67
69
 
68
70
  options = {}
69
- options[:data] = false if ispopulated == 'f'
71
+ options[:data] = false if ispopulated == 'f' || ispopulated == false
70
72
  options[:storage] = parse_storage_definition(storage) if storage.present?
71
73
  options[:tablespace] = tablespace if tablespace.present?
72
74
 
@@ -133,6 +135,10 @@ module Spectacles
133
135
  execute "REFRESH MATERIALIZED VIEW #{quote_table_name(view_name)}"
134
136
  end
135
137
 
138
+ def refresh_materialized_view_concurrently(view_name)
139
+ execute "REFRESH MATERIALIZED VIEW CONCURRENTLY #{quote_table_name(view_name)}"
140
+ end
141
+
136
142
  def parse_storage_definition(storage)
137
143
  # JRuby 9000 returns storage as an Array, whereas
138
144
  # MRI returns a string.
@@ -145,6 +151,10 @@ module Spectacles
145
151
  hash
146
152
  end
147
153
  end
154
+
155
+ def database_username
156
+ @config[:username]
157
+ end
148
158
  end
149
159
  end
150
160
  end
@@ -21,7 +21,7 @@ module Spectacles
21
21
  end
22
22
 
23
23
  def generate_view_query(*columns)
24
- sql = <<-SQL
24
+ <<-SQL
25
25
  SELECT #{columns.join(',')}
26
26
  FROM sqlite_master
27
27
  WHERE type = 'view'
@@ -1,3 +1,3 @@
1
1
  module Spectacles
2
- VERSION = "1.0.1"
2
+ VERSION = "6.0.0"
3
3
  end
@@ -3,8 +3,7 @@ module Spectacles
3
3
  self.abstract_class = true
4
4
 
5
5
  def self.new(*)
6
- warn "DEPRECATION WARNING: #{self} is an abstract class and should not be instantiated. In v1.0, calling `#{self}.new` will raise a NotImplementedError."
7
- super # raise NotImplementedError, "#{self} is an abstract class and can not be instantiated."
6
+ raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
8
7
  end
9
8
 
10
9
  def self.view_exists?
data/lib/spectacles.rb CHANGED
@@ -6,6 +6,7 @@ require 'spectacles/view'
6
6
  require 'spectacles/materialized_view'
7
7
  require 'spectacles/version'
8
8
  require 'spectacles/configuration'
9
+ require 'spectacles/abstract_adapter_override'
9
10
 
10
11
  require 'spectacles/railtie' if defined?(Rails)
11
12
 
@@ -23,21 +24,12 @@ module Spectacles
23
24
  end
24
25
  end
25
26
 
26
- ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
27
- alias_method(:_spectacles_original_inherited, :inherited) if method_defined?(:inherited)
28
-
29
- def self.inherited(klass)
30
- ::Spectacles::load_adapters
31
- _spectacles_orig_inherited if method_defined?(:_spectacles_original_inherited)
32
- end
33
- end
34
-
35
27
  ActiveRecord::SchemaDumper.class_eval do
36
28
  alias_method(:_spectacles_orig_trailer, :trailer)
37
29
 
38
30
  def trailer(stream)
39
31
  ::Spectacles::SchemaDumper.dump_views(stream, @connection)
40
- ::Spectacles::SchemaDumper.dump_materialized_views(stream, @connection)
32
+ ::Spectacles::SchemaDumper.dump_materialized_views(self, stream, @connection)
41
33
  _spectacles_orig_trailer(stream)
42
34
  end
43
35
  end
@@ -6,7 +6,7 @@ describe "Spectacles::SchemaStatements::Mysql2Adapter" do
6
6
  :host => "localhost",
7
7
  :username => "root"
8
8
  }
9
-
9
+
10
10
  configure_database(config)
11
11
  recreate_database("spectacles_test")
12
12
  load_schema
@@ -25,44 +25,44 @@ describe "Spectacles::SchemaStatements::PostgreSQLAdapter" do
25
25
 
26
26
  describe "#view_build_query" do
27
27
  it "should escape double-quotes returned by Postgres" do
28
- test_base.view_build_query(:new_product_users).must_match(/\\"/)
28
+ _(test_base.view_build_query(:new_product_users)).must_match(/\\"/)
29
29
  end
30
30
  end
31
31
 
32
32
  describe "#materialized_views" do
33
33
  it "should support materialized views" do
34
- test_base.supports_materialized_views?.must_equal true
34
+ _(test_base.supports_materialized_views?).must_equal true
35
35
  end
36
36
  end
37
37
 
38
38
  describe "#create_materialized_view_statement" do
39
39
  it "should work with no options" do
40
40
  query = test_base.create_materialized_view_statement(:view_name, "select_query_here")
41
- query.must_match(/create materialized view view_name as select_query_here with data/i)
41
+ _(query).must_match(/create materialized view view_name as select_query_here with data/i)
42
42
  end
43
43
 
44
44
  it "should allow column names to be specified" do
45
45
  query = test_base.create_materialized_view_statement(:view_name, "select_query_here",
46
46
  columns: %i(first second third))
47
- query.must_match(/create materialized view view_name \(first,second,third\) as select_query_here with data/i)
47
+ _(query).must_match(/create materialized view view_name \(first,second,third\) as select_query_here with data/i)
48
48
  end
49
49
 
50
50
  it "should allow storage parameters to be specified" do
51
51
  query = test_base.create_materialized_view_statement(:view_name, "select_query_here",
52
52
  storage: { bats_in_belfry: true, max_wingspan: 15 })
53
- query.must_match(/create materialized view view_name with \(bats_in_belfry=true, max_wingspan=15\) as select_query_here with data/i)
53
+ _(query).must_match(/create materialized view view_name with \(bats_in_belfry=true, max_wingspan=15\) as select_query_here with data/i)
54
54
  end
55
55
 
56
56
  it "should allow tablespace to be specified" do
57
57
  query = test_base.create_materialized_view_statement(:view_name, "select_query_here",
58
58
  tablespace: :the_final_frontier)
59
- query.must_match(/create materialized view view_name tablespace the_final_frontier as select_query_here with data/i)
59
+ _(query).must_match(/create materialized view view_name tablespace the_final_frontier as select_query_here with data/i)
60
60
  end
61
61
 
62
62
  it "should allow empty view to be created" do
63
63
  query = test_base.create_materialized_view_statement(:view_name, "select_query_here",
64
64
  data: false)
65
- query.must_match(/create materialized view view_name as select_query_here with no data/i)
65
+ _(query).must_match(/create materialized view view_name as select_query_here with no data/i)
66
66
  end
67
67
  end
68
68
  end
data/specs/spec_helper.rb CHANGED
@@ -50,4 +50,4 @@ def recreate_database(database)
50
50
  ActiveRecord::Base.connection.drop_database(database) rescue nil
51
51
  ActiveRecord::Base.connection.create_database(database)
52
52
  ActiveRecord::Base.establish_connection(@database_config.merge(:database => database))
53
- end
53
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe "loading an adapter" do
4
+ it "calls the original AR::CA::AbstractAdapter.inherited method" do
5
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
6
+ def self.inherited(subclass)
7
+ @_spectacles_inherited_called = true
8
+ end
9
+ end
10
+ load File.join(__dir__, '../../lib/spectacles/abstract_adapter_override.rb')
11
+ Class.new(ActiveRecord::ConnectionAdapters::AbstractAdapter)
12
+ _(ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_variable_get("@_spectacles_inherited_called")).must_equal true
13
+ end
14
+ end
@@ -1,10 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Spectacles::SchemaStatements::AbstractAdapter do
3
+ describe Spectacles::SchemaStatements::AbstractAdapter do
4
4
  class TestBase
5
5
  extend Spectacles::SchemaStatements::AbstractAdapter
6
6
 
7
7
  def self.materialized_views
8
+ @materialized_views ||= nil
8
9
  @materialized_views || super
9
10
  end
10
11
 
@@ -17,64 +18,64 @@ describe Spectacles::SchemaStatements::AbstractAdapter do
17
18
  end
18
19
 
19
20
  describe "#create_view" do
20
- it "throws error when block not given and no build_query" do
21
- lambda { TestBase.create_view(:view_name) }.must_raise(RuntimeError)
21
+ it "throws error when block not given and no build_query" do
22
+ _(lambda { TestBase.create_view(:view_name) }).must_raise(RuntimeError)
22
23
  end
23
24
  end
24
25
 
25
- describe "#views" do
26
- it "throws error when accessed on AbstractAdapter" do
27
- lambda { TestBase.views }.must_raise(RuntimeError)
26
+ describe "#views" do
27
+ it "throws error when accessed on AbstractAdapter" do
28
+ _(lambda { TestBase.views }).must_raise(RuntimeError)
28
29
  end
29
30
  end
30
31
 
31
32
  describe "#supports_materialized_views?" do
32
33
  it "returns false when accessed on AbstractAdapter" do
33
- TestBase.supports_materialized_views?.must_equal false
34
+ _(TestBase.supports_materialized_views?).must_equal false
34
35
  end
35
36
  end
36
37
 
37
38
  describe "#materialized_views" do
38
39
  it "throws error when accessed on AbstractAdapter" do
39
- lambda { TestBase.materialized_views }.must_raise(NotImplementedError)
40
+ _(lambda { TestBase.materialized_views }).must_raise(NotImplementedError)
40
41
  end
41
42
  end
42
43
 
43
44
  describe "#materialized_view_exists?" do
44
45
  it "is true when materialized_views includes the view" do
45
46
  TestBase.with_materialized_views(%w(alpha beta gamma)) do
46
- TestBase.materialized_view_exists?(:beta).must_equal true
47
+ _(TestBase.materialized_view_exists?(:beta)).must_equal true
47
48
  end
48
49
  end
49
50
 
50
51
  it "is false when materialized_views does not include the view" do
51
52
  TestBase.with_materialized_views(%w(alpha beta gamma)) do
52
- TestBase.materialized_view_exists?(:delta).must_equal false
53
+ _(TestBase.materialized_view_exists?(:delta)).must_equal false
53
54
  end
54
55
  end
55
56
  end
56
57
 
57
58
  describe "#materialized_view_build_query" do
58
59
  it "throws error when accessed on AbstractAdapter" do
59
- lambda { TestBase.materialized_view_build_query(:books) }.must_raise(NotImplementedError)
60
+ _(lambda { TestBase.materialized_view_build_query(:books) }).must_raise(NotImplementedError)
60
61
  end
61
62
  end
62
63
 
63
64
  describe "#create_materialized_view" do
64
65
  it "throws error when accessed on AbstractAdapter" do
65
- lambda { TestBase.create_materialized_view(:books) }.must_raise(NotImplementedError)
66
+ _(lambda { TestBase.create_materialized_view(:books) }).must_raise(NotImplementedError)
66
67
  end
67
68
  end
68
69
 
69
70
  describe "#drop_materialized_view" do
70
71
  it "throws error when accessed on AbstractAdapter" do
71
- lambda { TestBase.drop_materialized_view(:books) }.must_raise(NotImplementedError)
72
+ _(lambda { TestBase.drop_materialized_view(:books) }).must_raise(NotImplementedError)
72
73
  end
73
74
  end
74
75
 
75
76
  describe "#refresh_materialized_view" do
76
77
  it "throws error when accessed on AbstractAdapter" do
77
- lambda { TestBase.refresh_materialized_view(:books) }.must_raise(NotImplementedError)
78
+ _(lambda { TestBase.refresh_materialized_view(:books) }).must_raise(NotImplementedError)
78
79
  end
79
80
  end
80
81
 
@@ -2,6 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe Spectacles::View do
4
4
  it "is an abstract class" do
5
- Spectacles::View.abstract_class?.must_be true
5
+ _(Spectacles::View.abstract_class?).must_be true
6
6
  end
7
- end
7
+ end
@@ -1,57 +1,66 @@
1
- require 'spec_helper'
2
-
3
1
  shared_examples_for "an adapter" do |adapter|
4
2
  shared_base = Class.new do
5
3
  extend Spectacles::SchemaStatements.const_get(adapter)
6
4
  def self.quote_table_name(name); name; end
7
5
  def self.quote_column_name(name); name; end
8
- def self.execute(query); query; end
6
+ def self.execute(query); query; end
9
7
  end
10
8
 
11
- describe "ActiveRecord::SchemaDumper#dump" do
9
+ describe "ActiveRecord::SchemaDumper#dump" do
12
10
  before(:each) do
13
11
  ActiveRecord::Base.connection.drop_view(:new_product_users)
14
12
 
15
- ActiveRecord::Base.connection.create_view(:new_product_users) do
13
+ ActiveRecord::Base.connection.create_view(:new_product_users) do
16
14
  "SELECT name AS product_name, first_name AS username FROM
17
15
  products JOIN users ON users.id = products.user_id"
18
16
  end
19
17
 
20
18
  if ActiveRecord::Base.connection.supports_materialized_views?
21
- ActiveRecord::Base.connection.create_materialized_view(:materialized_product_users, force: true) do
19
+ ActiveRecord::Base.connection.drop_materialized_view(:materialized_product_users)
20
+ ActiveRecord::Base.connection.drop_materialized_view(:empty_materialized_product_users)
21
+
22
+ ActiveRecord::Base.connection.create_materialized_view(:materialized_product_users, force: true) do
22
23
  "SELECT name AS product_name, first_name AS username FROM
23
24
  products JOIN users ON users.id = products.user_id"
24
25
  end
25
26
 
26
- ActiveRecord::Base.connection.create_materialized_view(:empty_materialized_product_users, storage: { fillfactor: 50 }, data: false, force: true) do
27
+ ActiveRecord::Base.connection.add_index :materialized_product_users, :product_name
28
+
29
+ ActiveRecord::Base.connection.create_materialized_view(:empty_materialized_product_users, storage: { fillfactor: 50 }, data: false, force: true) do
27
30
  "SELECT name AS product_name, first_name AS username FROM
28
31
  products JOIN users ON users.id = products.user_id"
29
32
  end
30
33
  end
31
34
  end
32
35
 
33
- it "should return create_view in dump stream" do
36
+ it "should return create_view in dump stream" do
34
37
  stream = StringIO.new
35
38
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
36
- stream.string.must_match(/create_view/)
39
+ _(stream.string).must_match(/create_view/)
37
40
  end
38
41
 
39
42
  if ActiveRecord::Base.connection.supports_materialized_views?
40
- it "should return create_materialized_view in dump stream" do
43
+ it "should return create_materialized_view in dump stream" do
44
+ stream = StringIO.new
45
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
46
+ _(stream.string).must_match(/create_materialized_view/)
47
+ end
48
+
49
+ it "should return add_index in dump stream" do
41
50
  stream = StringIO.new
42
51
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
43
- stream.string.must_match(/create_materialized_view/)
52
+ _(stream.string).must_match(/add_index/)
44
53
  end
45
54
 
46
55
  it "should include options for create_materialized_view" do
47
56
  stream = StringIO.new
48
57
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
49
- stream.string.must_match(/create_materialized_view.*fillfactor: 50/)
50
- stream.string.must_match(/create_materialized_view.*data: false/)
58
+ _(stream.string).must_match(/create_materialized_view.*fillfactor: 50/)
59
+ _(stream.string).must_match(/create_materialized_view.*data: false/)
51
60
  end
52
61
  end
53
62
 
54
- it "should rebuild views in dump stream" do
63
+ it "should rebuild views in dump stream" do
55
64
  stream = StringIO.new
56
65
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
57
66
 
@@ -71,10 +80,10 @@ shared_examples_for "an adapter" do |adapter|
71
80
 
72
81
  eval(stream.string)
73
82
 
74
- ActiveRecord::Base.connection.views.must_include('new_product_users')
83
+ _(ActiveRecord::Base.connection.views).must_include('new_product_users')
75
84
 
76
85
  if ActiveRecord::Base.connection.supports_materialized_views?
77
- ActiveRecord::Base.connection.materialized_views.must_include('materialized_product_users')
86
+ _(ActiveRecord::Base.connection.materialized_views).must_include('materialized_product_users')
78
87
  end
79
88
  end
80
89
  end
@@ -82,41 +91,41 @@ shared_examples_for "an adapter" do |adapter|
82
91
  describe "#create_view" do
83
92
  let(:view_name) { :view_name }
84
93
 
85
- it "throws error when block not given and no build_query" do
86
- lambda { shared_base.create_view(view_name) }.must_raise(RuntimeError)
94
+ it "throws error when block not given and no build_query" do
95
+ _(lambda { shared_base.create_view(view_name) }).must_raise(RuntimeError)
87
96
  end
88
97
 
89
98
  describe "view_name" do
90
- it "takes a symbol as the view_name" do
91
- shared_base.create_view(view_name.to_sym, Product.all).must_match(/#{view_name}/)
99
+ it "takes a symbol as the view_name" do
100
+ _(shared_base.create_view(view_name.to_sym, Product.all)).must_match(/#{view_name}/)
92
101
  end
93
102
 
94
- it "takes a string as the view_name" do
95
- shared_base.create_view(view_name.to_s, Product.all).must_match(/#{view_name}/)
103
+ it "takes a string as the view_name" do
104
+ _(shared_base.create_view(view_name.to_s, Product.all)).must_match(/#{view_name}/)
96
105
  end
97
106
  end
98
107
 
99
- describe "build_query" do
100
- it "uses a string if passed" do
108
+ describe "build_query" do
109
+ it "uses a string if passed" do
101
110
  select_statement = "SELECT * FROM products"
102
- shared_base.create_view(view_name, select_statement).must_match(/#{Regexp.escape(select_statement)}/)
111
+ _(shared_base.create_view(view_name, select_statement)).must_match(/#{Regexp.escape(select_statement)}/)
103
112
  end
104
113
 
105
- it "uses an Arel::Relation if passed" do
114
+ it "uses an Arel::Relation if passed" do
106
115
  select_statement = Product.all.to_sql
107
- shared_base.create_view(view_name, Product.all).must_match(/#{Regexp.escape(select_statement)}/)
116
+ _(shared_base.create_view(view_name, Product.all)).must_match(/#{Regexp.escape(select_statement)}/)
108
117
  end
109
118
  end
110
119
 
111
- describe "block" do
112
- it "can use an Arel::Relation from the yield" do
120
+ describe "block" do
121
+ it "can use an Arel::Relation from the yield" do
113
122
  select_statement = Product.all.to_sql
114
- shared_base.create_view(view_name) { Product.all }.must_match(/#{Regexp.escape(select_statement)}/)
123
+ _(shared_base.create_view(view_name) { Product.all }).must_match(/#{Regexp.escape(select_statement)}/)
115
124
  end
116
125
 
117
- it "can use a String from the yield" do
126
+ it "can use a String from the yield" do
118
127
  select_statement = "SELECT * FROM products"
119
- shared_base.create_view(view_name) { "SELECT * FROM products" }.must_match(/#{Regexp.escape(select_statement)}/)
128
+ _(shared_base.create_view(view_name) { "SELECT * FROM products" }).must_match(/#{Regexp.escape(select_statement)}/)
120
129
  end
121
130
  end
122
131
  end
@@ -125,55 +134,72 @@ shared_examples_for "an adapter" do |adapter|
125
134
  let(:view_name) { :view_name }
126
135
 
127
136
  describe "view_name" do
128
- it "takes a symbol as the view_name" do
129
- shared_base.drop_view(view_name.to_sym).must_match(/#{view_name}/)
137
+ it "takes a symbol as the view_name" do
138
+ _(shared_base.drop_view(view_name.to_sym)).must_match(/#{view_name}/)
130
139
  end
131
140
 
132
- it "takes a string as the view_name" do
133
- shared_base.drop_view(view_name.to_s).must_match(/#{view_name}/)
141
+ it "takes a string as the view_name" do
142
+ _(shared_base.drop_view(view_name.to_s)).must_match(/#{view_name}/)
134
143
  end
135
144
  end
136
145
  end
137
146
 
147
+ describe "#tables" do
148
+ it "returns an array of all table names" do
149
+ _(ActiveRecord::Base.connection.tables).must_include("products")
150
+ _(ActiveRecord::Base.connection.tables).must_include("users")
151
+ end
152
+
153
+ it "does not include the names of the views" do
154
+ _(ActiveRecord::Base.connection.tables).wont_include("new_product_users")
155
+ end
156
+ end
157
+
158
+ describe "#views" do
159
+ it "returns an array of all views" do
160
+ _(ActiveRecord::Base.connection.views).must_include("new_product_users")
161
+ end
162
+ end
163
+
138
164
  if shared_base.supports_materialized_views?
139
165
  describe "#create_materialized_view" do
140
166
  let(:view_name) { :view_name }
141
167
 
142
168
  it "throws error when block not given and no build_query" do
143
- lambda { shared_base.create_materialized_view(view_name) }.must_raise(RuntimeError)
169
+ _(lambda { shared_base.create_materialized_view(view_name) }).must_raise(RuntimeError)
144
170
  end
145
171
 
146
172
  describe "view_name" do
147
173
  it "takes a symbol as the view_name" do
148
- shared_base.create_materialized_view(view_name.to_sym, Product.all).must_match(/#{view_name}/)
174
+ _(shared_base.create_materialized_view(view_name.to_sym, Product.all)).must_match(/#{view_name}/)
149
175
  end
150
176
 
151
177
  it "takes a string as the view_name" do
152
- shared_base.create_materialized_view(view_name.to_s, Product.all).must_match(/#{view_name}/)
178
+ _(shared_base.create_materialized_view(view_name.to_s, Product.all)).must_match(/#{view_name}/)
153
179
  end
154
180
  end
155
181
 
156
182
  describe "build_query" do
157
183
  it "uses a string if passed" do
158
184
  select_statement = "SELECT * FROM products"
159
- shared_base.create_materialized_view(view_name, select_statement).must_match(/#{Regexp.escape(select_statement)}/)
185
+ _(shared_base.create_materialized_view(view_name, select_statement)).must_match(/#{Regexp.escape(select_statement)}/)
160
186
  end
161
187
 
162
188
  it "uses an Arel::Relation if passed" do
163
189
  select_statement = Product.all.to_sql
164
- shared_base.create_materialized_view(view_name, Product.all).must_match(/#{Regexp.escape(select_statement)}/)
190
+ _(shared_base.create_materialized_view(view_name, Product.all)).must_match(/#{Regexp.escape(select_statement)}/)
165
191
  end
166
192
  end
167
193
 
168
194
  describe "block" do
169
195
  it "can use an Arel::Relation from the yield" do
170
196
  select_statement = Product.all.to_sql
171
- shared_base.create_materialized_view(view_name) { Product.all }.must_match(/#{Regexp.escape(select_statement)}/)
197
+ _(shared_base.create_materialized_view(view_name) { Product.all }).must_match(/#{Regexp.escape(select_statement)}/)
172
198
  end
173
199
 
174
200
  it "can use a String from the yield" do
175
201
  select_statement = "SELECT * FROM products"
176
- shared_base.create_materialized_view(view_name) { "SELECT * FROM products" }.must_match(/#{Regexp.escape(select_statement)}/)
202
+ _(shared_base.create_materialized_view(view_name) { "SELECT * FROM products" }).must_match(/#{Regexp.escape(select_statement)}/)
177
203
  end
178
204
  end
179
205
  end
@@ -183,11 +209,11 @@ shared_examples_for "an adapter" do |adapter|
183
209
 
184
210
  describe "view_name" do
185
211
  it "takes a symbol as the view_name" do
186
- shared_base.drop_materialized_view(view_name.to_sym).must_match(/#{view_name}/)
212
+ _(shared_base.drop_materialized_view(view_name.to_sym)).must_match(/#{view_name}/)
187
213
  end
188
214
 
189
215
  it "takes a string as the view_name" do
190
- shared_base.drop_materialized_view(view_name.to_s).must_match(/#{view_name}/)
216
+ _(shared_base.drop_materialized_view(view_name.to_s)).must_match(/#{view_name}/)
191
217
  end
192
218
  end
193
219
  end
@@ -197,18 +223,18 @@ shared_examples_for "an adapter" do |adapter|
197
223
 
198
224
  describe "view_name" do
199
225
  it "takes a symbol as the view_name" do
200
- shared_base.refresh_materialized_view(view_name.to_sym).must_match(/#{view_name}/)
226
+ _(shared_base.refresh_materialized_view(view_name.to_sym)).must_match(/#{view_name}/)
201
227
  end
202
228
 
203
229
  it "takes a string as the view_name" do
204
- shared_base.refresh_materialized_view(view_name.to_s).must_match(/#{view_name}/)
230
+ _(shared_base.refresh_materialized_view(view_name.to_s)).must_match(/#{view_name}/)
205
231
  end
206
232
  end
207
233
  end
208
234
  else
209
235
  describe "#materialized_views" do
210
236
  it "should not be supported by #{adapter}" do
211
- lambda { shared_base.materialized_views }.must_raise(NotImplementedError)
237
+ _(lambda { shared_base.materialized_views }).must_raise(NotImplementedError)
212
238
  end
213
239
  end
214
240
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  shared_examples_for "a view model" do
4
2
  ActiveRecord::Base.connection.create_view(:new_product_users) do
5
3
  "SELECT name AS product_name, first_name AS username FROM
@@ -12,18 +10,22 @@ shared_examples_for "a view model" do
12
10
 
13
11
  describe "Spectacles::View" do
14
12
  describe "inherited class" do
15
- it "can has scopes" do
13
+ before(:each) do
16
14
  User.destroy_all
17
15
  Product.destroy_all
18
16
  @john = User.create(:first_name => 'John', :last_name => 'Doe')
19
17
  @john.products.create(:name => 'Rubber Duck', :value => 10)
18
+ end
19
+
20
+ let(:new_product_user) { NewProductUser.duck_lovers.load.first }
20
21
 
21
- NewProductUser.duck_lovers.load.first.username.must_be @john.first_name
22
+ it "can have scopes" do
23
+ _(new_product_user.username).must_be @john.first_name
22
24
  end
23
25
 
24
26
  describe "an instance" do
25
27
  it "is readonly" do
26
- NewProductUser.new.readonly?.must_be true
28
+ _(new_product_user.readonly?).must_be true
27
29
  end
28
30
  end
29
31
  end
@@ -48,12 +50,12 @@ shared_examples_for "a view model" do
48
50
  MaterializedProductUser.refresh!
49
51
  end
50
52
 
51
- it "can has scopes" do
52
- MaterializedProductUser.duck_lovers.load.first.username.must_be @john.first_name
53
+ it "can have scopes" do
54
+ _(MaterializedProductUser.duck_lovers.load.first.username).must_be @john.first_name
53
55
  end
54
56
 
55
57
  it "is readonly" do
56
- MaterializedProductUser.first.readonly?.must_be true
58
+ _(MaterializedProductUser.first.readonly?).must_be true
57
59
  end
58
60
  end
59
61
  end
data/spectacles.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
10
10
  gem.email = ["liveh2o@gmail.com, brandonsdewitt@gmail.com"]
11
11
  gem.homepage = "http://github.com/liveh2o/spectacles"
12
12
  gem.summary = %q{Spectacles (derived from RailsSQLViews) adds database view functionality to ActiveRecord.}
13
- gem.description = %q{Spectacles adds database view functionality to ActiveRecord. Current supported adapters include Postgres, SQLite and Vertica (MySQL is close).}
13
+ gem.description = %q{Spectacles adds database view functionality to ActiveRecord. Current supported adapters include Postgres, SQLite, Vertica, and MySQL.}
14
14
  gem.license = 'MIT'
15
15
 
16
16
  gem.files = `git ls-files`.split($\)
@@ -21,9 +21,9 @@ Gem::Specification.new do |gem|
21
21
  ##
22
22
  # Dependencies
23
23
  #
24
- gem.required_ruby_version = ">= 2.0.0"
25
- gem.add_dependency "activerecord", ">= 3.2.0"
26
- gem.add_dependency "activesupport", ">= 3.2.0"
24
+ gem.required_ruby_version = ">= 2.2.0"
25
+ gem.add_dependency "activerecord", ">= 3.2.0", "~> 6.1.0"
26
+ gem.add_dependency "activesupport", ">= 3.2.0", "~> 6.1.0"
27
27
 
28
28
  ##
29
29
  # Development dependencies
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectacles
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hutchison, Brandon Dewitt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-29 00:00:00.000000000 Z
11
+ date: 2022-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.2.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: 6.1.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: 3.2.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 6.1.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: activesupport
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -31,6 +37,9 @@ dependencies:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: 3.2.0
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: 6.1.0
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +47,9 @@ dependencies:
38
47
  - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: 3.2.0
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: 6.1.0
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: rake
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +79,7 @@ dependencies:
67
79
  - !ruby/object:Gem::Version
68
80
  version: '0'
69
81
  description: Spectacles adds database view functionality to ActiveRecord. Current
70
- supported adapters include Postgres, SQLite and Vertica (MySQL is close).
82
+ supported adapters include Postgres, SQLite, Vertica, and MySQL.
71
83
  email:
72
84
  - liveh2o@gmail.com, brandonsdewitt@gmail.com
73
85
  executables: []
@@ -75,11 +87,13 @@ extensions: []
75
87
  extra_rdoc_files: []
76
88
  files:
77
89
  - ".gitignore"
90
+ - ".travis.yml"
78
91
  - Gemfile
79
92
  - LICENSE
80
93
  - Rakefile
81
94
  - Readme.rdoc
82
95
  - lib/spectacles.rb
96
+ - lib/spectacles/abstract_adapter_override.rb
83
97
  - lib/spectacles/configuration.rb
84
98
  - lib/spectacles/materialized_view.rb
85
99
  - lib/spectacles/railtie.rb
@@ -87,7 +101,6 @@ files:
87
101
  - lib/spectacles/schema_statements.rb
88
102
  - lib/spectacles/schema_statements/abstract_adapter.rb
89
103
  - lib/spectacles/schema_statements/mysql2_adapter.rb
90
- - lib/spectacles/schema_statements/mysql_adapter.rb
91
104
  - lib/spectacles/schema_statements/postgresql_adapter.rb
92
105
  - lib/spectacles/schema_statements/sqlite3_adapter.rb
93
106
  - lib/spectacles/schema_statements/sqlserver_adapter.rb
@@ -95,10 +108,10 @@ files:
95
108
  - lib/spectacles/version.rb
96
109
  - lib/spectacles/view.rb
97
110
  - specs/adapters/mysql2_adapter_spec.rb
98
- - specs/adapters/mysql_adapter_spec.rb
99
111
  - specs/adapters/postgresql_adapter_spec.rb
100
112
  - specs/adapters/sqlite3_adapter_spec.rb
101
113
  - specs/spec_helper.rb
114
+ - specs/spectacles/abstract_adapter_override_spec.rb
102
115
  - specs/spectacles/schema_statements/abstract_adapter_spec.rb
103
116
  - specs/spectacles/view_spec.rb
104
117
  - specs/support/minitest_matchers.rb
@@ -110,7 +123,7 @@ homepage: http://github.com/liveh2o/spectacles
110
123
  licenses:
111
124
  - MIT
112
125
  metadata: {}
113
- post_install_message:
126
+ post_install_message:
114
127
  rdoc_options: []
115
128
  require_paths:
116
129
  - lib
@@ -118,16 +131,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
118
131
  requirements:
119
132
  - - ">="
120
133
  - !ruby/object:Gem::Version
121
- version: 2.0.0
134
+ version: 2.2.0
122
135
  required_rubygems_version: !ruby/object:Gem::Requirement
123
136
  requirements:
124
137
  - - ">="
125
138
  - !ruby/object:Gem::Version
126
139
  version: '0'
127
140
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.4.8
130
- signing_key:
141
+ rubygems_version: 3.3.6
142
+ signing_key:
131
143
  specification_version: 4
132
144
  summary: Spectacles (derived from RailsSQLViews) adds database view functionality
133
145
  to ActiveRecord.
@@ -1,39 +0,0 @@
1
- require 'spectacles/schema_statements/abstract_adapter'
2
-
3
- module Spectacles
4
- module SchemaStatements
5
- module MysqlAdapter
6
- include Spectacles::SchemaStatements::AbstractAdapter
7
-
8
- # overrides the #tables method from ActiveRecord's MysqlAdapter
9
- # to return only tables, and not views.
10
- def tables(name = nil, database = nil, like = nil)
11
- database = database ? quote_table_name(database) : "DATABASE()"
12
- by_name = like ? "AND table_name LIKE #{quote(like)}" : ""
13
-
14
- sql = <<-SQL.squish
15
- SELECT table_name, table_type
16
- FROM information_schema.tables
17
- WHERE table_schema = #{database}
18
- AND table_type = 'BASE TABLE'
19
- #{by_name}
20
- SQL
21
-
22
- execute_and_free(sql, 'SCHEMA') do |result|
23
- result.collect(&:first)
24
- end
25
- end
26
-
27
- def views(name = nil) #:nodoc:
28
- execute("SHOW FULL TABLES WHERE TABLE_TYPE='VIEW'").map { |row| row[0] }
29
- end
30
-
31
- def view_build_query(view, name = nil)
32
- row = execute("SHOW CREATE VIEW #{view}", name).first
33
- return row[1].gsub(/CREATE .*? (AS)+/i, "")
34
- rescue ActiveRecord::StatementInvalid => e
35
- raise "No view called #{view} found"
36
- end
37
- end
38
- end
39
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Spectacles::SchemaStatements::MysqlAdapter" do
4
- config = {
5
- :adapter => "mysql",
6
- :host => "localhost",
7
- :username => "root"
8
- }
9
- configure_database(config)
10
- recreate_database("spectacles_test")
11
- load_schema
12
-
13
- it_behaves_like "an adapter", "MysqlAdapter"
14
- it_behaves_like "a view model"
15
- end