smriti 0.5.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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +168 -0
  4. data/Rakefile +15 -0
  5. data/app/assets/images/smriti/android-chrome-192x192.png +0 -0
  6. data/app/assets/images/smriti/android-chrome-512x512.png +0 -0
  7. data/app/assets/images/smriti/apple-touch-icon.png +0 -0
  8. data/app/assets/images/smriti/favicon-16x16.png +0 -0
  9. data/app/assets/images/smriti/favicon-32x32.png +0 -0
  10. data/app/assets/images/smriti/favicon-48x48.png +0 -0
  11. data/app/assets/images/smriti/favicon.ico +0 -0
  12. data/app/assets/images/smriti/favicon.svg +18 -0
  13. data/app/assets/images/smriti/logo.svg +18 -0
  14. data/app/assets/images/smriti/mask-icon.svg +5 -0
  15. data/app/assets/stylesheets/smriti/application.css +1040 -0
  16. data/app/controllers/smriti/admin/application_controller.rb +135 -0
  17. data/app/controllers/smriti/admin/dashboard_controller.rb +32 -0
  18. data/app/controllers/smriti/admin/mat_view_definitions_controller.rb +372 -0
  19. data/app/controllers/smriti/admin/mat_view_runs_controller.rb +185 -0
  20. data/app/controllers/smriti/admin/preferences_controller.rb +91 -0
  21. data/app/helpers/smriti/admin/datatable_helper.rb +249 -0
  22. data/app/helpers/smriti/admin/localized_digit_helper.rb +70 -0
  23. data/app/helpers/smriti/admin/ui_helper.rb +539 -0
  24. data/app/javascript/smriti/application.js +8 -0
  25. data/app/javascript/smriti/controllers/application.js +10 -0
  26. data/app/javascript/smriti/controllers/body_setup_controller.js +120 -0
  27. data/app/javascript/smriti/controllers/datatable_controller.js +351 -0
  28. data/app/javascript/smriti/controllers/details_controller.js +200 -0
  29. data/app/javascript/smriti/controllers/drawer_controller.js +470 -0
  30. data/app/javascript/smriti/controllers/flash_controller.js +112 -0
  31. data/app/javascript/smriti/controllers/index.js +10 -0
  32. data/app/javascript/smriti/controllers/mv_confirm_controller.js +435 -0
  33. data/app/javascript/smriti/controllers/tabs_controller.js +184 -0
  34. data/app/javascript/smriti/controllers/tooltip_controller.js +525 -0
  35. data/app/javascript/smriti/controllers/turbo_frame_lifecycle_controller.js +342 -0
  36. data/app/jobs/smriti/application_job.rb +144 -0
  37. data/app/jobs/smriti/create_view_job.rb +87 -0
  38. data/app/jobs/smriti/delete_view_job.rb +89 -0
  39. data/app/jobs/smriti/refresh_view_job.rb +94 -0
  40. data/app/models/concerns/smriti_i18n.rb +139 -0
  41. data/app/models/concerns/smriti_paginate.rb +70 -0
  42. data/app/models/concerns/smriti_query_helper.rb +36 -0
  43. data/app/models/smriti/application_record.rb +39 -0
  44. data/app/models/smriti/mat_view_definition.rb +254 -0
  45. data/app/models/smriti/mat_view_run.rb +275 -0
  46. data/app/views/layouts/smriti/_footer.html.erb +47 -0
  47. data/app/views/layouts/smriti/_header.html.erb +25 -0
  48. data/app/views/layouts/smriti/admin.html.erb +47 -0
  49. data/app/views/layouts/smriti/turbo_frame.html.erb +3 -0
  50. data/app/views/smriti/admin/dashboard/index.html.erb +38 -0
  51. data/app/views/smriti/admin/mat_view_definitions/_definition_actions.html.erb +94 -0
  52. data/app/views/smriti/admin/mat_view_definitions/_dt-index-empty-row.html.erb +11 -0
  53. data/app/views/smriti/admin/mat_view_definitions/_dt-index-row.html.erb +27 -0
  54. data/app/views/smriti/admin/mat_view_definitions/empty.html.erb +1 -0
  55. data/app/views/smriti/admin/mat_view_definitions/form.html.erb +79 -0
  56. data/app/views/smriti/admin/mat_view_definitions/index.html.erb +10 -0
  57. data/app/views/smriti/admin/mat_view_definitions/show.html.erb +40 -0
  58. data/app/views/smriti/admin/mat_view_runs/_dt-index-empty-row.html.erb +11 -0
  59. data/app/views/smriti/admin/mat_view_runs/_dt-index-row.html.erb +41 -0
  60. data/app/views/smriti/admin/mat_view_runs/index.html.erb +1 -0
  61. data/app/views/smriti/admin/mat_view_runs/show.html.erb +64 -0
  62. data/app/views/smriti/admin/preferences/show.html.erb +49 -0
  63. data/app/views/smriti/admin/ui/_card.html.erb +15 -0
  64. data/app/views/smriti/admin/ui/_datatable.html.erb +34 -0
  65. data/app/views/smriti/admin/ui/_datatable_filters.html.erb +45 -0
  66. data/app/views/smriti/admin/ui/_datatable_tbody.html.erb +11 -0
  67. data/app/views/smriti/admin/ui/_datatable_tfoot.html.erb +70 -0
  68. data/app/views/smriti/admin/ui/_datatable_thead.html.erb +105 -0
  69. data/app/views/smriti/admin/ui/_details.html.erb +10 -0
  70. data/app/views/smriti/admin/ui/_flash.html.erb +6 -0
  71. data/app/views/smriti/admin/ui/_table.html.erb +8 -0
  72. data/config/importmap.rb +9 -0
  73. data/config/locales/ar.yml +223 -0
  74. data/config/locales/de.yml +230 -0
  75. data/config/locales/en-AU-ocker.yml +223 -0
  76. data/config/locales/en-AU.yml +202 -0
  77. data/config/locales/en-BORK.yml +225 -0
  78. data/config/locales/en-CA.yml +223 -0
  79. data/config/locales/en-GB.yml +223 -0
  80. data/config/locales/en-LOL.yml +219 -0
  81. data/config/locales/en-SCOT.yml +223 -0
  82. data/config/locales/en-SHAKESPEARE.yml +225 -0
  83. data/config/locales/en-US-pirate.yml +222 -0
  84. data/config/locales/en-US.yml +225 -0
  85. data/config/locales/en-YODA.yml +221 -0
  86. data/config/locales/en.yml +223 -0
  87. data/config/locales/es.yml +226 -0
  88. data/config/locales/fa.yml +223 -0
  89. data/config/locales/fr-CA.yml +227 -0
  90. data/config/locales/fr.yml +227 -0
  91. data/config/locales/he.yml +218 -0
  92. data/config/locales/hi.yml +223 -0
  93. data/config/locales/it.yml +225 -0
  94. data/config/locales/ja-JP.yml +215 -0
  95. data/config/locales/pt.yml +225 -0
  96. data/config/locales/ru.yml +228 -0
  97. data/config/locales/ur.yml +225 -0
  98. data/config/locales/zh-CN.yml +214 -0
  99. data/config/locales/zh-TW.yml +214 -0
  100. data/config/routes.rb +36 -0
  101. data/lib/ext/exception.rb +20 -0
  102. data/lib/generators/smriti/install/install_generator.rb +86 -0
  103. data/lib/generators/smriti/install/templates/create_mat_view_definitions.rb +29 -0
  104. data/lib/generators/smriti/install/templates/create_mat_view_runs.rb +32 -0
  105. data/lib/generators/smriti/install/templates/smriti_initializer.rb +23 -0
  106. data/lib/smriti/admin/auth_bridge.rb +93 -0
  107. data/lib/smriti/admin/default_auth.rb +62 -0
  108. data/lib/smriti/configuration.rb +58 -0
  109. data/lib/smriti/engine.rb +82 -0
  110. data/lib/smriti/helpers/ui_test_ids.rb +49 -0
  111. data/lib/smriti/jobs/adapter.rb +81 -0
  112. data/lib/smriti/service_response.rb +75 -0
  113. data/lib/smriti/services/base_service.rb +471 -0
  114. data/lib/smriti/services/check_matview_exists.rb +76 -0
  115. data/lib/smriti/services/concurrent_refresh.rb +94 -0
  116. data/lib/smriti/services/create_view.rb +173 -0
  117. data/lib/smriti/services/delete_view.rb +111 -0
  118. data/lib/smriti/services/regular_refresh.rb +90 -0
  119. data/lib/smriti/services/swap_refresh.rb +181 -0
  120. data/lib/smriti/version.rb +21 -0
  121. data/lib/smriti.rb +64 -0
  122. data/lib/tasks/helpers.rb +185 -0
  123. data/lib/tasks/smriti_tasks.rake +151 -0
  124. metadata +206 -0
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Smriti
6
+ module Tasks
7
+ ##
8
+ # Helpers module provides utility methods for Smriti Rake tasks.
9
+ #
10
+ # These helpers support:
11
+ # - Database connections
12
+ # - Logging
13
+ # - Parsing boolean/flag-like arguments
14
+ # - Confirmation prompts
15
+ # - Enqueueing background jobs for create, refresh, and delete operations
16
+ # - Looking up materialised view definitions
17
+ #
18
+ # By extracting this logic, Rake tasks can remain clean and declarative.
19
+ module Helpers
20
+ module_function
21
+
22
+ # Returns the current database connection.
23
+ # @return [ActiveRecord::ConnectionAdapters::AbstractAdapter]
24
+ def mv_conn
25
+ ActiveRecord::Base.connection
26
+ end
27
+
28
+ # Returns the Rails logger.
29
+ # @return [Logger]
30
+ def logger
31
+ Rails.logger
32
+ end
33
+
34
+ # Check if a value is a "truthy" boolean-like string.
35
+ # Recognized: 1, true, yes, y, --yes
36
+ # @param value [String, Boolean, nil]
37
+ # @return [Boolean]
38
+ def booleanish_true?(value)
39
+ str = value.to_s.strip.downcase
40
+ %w[1 true yes y --yes].include?(str)
41
+ end
42
+
43
+ # Whether confirmation should be skipped (YES env or arg).
44
+ def skip_confirm?(arg)
45
+ booleanish_true?(arg || ENV.fetch('YES', nil))
46
+ end
47
+
48
+ # Parse whether force mode is enabled (FORCE env or arg).
49
+ def parse_force?(arg)
50
+ booleanish_true?(arg || ENV.fetch('FORCE', nil))
51
+ end
52
+
53
+ # Parse row count strategy from arg or ROW_COUNT_STRATEGY env.
54
+ # Defaults to :none if blank.
55
+ def parse_row_count_strategy(arg)
56
+ str = (arg || ENV.fetch('ROW_COUNT_STRATEGY', nil)).to_s.strip
57
+ return :none if str.empty?
58
+
59
+ str.to_sym
60
+ end
61
+
62
+ # Check if a materialised view exists in schema.
63
+ # @param rel [String] relation name
64
+ # @param schema [String] schema name
65
+ # @return [Boolean]
66
+ def matview_exists?(rel, schema: 'public')
67
+ mv_conn.select_value(<<~SQL).to_i.positive?
68
+ SELECT COUNT(*)
69
+ FROM pg_matviews
70
+ WHERE schemaname = #{mv_conn.quote(schema)} AND matviewname = #{mv_conn.quote(rel)}
71
+ SQL
72
+ end
73
+
74
+ # Find a MatViewDefinition by raw name (schema.rel or rel).
75
+ # Raises if none found or mismatch with DB presence.
76
+ #
77
+ # @param raw_name [String] schema-qualified or unqualified view name
78
+ # @return [Smriti::MatViewDefinition]
79
+ # @raise [RuntimeError] if no definition found or mismatch with DB
80
+ def find_definition_by_name!(raw_name)
81
+ raw_name_string = raw_name&.to_s&.strip
82
+ raise 'view_name is required' unless raw_name_string && !raw_name_string.empty?
83
+
84
+ schema, rel =
85
+ if raw_name_string.include?('.')
86
+ parts = raw_name_string.split('.', 2)
87
+ [parts[0], parts[1]]
88
+ else
89
+ [nil, raw_name_string]
90
+ end
91
+
92
+ defn = Smriti::MatViewDefinition.find_by(name: rel)
93
+ return defn if defn
94
+
95
+ if schema && matview_exists?(rel, schema: schema)
96
+ raise "Materialized view #{schema}.#{rel} exists, but no Smriti::MatViewDefinition record was found for name=#{rel.inspect}"
97
+ end
98
+
99
+ raise "No Smriti::MatViewDefinition found for #{raw_name.inspect}"
100
+ end
101
+
102
+ # Ask user to confirm a destructive action, unless skipped.
103
+ #
104
+ # @param message [String] confirmation message
105
+ # @param skip [Boolean] whether to skip confirmation
106
+ # @raise [RuntimeError] if user declines confirmation
107
+ # @return [void]
108
+ #
109
+ # If `skip` is true, logs the message and returns without prompting.
110
+ # Otherwise, prompts user for confirmation and raises if declined.
111
+ def confirm!(message, skip: false)
112
+ if skip
113
+ logger.info("[smriti] #{message} - confirmation skipped.")
114
+ return
115
+ end
116
+
117
+ logger.info("[smriti] #{message}")
118
+ $stdout.print('Proceed? [y/N]: ')
119
+ $stdout.flush
120
+ ans = $stdin.gets&.strip&.downcase
121
+ return if ans&.start_with?('y')
122
+
123
+ raise 'Aborted.'
124
+ end
125
+
126
+ # Enqueue a CreateView job for given definition.
127
+ #
128
+ # @param mat_view_definition_id [Integer] MatViewDefinition ID
129
+ # @param force [Boolean] whether to force creation
130
+ # @param row_count_strategy [Symbol] :estimated or :exact or :none
131
+ # @return [void]
132
+ def enqueue_create(mat_view_definition_id, force, row_count_strategy)
133
+ Smriti::Jobs::Adapter.enqueue(
134
+ Smriti::CreateViewJob,
135
+ queue: Smriti.configuration.job_queue || :default,
136
+ args: [mat_view_definition_id, force, row_count_strategy]
137
+ )
138
+ end
139
+
140
+ # Enqueue a RefreshView job for given definition.
141
+ #
142
+ # @param mat_view_definition_id [Integer] MatViewDefinition ID
143
+ # @param row_count_strategy [Symbol] :estimated or :exact
144
+ # @return [void]
145
+ #
146
+ # This method allows scheduling a refresh operation with the specified row count strategy.
147
+ # It uses the configured job adapter to enqueue the job.
148
+ def enqueue_refresh(mat_view_definition_id, row_count_strategy)
149
+ Smriti::Jobs::Adapter.enqueue(
150
+ Smriti::RefreshViewJob,
151
+ queue: Smriti.configuration.job_queue || :default,
152
+ args: [mat_view_definition_id, row_count_strategy]
153
+ )
154
+ end
155
+
156
+ # Parse cascade option (CASCADE env or arg).
157
+ #
158
+ # @param arg [String, Boolean, nil] argument or environment variable value
159
+ # @return [Boolean] true if cascade is enabled, false otherwise
160
+ #
161
+ # This method checks if the CASCADE option is set to true, allowing for cascading drops.
162
+ # It defaults to the value of the CASCADE environment variable if not provided.
163
+ def parse_cascade?(arg)
164
+ booleanish_true?(arg || ENV.fetch('CASCADE', nil))
165
+ end
166
+
167
+ # Enqueue a DeleteView job for given definition.
168
+ #
169
+ # @param mat_view_definition_id [Integer] MatViewDefinition ID
170
+ # @param cascade [Boolean] whether to drop with CASCADE
171
+ # @param row_count_strategy [Symbol] :estimated or :exact or :none
172
+ # @return [void]
173
+ #
174
+ # This method schedules a job to delete the materialised view, optionally with CASCADE.
175
+ # It uses the configured job adapter to enqueue the job.
176
+ def enqueue_delete(mat_view_definition_id, cascade, row_count_strategy)
177
+ Smriti::Jobs::Adapter.enqueue(
178
+ Smriti::DeleteViewJob,
179
+ queue: Smriti.configuration.job_queue || :default,
180
+ args: [mat_view_definition_id, cascade, row_count_strategy]
181
+ )
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+ require_relative 'helpers'
5
+
6
+ # rubocop:disable Metrics/BlockLength
7
+ namespace :smriti do
8
+ helpers = Smriti::Tasks::Helpers
9
+
10
+ # ───────────── CREATE ─────────────
11
+
12
+ desc 'Enqueue a CREATE for a specific view by its name (optionally schema-qualified)'
13
+ task :create_by_name, %i[view_name force row_count_strategy yes] => :environment do |_t, args|
14
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
15
+ force = helpers.parse_force?(args[:force])
16
+ skip = helpers.skip_confirm?(args[:yes])
17
+ defn = helpers.find_definition_by_name!(args[:view_name])
18
+
19
+ helpers.confirm!("Enqueue CREATE for view=#{defn.name} (id=#{defn.id}), force=#{force}, row_count_strategy=#{rcs}", skip: skip)
20
+ helpers.enqueue_create(defn.id, force, rcs)
21
+ helpers.logger.info("[smriti] Enqueued CreateViewJob for definition ##{defn.id} (#{defn.name}), force=#{force}, row_count_strategy=#{rcs}.")
22
+ end
23
+
24
+ desc 'Enqueue a CREATE for a specific view by its definition ID'
25
+ task :create_by_id, %i[mat_view_definition_id force row_count_strategy yes] => :environment do |_t, args|
26
+ raise 'smriti:create_by_id requires a mat_view_definition_id parameter' if args[:mat_view_definition_id].to_s.strip.empty?
27
+
28
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
29
+ force = helpers.parse_force?(args[:force])
30
+ skip = helpers.skip_confirm?(args[:yes])
31
+
32
+ defn = Smriti::MatViewDefinition.find_by(id: args[:mat_view_definition_id])
33
+ raise "No Smriti::MatViewDefinition found for id=#{args[:mat_view_definition_id]}" unless defn
34
+
35
+ helpers.confirm!("Enqueue CREATE for id=#{defn.id} (#{defn.name}), force=#{force}, row_count_strategy=#{rcs}", skip: skip)
36
+ helpers.enqueue_create(defn.id, force, rcs)
37
+ helpers.logger.info("[smriti] Enqueued CreateViewJob for definition ##{defn.id} (#{defn.name}), force=#{force}, row_count_strategy=#{rcs}.")
38
+ end
39
+
40
+ desc 'Enqueue CREATE jobs for ALL defined materialised views'
41
+ task :create_all, %i[force row_count_strategy yes] => :environment do |_t, args|
42
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
43
+ force = helpers.parse_force?(args[:force])
44
+ skip = helpers.skip_confirm?(args[:yes])
45
+
46
+ scope = Smriti::MatViewDefinition.all
47
+ count = scope.count
48
+ if count.zero?
49
+ helpers.logger.info('[smriti] No mat view definitions found.')
50
+ next
51
+ end
52
+
53
+ helpers.confirm!("Enqueue CREATE for ALL (#{count}) views, force=#{force}, row_count_strategy=#{rcs}", skip: skip)
54
+ scope.find_each { |defn| helpers.enqueue_create(defn.id, force, rcs) }
55
+ helpers.logger.info("[smriti] Enqueued #{count} CreateViewJob(s), force=#{force}, row_count_strategy=#{rcs}.")
56
+ end
57
+
58
+ # ───────────── REFRESH ─────────────
59
+
60
+ desc 'Enqueue a REFRESH for a specific view by its name (optionally schema-qualified)'
61
+ task :refresh_by_name, %i[view_name row_count_strategy yes] => :environment do |_t, args|
62
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
63
+ skip = helpers.skip_confirm?(args[:yes])
64
+ defn = helpers.find_definition_by_name!(args[:view_name])
65
+
66
+ helpers.confirm!("Enqueue REFRESH for view=#{defn.name} (id=#{defn.id}), row_count_strategy=#{rcs}", skip: skip)
67
+ helpers.enqueue_refresh(defn.id, rcs)
68
+ helpers.logger.info("[smriti] Enqueued RefreshViewJob for definition ##{defn.id} (#{defn.name}), row_count_strategy=#{rcs}.")
69
+ end
70
+
71
+ desc 'Enqueue a REFRESH for a specific view by its definition ID'
72
+ task :refresh_by_id, %i[mat_view_definition_id row_count_strategy yes] => :environment do |_t, args|
73
+ raise 'smriti:refresh_by_id requires a mat_view_definition_id parameter' if args[:mat_view_definition_id].to_s.strip.empty?
74
+
75
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
76
+ skip = helpers.skip_confirm?(args[:yes])
77
+
78
+ defn = Smriti::MatViewDefinition.find_by(id: args[:mat_view_definition_id])
79
+ raise "No Smriti::MatViewDefinition found for id=#{args[:mat_view_definition_id]}" unless defn
80
+
81
+ helpers.confirm!("Enqueue REFRESH for id=#{defn.id} (#{defn.name}), row_count_strategy=#{rcs}", skip: skip)
82
+ helpers.enqueue_refresh(defn.id, rcs)
83
+ helpers.logger.info("[smriti] Enqueued RefreshViewJob for definition ##{defn.id} (#{defn.name}), row_count_strategy=#{rcs}.")
84
+ end
85
+
86
+ desc 'Enqueue REFRESH jobs for ALL defined materialised views'
87
+ task :refresh_all, %i[row_count_strategy yes] => :environment do |_t, args|
88
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
89
+ skip = helpers.skip_confirm?(args[:yes])
90
+
91
+ scope = Smriti::MatViewDefinition.all
92
+ count = scope.count
93
+ if count.zero?
94
+ helpers.logger.info('[smriti] No mat view definitions found.')
95
+ next
96
+ end
97
+
98
+ helpers.confirm!("Enqueue REFRESH for ALL (#{count}) views, row_count_strategy=#{rcs}", skip: skip)
99
+ scope.find_each { |defn| helpers.enqueue_refresh(defn.id, rcs) }
100
+ helpers.logger.info("[smriti] Enqueued #{count} RefreshViewJob(s), row_count_strategy=#{rcs}.")
101
+ end
102
+
103
+ # ───────────── DELETE ─────────────
104
+
105
+ desc 'Enqueue a DELETE (DROP MATERIALIZED VIEW) for a specific view by its name (optionally schema-qualified)'
106
+ task :delete_by_name, %i[view_name cascade row_count_strategy yes] => :environment do |_t, args|
107
+ cascade = helpers.parse_cascade?(args[:cascade])
108
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
109
+ skip = helpers.skip_confirm?(args[:yes])
110
+ defn = helpers.find_definition_by_name!(args[:view_name])
111
+
112
+ helpers.confirm!("Enqueue DELETE for view=#{defn.name} (id=#{defn.id}), cascade=#{cascade}, row_count_strategy=#{rcs}", skip: skip)
113
+ helpers.enqueue_delete(defn.id, cascade, rcs)
114
+ helpers.logger.info("[smriti] Enqueued DeleteViewJob for definition ##{defn.id} (#{defn.name}), cascade=#{cascade}, row_count_strategy=#{rcs}.")
115
+ end
116
+
117
+ desc 'Enqueue a DELETE (DROP MATERIALIZED VIEW) for a specific view by its definition ID'
118
+ task :delete_by_id, %i[mat_view_definition_id cascade row_count_strategy yes] => :environment do |_t, args|
119
+ raise 'smriti:delete_by_id requires a mat_view_definition_id parameter' if args[:mat_view_definition_id].to_s.strip.empty?
120
+
121
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
122
+ cascade = helpers.parse_cascade?(args[:cascade])
123
+ skip = helpers.skip_confirm?(args[:yes])
124
+
125
+ defn = Smriti::MatViewDefinition.find_by(id: args[:mat_view_definition_id])
126
+ raise "No Smriti::MatViewDefinition found for id=#{args[:mat_view_definition_id]}" unless defn
127
+
128
+ helpers.confirm!("Enqueue DELETE for id=#{defn.id} (#{defn.name}), cascade=#{cascade}, row_count_strategy=#{rcs}", skip: skip)
129
+ helpers.enqueue_delete(defn.id, cascade, rcs)
130
+ helpers.logger.info("[smriti] Enqueued DeleteViewJob for definition ##{defn.id} (#{defn.name}), cascade=#{cascade}, row_count_strategy=#{rcs}.")
131
+ end
132
+
133
+ desc 'Enqueue DELETE jobs for ALL defined materialised views'
134
+ task :delete_all, %i[cascade row_count_strategy yes] => :environment do |_t, args|
135
+ rcs = helpers.parse_row_count_strategy(args[:row_count_strategy])
136
+ cascade = helpers.parse_cascade?(args[:cascade])
137
+ skip = helpers.skip_confirm?(args[:yes])
138
+
139
+ scope = Smriti::MatViewDefinition.all
140
+ count = scope.count
141
+ if count.zero?
142
+ helpers.logger.info('[smriti] No mat view definitions found.')
143
+ next
144
+ end
145
+
146
+ helpers.confirm!("Enqueue DELETE for ALL (#{count}) views, cascade=#{cascade}, row_count_strategy=#{rcs}", skip: skip)
147
+ scope.find_each { |defn| helpers.enqueue_delete(defn.id, cascade, rcs) }
148
+ helpers.logger.info("[smriti] Enqueued #{count} DeleteViewJob(s), cascade=#{cascade}, row_count_strategy=#{rcs}.")
149
+ end
150
+ end
151
+ # rubocop:enable Metrics/BlockLength
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smriti
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Nitesh Purohit
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.1'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: rails-i18n
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '7.0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '7.0'
46
+ description: A mountable Rails engine to track, define, refresh, and monitor Postgres
47
+ materialised views.
48
+ email:
49
+ - nitesh.purohit.it@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - LICENSE
55
+ - README.md
56
+ - Rakefile
57
+ - app/assets/images/smriti/android-chrome-192x192.png
58
+ - app/assets/images/smriti/android-chrome-512x512.png
59
+ - app/assets/images/smriti/apple-touch-icon.png
60
+ - app/assets/images/smriti/favicon-16x16.png
61
+ - app/assets/images/smriti/favicon-32x32.png
62
+ - app/assets/images/smriti/favicon-48x48.png
63
+ - app/assets/images/smriti/favicon.ico
64
+ - app/assets/images/smriti/favicon.svg
65
+ - app/assets/images/smriti/logo.svg
66
+ - app/assets/images/smriti/mask-icon.svg
67
+ - app/assets/stylesheets/smriti/application.css
68
+ - app/controllers/smriti/admin/application_controller.rb
69
+ - app/controllers/smriti/admin/dashboard_controller.rb
70
+ - app/controllers/smriti/admin/mat_view_definitions_controller.rb
71
+ - app/controllers/smriti/admin/mat_view_runs_controller.rb
72
+ - app/controllers/smriti/admin/preferences_controller.rb
73
+ - app/helpers/smriti/admin/datatable_helper.rb
74
+ - app/helpers/smriti/admin/localized_digit_helper.rb
75
+ - app/helpers/smriti/admin/ui_helper.rb
76
+ - app/javascript/smriti/application.js
77
+ - app/javascript/smriti/controllers/application.js
78
+ - app/javascript/smriti/controllers/body_setup_controller.js
79
+ - app/javascript/smriti/controllers/datatable_controller.js
80
+ - app/javascript/smriti/controllers/details_controller.js
81
+ - app/javascript/smriti/controllers/drawer_controller.js
82
+ - app/javascript/smriti/controllers/flash_controller.js
83
+ - app/javascript/smriti/controllers/index.js
84
+ - app/javascript/smriti/controllers/mv_confirm_controller.js
85
+ - app/javascript/smriti/controllers/tabs_controller.js
86
+ - app/javascript/smriti/controllers/tooltip_controller.js
87
+ - app/javascript/smriti/controllers/turbo_frame_lifecycle_controller.js
88
+ - app/jobs/smriti/application_job.rb
89
+ - app/jobs/smriti/create_view_job.rb
90
+ - app/jobs/smriti/delete_view_job.rb
91
+ - app/jobs/smriti/refresh_view_job.rb
92
+ - app/models/concerns/smriti_i18n.rb
93
+ - app/models/concerns/smriti_paginate.rb
94
+ - app/models/concerns/smriti_query_helper.rb
95
+ - app/models/smriti/application_record.rb
96
+ - app/models/smriti/mat_view_definition.rb
97
+ - app/models/smriti/mat_view_run.rb
98
+ - app/views/layouts/smriti/_footer.html.erb
99
+ - app/views/layouts/smriti/_header.html.erb
100
+ - app/views/layouts/smriti/admin.html.erb
101
+ - app/views/layouts/smriti/turbo_frame.html.erb
102
+ - app/views/smriti/admin/dashboard/index.html.erb
103
+ - app/views/smriti/admin/mat_view_definitions/_definition_actions.html.erb
104
+ - app/views/smriti/admin/mat_view_definitions/_dt-index-empty-row.html.erb
105
+ - app/views/smriti/admin/mat_view_definitions/_dt-index-row.html.erb
106
+ - app/views/smriti/admin/mat_view_definitions/empty.html.erb
107
+ - app/views/smriti/admin/mat_view_definitions/form.html.erb
108
+ - app/views/smriti/admin/mat_view_definitions/index.html.erb
109
+ - app/views/smriti/admin/mat_view_definitions/show.html.erb
110
+ - app/views/smriti/admin/mat_view_runs/_dt-index-empty-row.html.erb
111
+ - app/views/smriti/admin/mat_view_runs/_dt-index-row.html.erb
112
+ - app/views/smriti/admin/mat_view_runs/index.html.erb
113
+ - app/views/smriti/admin/mat_view_runs/show.html.erb
114
+ - app/views/smriti/admin/preferences/show.html.erb
115
+ - app/views/smriti/admin/ui/_card.html.erb
116
+ - app/views/smriti/admin/ui/_datatable.html.erb
117
+ - app/views/smriti/admin/ui/_datatable_filters.html.erb
118
+ - app/views/smriti/admin/ui/_datatable_tbody.html.erb
119
+ - app/views/smriti/admin/ui/_datatable_tfoot.html.erb
120
+ - app/views/smriti/admin/ui/_datatable_thead.html.erb
121
+ - app/views/smriti/admin/ui/_details.html.erb
122
+ - app/views/smriti/admin/ui/_flash.html.erb
123
+ - app/views/smriti/admin/ui/_table.html.erb
124
+ - config/importmap.rb
125
+ - config/locales/ar.yml
126
+ - config/locales/de.yml
127
+ - config/locales/en-AU-ocker.yml
128
+ - config/locales/en-AU.yml
129
+ - config/locales/en-BORK.yml
130
+ - config/locales/en-CA.yml
131
+ - config/locales/en-GB.yml
132
+ - config/locales/en-LOL.yml
133
+ - config/locales/en-SCOT.yml
134
+ - config/locales/en-SHAKESPEARE.yml
135
+ - config/locales/en-US-pirate.yml
136
+ - config/locales/en-US.yml
137
+ - config/locales/en-YODA.yml
138
+ - config/locales/en.yml
139
+ - config/locales/es.yml
140
+ - config/locales/fa.yml
141
+ - config/locales/fr-CA.yml
142
+ - config/locales/fr.yml
143
+ - config/locales/he.yml
144
+ - config/locales/hi.yml
145
+ - config/locales/it.yml
146
+ - config/locales/ja-JP.yml
147
+ - config/locales/pt.yml
148
+ - config/locales/ru.yml
149
+ - config/locales/ur.yml
150
+ - config/locales/zh-CN.yml
151
+ - config/locales/zh-TW.yml
152
+ - config/routes.rb
153
+ - lib/ext/exception.rb
154
+ - lib/generators/smriti/install/install_generator.rb
155
+ - lib/generators/smriti/install/templates/create_mat_view_definitions.rb
156
+ - lib/generators/smriti/install/templates/create_mat_view_runs.rb
157
+ - lib/generators/smriti/install/templates/smriti_initializer.rb
158
+ - lib/smriti.rb
159
+ - lib/smriti/admin/auth_bridge.rb
160
+ - lib/smriti/admin/default_auth.rb
161
+ - lib/smriti/configuration.rb
162
+ - lib/smriti/engine.rb
163
+ - lib/smriti/helpers/ui_test_ids.rb
164
+ - lib/smriti/jobs/adapter.rb
165
+ - lib/smriti/service_response.rb
166
+ - lib/smriti/services/base_service.rb
167
+ - lib/smriti/services/check_matview_exists.rb
168
+ - lib/smriti/services/concurrent_refresh.rb
169
+ - lib/smriti/services/create_view.rb
170
+ - lib/smriti/services/delete_view.rb
171
+ - lib/smriti/services/regular_refresh.rb
172
+ - lib/smriti/services/swap_refresh.rb
173
+ - lib/smriti/version.rb
174
+ - lib/tasks/helpers.rb
175
+ - lib/tasks/smriti_tasks.rake
176
+ homepage: https://github.com/Code-Vedas/smriti
177
+ licenses:
178
+ - MIT
179
+ metadata:
180
+ bug_tracker_uri: https://github.com/Code-Vedas/smriti/issues
181
+ changelog_uri: https://github.com/Code-Vedas/smriti/blob/main/CHANGELOG.md
182
+ documentation_uri: https://smriti.codevedas.com
183
+ homepage_uri: https://github.com/Code-Vedas/smriti
184
+ source_code_uri: https://github.com/Code-Vedas/smriti.git
185
+ funding_uri: https://github.com/sponsors/Code-Vedas
186
+ support_uri: https://smriti.codevedas.com/support
187
+ rubygems_uri: https://rubygems.org/gems/smriti
188
+ rubygems_mfa_required: 'true'
189
+ rdoc_options: []
190
+ require_paths:
191
+ - lib
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '3.2'
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ requirements: []
203
+ rubygems_version: 3.6.7
204
+ specification_version: 4
205
+ summary: Manage and refresh PostgreSQL materialised views in Rails
206
+ test_files: []