sql_view 0.0.3 → 0.0.5

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
  SHA256:
3
- metadata.gz: 3a7e04a9a62b624adce19a6462f76ddea7548e82aead8a8e639de633f4fa7279
4
- data.tar.gz: a19ed68c58a457aac9aa4e65e38f247ed9fd0176fc9eb4aa8bf5b1a42722f3dd
3
+ metadata.gz: 453bfcdc70b0ca2eba4be95d6eca062e840e9e3f4950f8fca7471421216d1de9
4
+ data.tar.gz: 14d65cba7bbcc28dc6741622abef7b91a8863ed8e738b35de373c1758e21f045
5
5
  SHA512:
6
- metadata.gz: eedc2c396f6d43e3a954889a4f66b6416b71ad2d98fd3bb44e50599069a6791998e873a22ad88f6c80f3add2f70abd3a7d19df86702a745a1e1494836cc54892
7
- data.tar.gz: 6cd70bb813ce62ea92d7754601fb57df410b0bb1946bd8c251085d20ce18d2b5125f853bd9a6b7f6bcb538175979b923d49573611a855816c563e5160a92e9c4
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)
@@ -11,7 +11,7 @@ module SqlView
11
11
 
12
12
  def create_everything
13
13
  create_file "app/sql_views/#{file_name}_view.rb", <<-FILE
14
- class #{class_name}View < SqlView::Model
14
+ class #{class_name}View < SQLView::Model
15
15
  #{top_code}
16
16
 
17
17
  schema ->#{schema_code}
@@ -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?)
@@ -100,3 +80,5 @@ module SqlView
100
80
  end
101
81
  end
102
82
  end
83
+
84
+ SQLView = SqlView
@@ -1,3 +1,3 @@
1
1
  module SqlView
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/sql_view.rb CHANGED
@@ -7,6 +7,7 @@ require "sql_view/railtie"
7
7
  #
8
8
  #
9
9
  # TODO for now in a single file
10
+ # move to separate files
10
11
  #
11
12
  #
12
13
 
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.3
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-13 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
@@ -84,13 +84,12 @@ files:
84
84
  - lib/sql_view/schema_dumper.rb
85
85
  - lib/sql_view/statements.rb
86
86
  - lib/sql_view/version.rb
87
- - lib/tasks/sql_view_tasks.rake
88
87
  homepage: https://github.com/igorkasyanchuk/sql_view
89
88
  licenses:
90
89
  - MIT
91
90
  metadata:
92
91
  homepage_uri: https://github.com/igorkasyanchuk/sql_view
93
- post_install_message:
92
+ post_install_message:
94
93
  rdoc_options: []
95
94
  require_paths:
96
95
  - lib
@@ -105,8 +104,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
104
  - !ruby/object:Gem::Version
106
105
  version: '0'
107
106
  requirements: []
108
- rubygems_version: 3.3.3
109
- signing_key:
107
+ rubygems_version: 3.4.13
108
+ signing_key:
110
109
  specification_version: 4
111
110
  summary: Simple way to create and interact with your SQL views using ActiveRecord.
112
111
  test_files: []
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :sql_view do
3
- # # Task goes here
4
- # end