sql_view 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba42c85d8dfc2f460a9996e6283dd998f4acdd4d92c953654d52868df30cab54
4
- data.tar.gz: d27a1d496c7f93ef63ff62820dd868532ac87eb4d10df541ed482e4febac71ac
3
+ metadata.gz: 025552fef24e528e14b29c5e5fde2f011e329a2aee4169d831d602aae26ca107
4
+ data.tar.gz: f0de63bac86f0a4ad119b972bb9357325c6556ff737c6be245514a4002021915
5
5
  SHA512:
6
- metadata.gz: 289169432b76935e91b885225281402af12779fec09d94360ea1e17ec947b4a3dec92686e8fe058a15098c6f02da140d5bc64f17649fbd1f7e5810b2d61dfe65
7
- data.tar.gz: 51bfe3fda64423d9041a0ea62c894f46c4a52a00d42eb9c8c1c4f29d59dede513f26876b101b96aa998bbbb9dda8bcee7dd8878b4a372bba125ea627abe1bf10
6
+ metadata.gz: 4213c7dc5a9c882664f9214cec6e148313221d0a799484517b3db45a288d9516094c70738c89030010ffa9a607a561e8339be9099741df291c9540bd13067247
7
+ data.tar.gz: e7177d5289085a4be25f4ff9d4bdecdab2104c1816281a7abeecdee5418be1b6aa2e18a05e0087f140370335b7fd146bf50d5017e2dcaa3c84722c3fc1ac1e46
data/README.md CHANGED
@@ -1,11 +1,98 @@
1
- # SqlView
2
- Short description and motivation.
1
+ # Rails + SQL View
2
+
3
+ [![Listed on OpenSource-Heroes.com](https://opensource-heroes.com/badge-v1.svg)](https://opensource-heroes.com/r/igorkasyanchuk/sql_view)
4
+
5
+ ## The easist way to add and work with SQL view in your app.
6
+
7
+ If you are lazy and don't like to write SQL to create SQL view but you know AR use your skills to create views.
8
+
9
+ Production-ready.
10
+
11
+ ![Demo](docs/sql_view.gif?raw=true "Demo")
3
12
 
4
13
  ## Usage
5
- How to use my plugin.
14
+
15
+ The most simple way to add a view is to call a generator (examples below):
16
+
17
+ ```bash
18
+ rails g sql_view:view DeletedProjects 'Project.only_deleted'
19
+ rails g sql_view:view ActiveUsers 'User.confirmed.where(active: true)' --materialized
20
+ ```
21
+
22
+ Depending on whether you need a materialized view or not add `--materialized` flag (later you can change in "view" class). Materialized views works in Postgres.
23
+
24
+ Generator will create a file similar to:
25
+
26
+ ```ruby
27
+ class ActiveUserView < SQLView::Model
28
+ materialized
29
+
30
+ schema -> { User.where(age: 18..60) }
31
+
32
+ extend_model_with do
33
+ # sample how you can extend it, similar to regular AR model
34
+ #
35
+ # include SomeConcern
36
+ #
37
+ # belongs_to :user
38
+ # has_many :posts
39
+ #
40
+ # scope :ordered, -> { order(:created_at) }
41
+ # scope :by_role, ->(role) { where(role: role) }
42
+ end
43
+ end
44
+ ```
45
+
46
+ or if you want to use SQL to create a regular view:
47
+
48
+
49
+ ```ruby
50
+ class ActiveUserView < SQLView::Model
51
+ schema -> { "SELECT * FROM users WHERE active = TRUE" }
52
+ end
53
+ ```
54
+
55
+ or the same but materialized:
56
+
57
+ ```ruby
58
+ class ActiveUserView < SQLView::Model
59
+ materialized
60
+ schema -> { "SELECT * FROM users WHERE active = TRUE" }
61
+ end
62
+ ```
63
+
64
+ Later with view you can work same way as with any model(ActiveRecord class). For example:
65
+
66
+ ```ruby
67
+ ActiveUserView.model.count
68
+ # or
69
+ ActiveUserView.count
70
+ # ----
71
+ ActiveUserView.find(42)
72
+ # you can apply scopes, relations, methods, BUT add them in extend_model_with block
73
+
74
+ ActiveUserView.model.by_role("admin").count
75
+ ActiveUserView.where(role: "admin").exists?
76
+ ActiveUserView.model.includes(:profile)
77
+ ```
78
+
79
+ If you need to refresh materialized view - `ActiveUserView.sql_view.refresh` (if you need to do it concerrently - `.refresh(concurrently: false)`.
80
+
81
+ It can also be used with your other models:
82
+
83
+ ```ruby
84
+ class Account < ApplicationRecord
85
+ has_many :users
86
+
87
+ has_one :account_stat_view, class_name: AccountStatViewView.model.to_s, foreign_key: :account_id
88
+ has_many :active_users, join_table: :active_users_views, class_name: ActiveUserView.model.to_s, foreign_key: :account_id
89
+ end
90
+ ```
91
+
92
+
93
+ More examples in this file: `./test/sql_view_test.rb`
6
94
 
7
95
  ## Installation
8
- Add this line to your application's Gemfile:
9
96
 
10
97
  ```ruby
11
98
  gem "sql_view"
@@ -16,17 +103,67 @@ And then execute:
16
103
  $ bundle
17
104
  ```
18
105
 
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install sql_view
106
+ And use generator. Or you can connect it to existing view with `view_name=`:
107
+
108
+ ```ruby
109
+ class OldUserView < SqlView::Model
110
+ self.view_name = "all_old_users"
111
+
112
+ materialized
113
+
114
+ schema -> { User.where("age > 18") }
115
+
116
+ extend_model_with do
117
+ scope :ordered, -> { order(:id) }
118
+
119
+ def test_instance_method
120
+ 42
121
+ end
122
+ end
123
+ end
22
124
  ```
23
125
 
126
+ ## Materialized view + concurrent update
127
+
128
+ 1. add index
129
+
130
+ ```ruby
131
+ add_index SomeView.view_name, :user_id, unique: true
132
+ ```
133
+
134
+ 2. refresh with parameter
135
+
136
+ ```ruby
137
+ SomeView.sql_view.refresh(concurrently: true)
138
+ ```
139
+
140
+ 3. profit :)
141
+
142
+ ## TODO
143
+
144
+ - CI with different versions of Rails/Ruby
145
+ - make unit tests works with `rake test`
146
+ - `cascade` option
147
+ - move classes to own files
148
+ - code coverage
149
+ - verify how it works with other DB's
150
+ - check if schema was changed on migrate or schema dump?
151
+
24
152
  ## Testing
25
153
 
26
154
  `ruby ./test/sql_view_test.rb` (because somehow `rake test` not works, not critical for now)
27
155
 
28
156
  ## Contributing
29
- Contribution directions go here.
157
+
158
+ You are welcome to contribute.
159
+
160
+ ## Credits
161
+
162
+ I know about and actually using `gem scenic`, which is very nice and I tool some examples from it how to dump view into schema.rb but this gem was created to simplify life and reduce amount of time needed to write SQL to create a sql view.
30
163
 
31
164
  ## License
165
+
32
166
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
167
+
168
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
169
+ />](https://www.railsjazz.com/?utm_source=github&utm_medium=bottom&utm_campaign=sql_view)
@@ -8,20 +8,21 @@ module SqlView
8
8
  class DBView < OpenStruct
9
9
  def to_schema
10
10
  <<-DEFINITION
11
- create_sql_view "#{self.viewname}", sql: <<-\SQL
12
- CREATE #{materialized_or_not} VIEW "#{self.viewname}" AS
11
+ create_sql_view "#{viewname}", sql: <<-\SQL
12
+ CREATE#{materialized_or_not}VIEW "#{viewname}" AS
13
13
  #{escaped_definition.indent(2)}
14
14
  SQL\n
15
15
  DEFINITION
16
16
  end
17
17
 
18
18
  private
19
+
19
20
  def materialized?
20
- self.kind == "m"
21
+ kind == "m"
21
22
  end
22
23
 
23
24
  def materialized_or_not
24
- materialized? ? " MATERIALIZED " : nil
25
+ materialized? ? " MATERIALIZED " : " "
25
26
  end
26
27
 
27
28
  def escaped_definition
@@ -35,40 +36,18 @@ module SqlView
35
36
  end
36
37
 
37
38
  def views(stream)
38
- if dumpable_views_in_database.any?
39
- stream.puts
40
- end
39
+ stream.puts if sql_views.any?
41
40
 
42
- dumpable_views_in_database.each do |viewname|
43
- next if already_indexed?(viewname)
44
- view = DBView.new(get_view_info(viewname))
41
+ sql_views.each do |view|
45
42
  stream.puts(view.to_schema)
46
- indexes(viewname, stream)
43
+ indexes(view.viewname, stream)
47
44
  end
48
45
  end
49
46
 
50
47
  private
51
48
 
52
- # make sure view was added one time, because somehow was adding views two times
53
- def already_indexed?(viewname)
54
- @already_indexed ||= []
55
- return true if @already_indexed.include?(viewname)
56
- @already_indexed << viewname
57
- false
58
- end
59
-
60
- def dumpable_views_in_database
61
- @dumpable_views_in_database ||= ActiveRecord::Base.connection.views.reject do |viewname|
62
- ignored?(viewname)
63
- end
64
- end
65
-
66
- def get_view_info(viewname)
67
- views_schema.detect{|e| e['viewname'] == viewname}
68
- end
69
-
70
- def views_schema
71
- @views_schema ||= ActiveRecord::Base.connection.execute(<<-SQL)
49
+ def sql_views
50
+ @sql_views ||= ActiveRecord::Base.connection.execute(<<-SQL)
72
51
  SELECT
73
52
  c.relname as viewname,
74
53
  pg_get_viewdef(c.oid) AS definition,
@@ -79,10 +58,11 @@ module SqlView
79
58
  WHERE
80
59
  c.relkind IN ('m', 'v')
81
60
  AND c.relname NOT IN (SELECT extname FROM pg_extension)
61
+ AND c.relname != 'pg_stat_statements_info'
82
62
  AND n.nspname = ANY (current_schemas(false))
83
63
  ORDER BY c.oid
84
64
  SQL
85
- .to_a
65
+ .to_a.map(&DBView.method(:new)).reject { |view| ignored?(view.viewname) }
86
66
  end
87
67
 
88
68
  unless ActiveRecord::SchemaDumper.private_instance_methods(false).include?(:ignored?)
@@ -101,4 +81,4 @@ module SqlView
101
81
  end
102
82
  end
103
83
 
104
- SQLView = SqlView
84
+ SQLView = SqlView
@@ -1,3 +1,3 @@
1
1
  module SqlView
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  end
data/lib/sql_view.rb CHANGED
@@ -68,7 +68,7 @@ module SqlView
68
68
  sql = <<-SQL
69
69
  REFRESH#{materialized_or_not}VIEW#{concurrently_or_not}#{parent.view_name};
70
70
  SQL
71
- execute(sql)
71
+ execute(sql, log: false)
72
72
  end
73
73
 
74
74
  def up
@@ -88,8 +88,8 @@ module SqlView
88
88
  execute(sql)
89
89
  end
90
90
 
91
- def execute(sql)
92
- SqlView.log sql
91
+ def execute(sql, log: true)
92
+ SqlView.log(sql) if log
93
93
  ActiveRecord::Base.connection.execute sql#.wp
94
94
  end
95
95
 
@@ -103,6 +103,7 @@ module SqlView
103
103
 
104
104
  class ClassBuilder
105
105
  def ClassBuilder.create_model(parent)
106
+ class_name = "#{parent}Model"
106
107
  klass = Class.new(ActiveRecord::Base) do
107
108
  def self.model_name
108
109
  ActiveModel::Name.new(self, nil, parent.view_name)
@@ -120,10 +121,11 @@ module SqlView
120
121
  # because of the error undefined scan for nil class
121
122
  klass.class_eval %Q{
122
123
  def self.name
123
- "#{parent.class}"
124
+ "#{class_name}"
124
125
  end
125
126
  }
126
- klass
127
+ Object.const_set(class_name, klass) unless const_defined?(class_name)
128
+ Object.const_get(class_name)
127
129
  end
128
130
  end
129
131
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_view
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-14 00:00:00.000000000 Z
11
+ date: 2023-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -89,7 +89,7 @@ licenses:
89
89
  - MIT
90
90
  metadata:
91
91
  homepage_uri: https://github.com/igorkasyanchuk/sql_view
92
- post_install_message:
92
+ post_install_message:
93
93
  rdoc_options: []
94
94
  require_paths:
95
95
  - lib
@@ -104,8 +104,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  requirements: []
107
- rubygems_version: 3.3.3
108
- signing_key:
107
+ rubygems_version: 3.4.13
108
+ signing_key:
109
109
  specification_version: 4
110
110
  summary: Simple way to create and interact with your SQL views using ActiveRecord.
111
111
  test_files: []