sql_view 0.0.4 → 0.0.5

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: 453bfcdc70b0ca2eba4be95d6eca062e840e9e3f4950f8fca7471421216d1de9
4
+ data.tar.gz: 14d65cba7bbcc28dc6741622abef7b91a8863ed8e738b35de373c1758e21f045
5
5
  SHA512:
6
- metadata.gz: 289169432b76935e91b885225281402af12779fec09d94360ea1e17ec947b4a3dec92686e8fe058a15098c6f02da140d5bc64f17649fbd1f7e5810b2d61dfe65
7
- data.tar.gz: 51bfe3fda64423d9041a0ea62c894f46c4a52a00d42eb9c8c1c4f29d59dede513f26876b101b96aa998bbbb9dda8bcee7dd8878b4a372bba125ea627abe1bf10
6
+ metadata.gz: 99a4e50942b3322d2a86e04b5c5b56e060718788beee10af35ca79de9331bf882d16f0311c9908d97bd8c5d88926e29fd1360fcaf30c90d5d3fd17b77813a238
7
+ data.tar.gz: d502bab08d5c44d183f6c741ed2d12c53cd5b27962c9a3eca384c66e213a0d1c5bdbce058184a13fdaf3495fca65f13f7e469a0a2fc59da861f4e8cffc18335d
data/README.md CHANGED
@@ -1,11 +1,86 @@
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
+ More examples in this file: `./test/sql_view_test.rb`
6
82
 
7
83
  ## Installation
8
- Add this line to your application's Gemfile:
9
84
 
10
85
  ```ruby
11
86
  gem "sql_view"
@@ -16,17 +91,67 @@ And then execute:
16
91
  $ bundle
17
92
  ```
18
93
 
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install sql_view
94
+ And use generator. Or you can connect it to existing view with `view_name=`:
95
+
96
+ ```ruby
97
+ class OldUserView < SqlView::Model
98
+ self.view_name = "all_old_users"
99
+
100
+ materialized
101
+
102
+ schema -> { User.where("age > 18") }
103
+
104
+ extend_model_with do
105
+ scope :ordered, -> { order(:id) }
106
+
107
+ def test_instance_method
108
+ 42
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
114
+ ## Materialized view + concurrent update
115
+
116
+ 1. add index
117
+
118
+ ```ruby
119
+ add_index SomeView.view_name, :user_id, unique: true
22
120
  ```
23
121
 
122
+ 2. refresh with parameter
123
+
124
+ ```ruby
125
+ SomeView.sql_view.refresh(concurrently: true)
126
+ ```
127
+
128
+ 3. profit :)
129
+
130
+ ## TODO
131
+
132
+ - CI with different versions of Rails/Ruby
133
+ - make unit tests works with `rake test`
134
+ - `cascade` option
135
+ - move classes to own files
136
+ - code coverage
137
+ - verify how it works with other DB's
138
+ - check if schema was changed on migrate or schema dump?
139
+
24
140
  ## Testing
25
141
 
26
142
  `ruby ./test/sql_view_test.rb` (because somehow `rake test` not works, not critical for now)
27
143
 
28
144
  ## Contributing
29
- Contribution directions go here.
145
+
146
+ You are welcome to contribute.
147
+
148
+ ## Credits
149
+
150
+ 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
151
 
31
152
  ## License
153
+
32
154
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
155
+
156
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
157
+ />](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.5"
3
3
  end
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.5
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-07 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: []