rails_db_views 0.0.3 → 0.0.4

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
2
  SHA1:
3
- metadata.gz: 6edc610e6b4cbd12093917e89a779067b9b78608
4
- data.tar.gz: 7ecebff3dbe8ff7c5d95161f65f543b69135ea64
3
+ metadata.gz: ff2f855836b239c4af2dae529189588761c22ff3
4
+ data.tar.gz: 027d2f0e0f45ddb654d5ba70f4613219aa581eba
5
5
  SHA512:
6
- metadata.gz: 0a986ce2241177d8f7f1757c88da836ed636bb9393bd2c04e64f02ca85a6217a4aed40799dae0bc40a29403910154e6d4d153a160c9e602b5d60bd3fee96b470
7
- data.tar.gz: 3083faeccd65ab15521d93ef971d3b48dfceaf0a4b82522f023dc2ce7fea2ebad721cd76e7a9abb68ae9678fbc907b65e2951175e48fdb9a8d1e91ac4c4a9441
6
+ metadata.gz: c1289482ced1e66da617ad275fd184e68fd2050aaa1ed0f53288066931e35418a6424ab4e7b09fc2bef98e598a90c382bb3d7311ff5107344061ed80b31d7bcd
7
+ data.tar.gz: 871085dcaac1dc9663bdc6c4b4ce983f9e9d9be8363c41f0cfeced6ca70023334598d09c9481efbca3aaa722411d7412fe6cefe23653e225a7d388e3b4e76f7e
@@ -0,0 +1,16 @@
1
+ class RailsDbViews::Configuration
2
+ attr_accessor :views_paths, :views_extension
3
+ attr_accessor :functions_paths, :functions_extension
4
+
5
+ def initialize
6
+ @views_paths = %w(db/views)
7
+ @views_extension = "*.sql"
8
+
9
+ @functions_paths = %w(db/functions)
10
+ @functions_extension = "*.sql"
11
+ end
12
+
13
+ def [] *args
14
+ raise "rails_db_view has changed! Please use the methods views_paths/views_extension instead of hash notation"
15
+ end
16
+ end
@@ -0,0 +1,138 @@
1
+ class RailsDbViews::DatabaseSymbol
2
+ class CircularReferenceError < RuntimeError; end
3
+ class SymbolNotFound < RuntimeError; end
4
+
5
+ attr_accessor :path, :sql_content, :status, :required, :inverse_of_required, :marked_as_deleted, :name
6
+ alias :marked_as_deleted? :marked_as_deleted
7
+
8
+ module Status
9
+ LOADED = :loaded
10
+ IN_PROGRESS = :in_progress
11
+ UNLOADED = :unloaded
12
+ end
13
+
14
+ def initialize file_path
15
+ @path = file_path
16
+ @name = File.basename(file_path, ".*")
17
+
18
+ @status = :none
19
+ @required = []
20
+ @marked_as_deleted = false
21
+ @sql_content = File.read(@path)
22
+ @inverse_of_required = []
23
+
24
+ load_directives
25
+ end
26
+
27
+ def process_inverse_of_required!
28
+ @required.each do |name|
29
+ required = RailsDbViews::Factory.get(self.class, name)
30
+ not_found_error if required.nil?
31
+ required.inverse_of_required << self.name
32
+ end
33
+ end
34
+
35
+ def mark_as_delete!
36
+ @marked_as_deleted = true
37
+ end
38
+
39
+ def loaded?
40
+ status == Status::LOADED
41
+ end
42
+
43
+ def in_progress?
44
+ status == Status::IN_PROGRESS
45
+ end
46
+
47
+ def unloaded?
48
+ status == Status::UNLOADED
49
+ end
50
+
51
+ def create!
52
+ return if marked_as_deleted? || loaded?
53
+
54
+ circular_reference_error if in_progress?
55
+
56
+ self.status = Status::IN_PROGRESS
57
+
58
+ required.each do |symbol_name|
59
+ symbol = RailsDbViews::Factory.get(self.class, symbol_name)
60
+ not_found_error(symbol_name) if symbol.nil?
61
+ symbol.create!
62
+ end
63
+
64
+ ActiveRecord::Base.connection.execute(create_sql)
65
+
66
+ self.status = Status::LOADED
67
+ end
68
+
69
+ def drop!
70
+ return if loaded?
71
+
72
+ circular_reference_error if in_progress?
73
+
74
+ self.status = Status::IN_PROGRESS
75
+
76
+ # We start by the required one to delete first.
77
+ inverse_of_required.each do |symbol_name|
78
+ symbol = RailsDbViews::Factory.get(self.class, symbol_name)
79
+ not_found_error(symbol_name) if symbol.nil?
80
+ symbol.drop!
81
+ end
82
+
83
+ begin
84
+ ActiveRecord::Base.connection.execute(drop_sql)
85
+ #rescue ActiveRecord::ActiveRecordError => e #Probably because the symbol doesn't exists yet.
86
+ # handle_error_on_drop
87
+ end
88
+
89
+ self.status = Status::LOADED
90
+ end
91
+
92
+ # Theses methods should be implemented in children objects.
93
+ def drop_sql
94
+ raise NotImplementedError, "DatabaseSymbol should not be instanciated"
95
+ end
96
+
97
+ def create_sql
98
+ raise NotImplementedError, "DatabaseSymbol should not be instanciated"
99
+ end
100
+
101
+ def handle_error_on_drop
102
+ raise NotImplementedError, "DatabaseSymbol should not be instanciated"
103
+ end
104
+
105
+ protected
106
+ TWO_DASH_DIRECTIVE_START = /^--[ \t]*!/
107
+ SHARP_CHAR_DIRECTIVE_START = /^#[ \t]*!/
108
+ DIRECTIVE_START = /#{TWO_DASH_DIRECTIVE_START}|#{SHARP_CHAR_DIRECTIVE_START}/
109
+
110
+ def circular_reference_error
111
+ raise CircularReferenceError, "Circular file reference! (file: #{path})"
112
+ end
113
+
114
+ def not_found_error(symbol_name)
115
+ raise SymbolNotFound, "#{self.class.name} `#{symbol_name}` referenced in file #{path} cannot be found..."
116
+ end
117
+
118
+ def load_directives
119
+ content_lines = sql_content.split("\n")
120
+
121
+ directives = content_lines.map(&:strip).select{ |x| x =~ DIRECTIVE_START }.map{ |x|
122
+ x.gsub(DIRECTIVE_START, "")
123
+ }
124
+
125
+ directives.each do |d|
126
+ case d
127
+ when /^require /
128
+ self.required += d.split(/[ \t]+/)[1..-1]
129
+ when /^delete(d?) /
130
+ self.mark_as_delete!
131
+ else
132
+ raise IllegalDirective, "I don't know what to do with `#{d}` (in #{path})"
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,46 @@
1
+
2
+ class RailsDbViews::Factory
3
+ class AmbigousNameError < RuntimeError; end
4
+
5
+ @symbols = {}
6
+
7
+ class << self
8
+ attr_reader :symbols
9
+
10
+ def register_files symbol_class, files
11
+ @symbols[symbol_class.to_s] ||= {}
12
+
13
+ files.each do |file|
14
+ symbol = symbol_class.new(file)
15
+
16
+ if s=@symbols[symbol_class.to_s][symbol.name]
17
+ raise AmbigousNameError, "between #{file} and #{s.path}"
18
+ end
19
+
20
+ @symbols[symbol_class.to_s][symbol.name] = symbol
21
+ end
22
+
23
+ @symbols.values.map(&:values).flatten.each(&:process_inverse_of_required!)
24
+ end
25
+
26
+ def drop(symbol_class)
27
+ symbol_list = @symbols[symbol_class.to_s]
28
+
29
+ symbol_list.values.each(&:drop!) if symbol_list
30
+ end
31
+
32
+ def create(symbol_class)
33
+ symbol_list = @symbols[symbol_class.to_s]
34
+
35
+ symbol_list.values.each(&:create!) if symbol_list
36
+ end
37
+
38
+ def get(symbol_class, name)
39
+ (@symbols[symbol_class.to_s]||{})[name]
40
+ end
41
+
42
+ def clear!
43
+ @symbols = {}
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ class RailsDbViews::Function < RailsDbViews::DatabaseSymbol
2
+ def create_sql
3
+ puts "CREATE OR REPLACE FUNCTION #{name}..."
4
+ "CREATE OR REPLACE FUNCTION #{name} #{sql_content}"
5
+ end
6
+
7
+ def drop_sql
8
+ puts "DROP FUNCTION #{name}..."
9
+ "DROP FUNCTION #{name}"
10
+ end
11
+
12
+ def handle_error_on_drop
13
+ puts "WARNING: DROP FUNCTION #{name}... ERROR"
14
+ end
15
+ end
@@ -1,11 +1,11 @@
1
- class Railtie < Rails::Railtie
1
+ require 'rails_db_views/configuration'
2
+
3
+ class RailsDbViews::Railtie < Rails::Railtie
2
4
  railtie_name :rails_db_views
3
5
 
4
- config.rails_db_views = ActiveSupport::OrderedHash.new
6
+ config.rails_db_views = RailsDbViews::Configuration.new
5
7
 
6
8
  initializer "rails_db_views.initialize" do |app|
7
- app.config.rails_db_views[:views_path] = %w( db/views )
8
- app.config.rails_db_views[:views_ext] = "*.sql"
9
9
  end
10
10
 
11
11
  rake_tasks do
@@ -1,3 +1,3 @@
1
1
  module RailsDbViews
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,15 @@
1
+ class RailsDbViews::View < RailsDbViews::DatabaseSymbol
2
+ def create_sql
3
+ puts "CREATE VIEW #{name}..."
4
+ "CREATE VIEW #{name} AS #{sql_content}"
5
+ end
6
+
7
+ def drop_sql
8
+ puts "DROP VIEW #{name}..."
9
+ "DROP VIEW #{name}"
10
+ end
11
+
12
+ def handle_error_on_drop
13
+ puts "WARNING: DROP VIEW #{name}... ERROR"
14
+ end
15
+ end
@@ -1,4 +1,11 @@
1
1
  module RailsDbViews
2
- require 'rails_db_views/railtie' if defined?(Rails)
3
- require 'rails_db_views/db_views_creator'
2
+ unless defined?(Rails)
3
+ raise "This gem is made for Ruby on Rails!"
4
+ end
4
5
  end
6
+
7
+ require 'rails_db_views/railtie'
8
+ require 'rails_db_views/database_symbol'
9
+ require 'rails_db_views/view'
10
+ require 'rails_db_views/function'
11
+ require 'rails_db_views/factory'
@@ -1,44 +1,55 @@
1
- namespace :db do
1
+ def apply_to paths, extension, method, klazz
2
+ RailsDbViews::Factory.clear!
2
3
 
3
- desc "Generate all the database views of the current project"
4
- task :create_views => :environment do
5
- creator = RailsDbViews::DbViewsCreator.new
4
+ paths.each do |path|
5
+ RailsDbViews::Factory.register_files klazz,
6
+ Dir[File.join(path, extension)].map{|x| File.expand_path(x)}
7
+ end
6
8
 
7
- views_path, views_ext = Rails.configuration.rails_db_views[:views_path], Rails.configuration.rails_db_views[:views_ext]
9
+ RailsDbViews::Factory.send(method, klazz)
10
+ end
8
11
 
9
- views_path.each do |path|
10
- creator.register_files Dir[File.join(path, views_ext)].map{|x| File.expand_path(x)}
11
- end
12
+ namespace :db do
12
13
 
13
- creator.create_views
14
+ desc "Create all the database views of the current project. Views are usually located in db/views"
15
+ task :create_views => :environment do
16
+ config = Rails.configuration.rails_db_views
17
+ apply_to config.views_paths, config.views_extension, :create, RailsDbViews::View
14
18
  end
15
19
 
16
20
  desc "Drop all the database views of the current project"
17
21
  task :drop_views => :environment do
18
- creator = RailsDbViews::DbViewsCreator.new
19
-
20
- views_path, views_ext = Rails.configuration.rails_db_views[:views_path], Rails.configuration.rails_db_views[:views_ext]
22
+ config = Rails.configuration.rails_db_views
23
+ apply_to config.views_paths, config.views_extension, :drop, RailsDbViews::View
24
+ end
21
25
 
22
- views_path.each do |path|
23
- creator.register_files Dir[File.join(path, views_ext)].map{|x| File.expand_path(x)}
26
+ desc "Create or replace all the functions"
27
+ task :create_functions => :environment do
28
+ adapter_type = ActiveRecord::Base.connection.adapter_name.downcase.to_sym
29
+ config = Rails.configuration.rails_db_views
30
+
31
+ if adapter_type != :sqlite
32
+ apply_to config.functions_paths, config.functions_extension, :create, RailsDbViews::Function
33
+ else
34
+ if config.functions_paths.length>=1 || File.is_directory?(config.functions_paths.try(:first))
35
+ puts "Notice: db:create_functions will not trigger for sqlite."
36
+ end
24
37
  end
38
+ end
25
39
 
26
- creator.drop_views
40
+ desc "Remove all the functions (to use manually only)"
41
+ task :drop_functions => :environment do
42
+ config = Rails.configuration.rails_db_views
43
+ apply_to config.functions_paths, config.functions_extension, :drop, RailsDbViews::Function
27
44
  end
28
45
  end
29
46
 
30
47
  require 'rake/hooks'
31
48
 
32
- before "db:migrate" do
33
- Rake::Task['db:drop_views'].invoke
34
- end
35
- before "db:rollback" do
36
- Rake::Task['db:drop_views'].invoke
37
- end
49
+ before("db:migrate"){ Rake::Task['db:drop_views'].invoke }
50
+ before("db:migrate"){ Rake::Task['db:create_functions'].invoke }
51
+ after("db:migrate"){ Rake::Task['db:create_views'].invoke }
38
52
 
39
- after "db:migrate" do
40
- Rake::Task['db:create_views'].invoke
41
- end
42
- after "db:rollback" do
43
- Rake::Task['db:create_views'].invoke
44
- end
53
+ before("db:rollback"){ Rake::Task['db:drop_views'].invoke }
54
+ before("db:rollback"){ Rake::Task['db:create_functions'].invoke }
55
+ after("db:rollback"){ Rake::Task['db:create_views'].invoke }
@@ -4,8 +4,8 @@
4
4
  # Ensure the SQLite 3 gem is defined in your Gemfile
5
5
  # gem 'sqlite3'
6
6
  development:
7
- adapter: sqlite3
8
- database: db/development.sqlite3
7
+ adapter: postgresql
8
+ database: rails_db_views
9
9
  pool: 5
10
10
  timeout: 5000
11
11
 
Binary file
@@ -0,0 +1,5 @@
1
+ (x integer, y integer) RETURNS integer AS $$
2
+ BEGIN
3
+ RETURN x + y;
4
+ END;
5
+ $$ LANGUAGE plpgsql;
@@ -13,4 +13,7 @@
13
13
 
14
14
  ActiveRecord::Schema.define(version: 0) do
15
15
 
16
+ # These are extensions that must be enabled in order to support this database
17
+ enable_extension "plpgsql"
18
+
16
19
  end
File without changes
@@ -1,2 +1,2 @@
1
- --!require required
1
+ --!require required
2
2
  SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
@@ -166,3 +166,319 @@ SQLite3::SQLException: table required already exists: CREATE VIEW required AS SE
166
166
  ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
167
167
   (0.9ms) CREATE VIEW required AS SELECT 1 as id
168
168
   (1.1ms) CREATE VIEW hello_world AS SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
169
+  (0.2ms) CREATE OR REPLACE FUNCTION (x integer, y integer) RETURNS integer AS $$
170
+ BEGIN
171
+ RETURN x + y;
172
+ END;
173
+ $$ LANGUAGE plpgsql; add.sql
174
+ SQLite3::SQLException: near "OR": syntax error: CREATE OR REPLACE FUNCTION (x integer, y integer) RETURNS integer AS $$
175
+ BEGIN
176
+ RETURN x + y;
177
+ END;
178
+ $$ LANGUAGE plpgsql; add.sql
179
+  (0.2ms) DROP FUNCTION add.sql
180
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
181
+  (0.1ms) DROP FUNCTION add.sql
182
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
183
+  (0.2ms) DROP FUNCTION add.sql
184
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
185
+  (0.1ms) DROP FUNCTION add.sql
186
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
187
+  (0.2ms) DROP FUNCTION add.sql
188
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
189
+  (0.2ms) DROP FUNCTION add.sql
190
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
191
+  (0.2ms) DROP FUNCTION add.sql
192
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
193
+  (0.2ms) DROP FUNCTION add.sql
194
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
195
+  (0.2ms) DROP FUNCTION add.sql
196
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
197
+  (0.2ms) DROP FUNCTION add.sql
198
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
199
+  (0.1ms) DROP FUNCTION add.sql
200
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
201
+  (0.2ms) DROP FUNCTION add.sql
202
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add.sql
203
+  (0.2ms) DROP FUNCTION add
204
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
205
+  (0.2ms) CREATE VIEW required
206
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
207
+  (0.1ms) CREATE VIEW hello_world
208
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
209
+  (1.0ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
210
+  (0.1ms) select sqlite_version(*)
211
+  (0.8ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
212
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
213
+  (0.1ms) CREATE VIEW SELECT 1 as id
214
+ SQLite3::SQLException: near "SELECT": syntax error: CREATE VIEW SELECT 1 as id
215
+  (0.2ms) DROP FUNCTION add
216
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
217
+  (0.2ms) CREATE VIEW required
218
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
219
+  (0.2ms) CREATE VIEW hello_world
220
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
221
+  (1.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
222
+  (0.1ms) select sqlite_version(*)
223
+  (0.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
224
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
225
+  (0.1ms) CREATE VIEW SELECT 1 as id
226
+ SQLite3::SQLException: near "SELECT": syntax error: CREATE VIEW SELECT 1 as id
227
+  (0.2ms) DROP FUNCTION add
228
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
229
+  (0.1ms) CREATE VIEW required
230
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
231
+  (0.1ms) CREATE VIEW hello_world
232
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
233
+  (1.9ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
234
+  (0.1ms) select sqlite_version(*)
235
+  (1.2ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
236
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
237
+  (1.0ms) CREATE VIEW required AS SELECT 1 as id
238
+  (0.2ms) DROP FUNCTION add
239
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
240
+  (0.1ms) CREATE VIEW required
241
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
242
+  (0.1ms) CREATE VIEW hello_world
243
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
244
+  (1.4ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
245
+  (0.1ms) select sqlite_version(*)
246
+  (0.8ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
247
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
248
+  (0.7ms) CREATE VIEW required AS SELECT 1 as id
249
+  (0.9ms) CREATE VIEW hello_world AS --!require required
250
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
251
+  (0.2ms) DROP FUNCTION add
252
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
253
+  (0.1ms) CREATE VIEW required
254
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
255
+  (0.1ms) CREATE VIEW hello_world
256
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
257
+  (1.4ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
258
+  (0.1ms) select sqlite_version(*)
259
+  (0.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
260
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
261
+  (0.8ms) CREATE VIEW required AS SELECT 1 as id
262
+  (0.9ms) CREATE VIEW hello_world AS --!require required
263
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
264
+  (0.2ms) DROP FUNCTION add
265
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
266
+  (0.1ms) CREATE VIEW required
267
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
268
+  (0.1ms) CREATE VIEW hello_world
269
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
270
+  (1.0ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
271
+  (0.1ms) select sqlite_version(*)
272
+  (1.0ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
273
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
274
+  (0.9ms) CREATE VIEW required AS SELECT 1 as id
275
+  (0.8ms) CREATE VIEW hello_world AS --!require required
276
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
277
+  (0.2ms) DROP FUNCTION add
278
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
279
+  (0.1ms) CREATE VIEW required
280
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
281
+  (0.1ms) CREATE VIEW hello_world
282
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
283
+  (1.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL)
284
+  (0.1ms) select sqlite_version(*)
285
+  (0.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
286
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
287
+  (0.8ms) CREATE VIEW required AS SELECT 1 as id
288
+  (1.1ms) CREATE VIEW hello_world AS --!require required
289
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
290
+  (0.2ms) CREATE VIEW required
291
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
292
+  (0.1ms) CREATE VIEW hello_world
293
+ SQLite3::SQLException: near "hello_world": syntax error: CREATE VIEW hello_world
294
+  (1.1ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL) 
295
+  (0.1ms) select sqlite_version(*)
296
+  (0.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
297
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
298
+  (3.9ms) CREATE VIEW required AS SELECT 1 as id
299
+  (0.9ms) CREATE VIEW hello_world AS --!require required
300
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
301
+  (0.2ms) DROP FUNCTION add
302
+ SQLite3::SQLException: near "FUNCTION": syntax error: DROP FUNCTION add
303
+  (0.2ms) CREATE VIEW required
304
+ SQLite3::SQLException: near "required": syntax error: CREATE VIEW required
305
+  (0.4ms) DROP VIEW required
306
+ SQLite3::SQLException: no such view: required: DROP VIEW required
307
+  (0.3ms) DROP VIEW required
308
+ SQLite3::SQLException: no such view: required: DROP VIEW required
309
+  (0.3ms) DROP VIEW required
310
+ SQLite3::SQLException: no such view: required: DROP VIEW required
311
+  (0.3ms) DROP VIEW required
312
+ SQLite3::SQLException: no such view: required: DROP VIEW required
313
+  (0.1ms) DROP VIEW hello_world
314
+ SQLite3::SQLException: no such view: hello_world: DROP VIEW hello_world
315
+  (1.2ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL) 
316
+  (0.1ms) select sqlite_version(*)
317
+  (0.8ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
318
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
319
+  (0.7ms) CREATE VIEW required AS SELECT 1 as id
320
+  (0.7ms) CREATE VIEW hello_world AS --!require required
321
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
322
+  (0.3ms) DROP VIEW required
323
+ SQLite3::SQLException: no such view: required: DROP VIEW required
324
+  (0.2ms) DROP VIEW hello_world
325
+ SQLite3::SQLException: no such view: hello_world: DROP VIEW hello_world
326
+  (1.0ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL) 
327
+  (0.1ms) select sqlite_version(*)
328
+  (0.8ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
329
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
330
+  (4.8ms) CREATE VIEW required AS SELECT 1 as id
331
+  (1.3ms) CREATE VIEW hello_world AS --!require required
332
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
333
+  (0.9ms) CREATE OR REPLACE FUNCTION (x integer, y integer) RETURNS integer AS $$
334
+ BEGIN
335
+ RETURN x + y;
336
+ END;
337
+ $$ LANGUAGE plpgsql; add
338
+ PG::SyntaxError: ERROR: syntax error at or near "("
339
+ LINE 1: CREATE OR REPLACE FUNCTION (x integer, y integer) RETURNS in...
340
+ ^
341
+ : CREATE OR REPLACE FUNCTION (x integer, y integer) RETURNS integer AS $$
342
+ BEGIN
343
+ RETURN x + y;
344
+ END;
345
+ $$ LANGUAGE plpgsql; add
346
+  (0.3ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
347
+ BEGIN
348
+ RETURN x + y;
349
+ END;
350
+ $$ LANGUAGE plpgsql; add
351
+ PG::SyntaxError: ERROR: syntax error at or near "add"
352
+ LINE 5: $$ LANGUAGE plpgsql; add
353
+ ^
354
+ : CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
355
+ BEGIN
356
+ RETURN x + y;
357
+ END;
358
+ $$ LANGUAGE plpgsql; add
359
+  (8.7ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
360
+ BEGIN
361
+ RETURN x + y;
362
+ END;
363
+ $$ LANGUAGE plpgsql;
364
+  (17.7ms) DROP VIEW required
365
+ PG::UndefinedTable: ERROR: view "required" does not exist
366
+ : DROP VIEW required
367
+  (0.3ms) DROP VIEW hello_world
368
+ PG::UndefinedTable: ERROR: view "hello_world" does not exist
369
+ : DROP VIEW hello_world
370
+  (24.1ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL)
371
+  (1.0ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
372
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
373
+  (23.3ms) CREATE VIEW required AS SELECT 1 as id
374
+  (5.5ms) CREATE VIEW hello_world AS --!require required
375
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
376
+  (12.3ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
377
+ BEGIN
378
+ RETURN x + y;
379
+ END;
380
+ $$ LANGUAGE plpgsql;
381
+  (10.6ms) DROP VIEW required
382
+ PG::DependentObjectsStillExist: ERROR: cannot drop view required because other objects depend on it
383
+ DETAIL: view hello_world depends on view required
384
+ HINT: Use DROP ... CASCADE to drop the dependent objects too.
385
+ : DROP VIEW required
386
+  (18.0ms) DROP VIEW hello_world
387
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
388
+  (0.2ms) CREATE VIEW required AS SELECT 1 as id
389
+ PG::DuplicateTable: ERROR: relation "required" already exists
390
+ : CREATE VIEW required AS SELECT 1 as id
391
+  (2.5ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
392
+ BEGIN
393
+ RETURN x + y;
394
+ END;
395
+ $$ LANGUAGE plpgsql;
396
+  (1.0ms) DROP VIEW required
397
+  (0.4ms) DROP VIEW hello_world
398
+ PG::UndefinedTable: ERROR: view "hello_world" does not exist
399
+ : DROP VIEW hello_world
400
+ ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
401
+  (8.1ms) CREATE VIEW required AS SELECT 1 as id
402
+  (6.6ms) CREATE VIEW hello_world AS --!require required
403
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
404
+  (2.0ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
405
+ BEGIN
406
+ RETURN x + y;
407
+ END;
408
+ $$ LANGUAGE plpgsql;
409
+  (0.6ms) DROP VIEW required
410
+ PG::DependentObjectsStillExist: ERROR: cannot drop view required because other objects depend on it
411
+ DETAIL: view hello_world depends on view required
412
+ HINT: Use DROP ... CASCADE to drop the dependent objects too.
413
+ : DROP VIEW required
414
+  (0.9ms) DROP VIEW hello_world
415
+ ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations".* FROM "schema_migrations"
416
+  (0.3ms) CREATE VIEW required AS SELECT 1 as id
417
+ PG::DuplicateTable: ERROR: relation "required" already exists
418
+ : CREATE VIEW required AS SELECT 1 as id
419
+  (2.1ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
420
+ BEGIN
421
+ RETURN x + y;
422
+ END;
423
+ $$ LANGUAGE plpgsql;
424
+  (0.9ms) DROP VIEW required
425
+  (0.3ms) DROP VIEW hello_world
426
+ PG::UndefinedTable: ERROR: view "hello_world" does not exist
427
+ : DROP VIEW hello_world
428
+  (2.0ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
429
+ BEGIN
430
+ RETURN x + y;
431
+ END;
432
+ $$ LANGUAGE plpgsql;
433
+  (0.3ms) DROP VIEW required
434
+ PG::UndefinedTable: ERROR: view "required" does not exist
435
+ : DROP VIEW required
436
+  (2.1ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
437
+ BEGIN
438
+ RETURN x + y;
439
+ END;
440
+ $$ LANGUAGE plpgsql;
441
+  (0.3ms) DROP VIEW required
442
+ PG::UndefinedTable: ERROR: view "required" does not exist
443
+ : DROP VIEW required
444
+  (2.0ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
445
+ BEGIN
446
+ RETURN x + y;
447
+ END;
448
+ $$ LANGUAGE plpgsql;
449
+  (0.3ms) DROP VIEW required
450
+ PG::UndefinedTable: ERROR: view "required" does not exist
451
+ : DROP VIEW required
452
+  (0.2ms) DROP VIEW hello_world
453
+ PG::UndefinedTable: ERROR: view "hello_world" does not exist
454
+ : DROP VIEW hello_world
455
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
456
+  (6.7ms) CREATE VIEW required AS SELECT 1 as id
457
+  (6.6ms) CREATE VIEW hello_world AS --!require required
458
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
459
+  (2.3ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
460
+ BEGIN
461
+ RETURN x + y;
462
+ END;
463
+ $$ LANGUAGE plpgsql;
464
+  (0.7ms) DROP VIEW required
465
+ PG::DependentObjectsStillExist: ERROR: cannot drop view required because other objects depend on it
466
+ DETAIL: view hello_world depends on view required
467
+ HINT: Use DROP ... CASCADE to drop the dependent objects too.
468
+ : DROP VIEW required
469
+  (3.0ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
470
+ BEGIN
471
+ RETURN x + y;
472
+ END;
473
+ $$ LANGUAGE plpgsql;
474
+  (1.4ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
475
+ BEGIN
476
+ RETURN x + y;
477
+ END;
478
+ $$ LANGUAGE plpgsql;
479
+  (1.2ms) DROP VIEW hello_world
480
+  (0.6ms) DROP VIEW required
481
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
482
+  (12.4ms) CREATE VIEW required AS SELECT 1 as id
483
+  (12.6ms) CREATE VIEW hello_world AS --!require required
484
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
metadata CHANGED
@@ -1,19 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_db_views
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yacine Petitprez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-05 00:00:00.000000000 Z
11
+ date: 2015-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
17
20
  - - ">="
18
21
  - !ruby/object:Gem::Version
19
22
  version: '4.0'
@@ -21,6 +24,9 @@ dependencies:
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4'
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
26
32
  version: '4.0'
@@ -29,6 +35,9 @@ dependencies:
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - - ">="
32
41
  - !ruby/object:Gem::Version
33
42
  version: 1.2.3
34
43
  type: :runtime
@@ -36,6 +45,9 @@ dependencies:
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
47
  - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.2'
50
+ - - ">="
39
51
  - !ruby/object:Gem::Version
40
52
  version: 1.2.3
41
53
  - !ruby/object:Gem::Dependency
@@ -52,7 +64,21 @@ dependencies:
52
64
  - - ">="
53
65
  - !ruby/object:Gem::Version
54
66
  version: '0'
55
- description: ''
67
+ - !ruby/object:Gem::Dependency
68
+ name: pg
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ description: Provide tools to create and manage database view through Rails project.
56
82
  email:
57
83
  - anykeyh@gmail.com
58
84
  executables: []
@@ -62,9 +88,13 @@ files:
62
88
  - LICENSE
63
89
  - Rakefile
64
90
  - lib/rails_db_views.rb
65
- - lib/rails_db_views/db_views_creator.rb
91
+ - lib/rails_db_views/configuration.rb
92
+ - lib/rails_db_views/database_symbol.rb
93
+ - lib/rails_db_views/factory.rb
94
+ - lib/rails_db_views/function.rb
66
95
  - lib/rails_db_views/railtie.rb
67
96
  - lib/rails_db_views/version.rb
97
+ - lib/rails_db_views/view.rb
68
98
  - lib/tasks/rails_db_views_tasks.rake
69
99
  - test/dummy/README.rdoc
70
100
  - test/dummy/Rakefile
@@ -94,7 +124,9 @@ files:
94
124
  - test/dummy/config/locales/en.yml
95
125
  - test/dummy/config/routes.rb
96
126
  - test/dummy/db/development.sqlite3
127
+ - test/dummy/db/functions/add.sql
97
128
  - test/dummy/db/schema.rb
129
+ - test/dummy/db/test.sqlite3
98
130
  - test/dummy/db/views/hello_world.sql
99
131
  - test/dummy/db/views/required.sql
100
132
  - test/dummy/log/development.log
@@ -124,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
156
  version: '0'
125
157
  requirements: []
126
158
  rubyforge_project:
127
- rubygems_version: 2.2.2
159
+ rubygems_version: 2.4.8
128
160
  signing_key:
129
161
  specification_version: 4
130
162
  summary: Provide tools to create and manage database view through Rails project.
@@ -155,7 +187,9 @@ test_files:
155
187
  - test/dummy/config/routes.rb
156
188
  - test/dummy/config.ru
157
189
  - test/dummy/db/development.sqlite3
190
+ - test/dummy/db/functions/add.sql
158
191
  - test/dummy/db/schema.rb
192
+ - test/dummy/db/test.sqlite3
159
193
  - test/dummy/db/views/hello_world.sql
160
194
  - test/dummy/db/views/required.sql
161
195
  - test/dummy/log/development.log
@@ -1,104 +0,0 @@
1
- class RailsDbViews::DbViewsCreator
2
- attr_reader :views
3
-
4
- def initialize
5
- @views = {}
6
- end
7
-
8
- def register_files files
9
- files.each do |file|
10
- view_name = File.basename(file, File.extname(file))
11
-
12
- content = File.read(file)
13
- content_lines = content.split("\n")
14
-
15
- # Reject the commented lines from the file
16
- sql_content = content_lines.reject{ |x| x.strip =~ /^--/ || x.strip =~ /^#/ }.join("\n")
17
-
18
- file_obj = { path: file, sql_content: sql_content, status: :none, requires: [] }
19
-
20
- # Detect directives in commentary
21
- directives = content_lines.select{ |x| x.strip =~ /^--/ || x.strip =~ /^#/ }.map(&:strip).map{ |x|
22
- x =~ /^--/ ? x[2..-1] : x[1..-1]
23
- }.select{|x| x =~ /^!/ }
24
-
25
- directives.each do |directive|
26
- if directive =~ /^!require / #Currently only the require directive exists.
27
- file_obj[:requires] += directive.split(" ")[1..-1]
28
- end
29
- end
30
-
31
- if @views[view_name]
32
- puts "WARNING: #{view_name} already defined in `#{@views[view_name][:path]}`. Will be ignored and we use `#{file_obj[:path]}`..."
33
- end
34
-
35
- @views[view_name] = file_obj
36
- end
37
- end
38
-
39
- def drop_views
40
- reset_views_status!
41
- @views.each{ |name, view|
42
- drop_view name, view
43
- }
44
- end
45
-
46
- def create_views
47
- reset_views_status!
48
- @views.each{ |name, view|
49
- create_view name, view
50
- }
51
- end
52
-
53
- private
54
- def reset_views_status!
55
- @views.each{ |name, view|
56
- view[:status] = :none
57
- }
58
- end
59
-
60
-
61
- def drop_view name, view
62
- return if view[:status] == :loaded
63
-
64
- if view[:status] == :inprogress
65
- raise "Error: Circular file reference! (view #{name})"
66
- end
67
-
68
- view[:requires].each do |other_view|
69
- drop_view other_view, @views[other_view]
70
- end
71
-
72
- sql = "DROP VIEW #{name}"
73
- begin
74
- ActiveRecord::Base.connection.execute(sql)
75
- puts "DROP VIEW #{name}... OK"
76
- rescue
77
- puts "WARNING: DROP VIEW #{name}... ERROR"
78
- end
79
-
80
- view[:status] = :loaded
81
- end
82
-
83
- def create_view name, view
84
- # View already loaded.
85
- return if view[:status] == :loaded
86
-
87
- if view[:status] == :inprogress
88
- raise "Error: Circular file reference! (view #{name})"
89
- end
90
-
91
- view[:status] = :inprogress
92
-
93
- view[:requires].each do |other_view|
94
- create_view other_view, @views[other_view]
95
- end
96
-
97
- sql = "CREATE VIEW #{name} AS #{view[:sql_content]}"
98
- ActiveRecord::Base.connection.execute(sql)
99
- puts "CREATE VIEW #{name} AS... OK"
100
-
101
- view[:status] = :loaded
102
- end
103
-
104
- end