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,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ # Extend the Exception class to add a method for serializing error details.
9
+ class Exception
10
+ # Serialize the exception into a hash with message, class, and backtrace.
11
+ #
12
+ # @return [Hash] serialized error details
13
+ def mv_serialize_error
14
+ {
15
+ message: message,
16
+ class: self.class.name,
17
+ backtrace: Array(backtrace)
18
+ }
19
+ end
20
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ require 'rails/generators'
9
+ require 'rails/generators/migration'
10
+ require 'rails/generators/active_record'
11
+
12
+ ##
13
+ # Top-level namespace for the smriti engine.
14
+ module Smriti
15
+ ##
16
+ # Namespace for Rails generators shipped with the smriti engine.
17
+ module Generators
18
+ ##
19
+ # Rails generator that installs Smriti into a host application by:
20
+ #
21
+ # 1. Copying migrations for definitions and run-tracking tables.
22
+ # 2. Creating an initializer at `config/initializers/smriti.rb`.
23
+ # 3. Printing a success message with next steps.
24
+ #
25
+ # @example Run the installer
26
+ # bin/rails g smriti:install
27
+ #
28
+ # @see Smriti::MatViewDefinition
29
+ # @see Smriti::MatViewRun
30
+ #
31
+ class InstallGenerator < Rails::Generators::Base
32
+ include Rails::Generators::Migration
33
+
34
+ ##
35
+ # Directory containing template files for the generator.
36
+ #
37
+ # @return [String] absolute path to templates dir
38
+ #
39
+ source_root File.expand_path('templates', __dir__)
40
+
41
+ ##
42
+ # Short description shown in `rails g --help`.
43
+ desc 'Installs Smriti: copies migrations and initializer.'
44
+
45
+ ##
46
+ # Copies all required migrations into the host app.
47
+ #
48
+ # @return [void]
49
+ #
50
+ def copy_migrations
51
+ migration_template 'create_mat_view_definitions.rb', 'db/migrate/create_mat_view_definitions.rb'
52
+ migration_template 'create_mat_view_runs.rb', 'db/migrate/create_mat_view_runs.rb'
53
+ end
54
+
55
+ ##
56
+ # Creates the engine initializer in the host app.
57
+ #
58
+ # @return [void]
59
+ #
60
+ def create_initializer
61
+ copy_file 'smriti_initializer.rb', 'config/initializers/smriti.rb'
62
+ end
63
+
64
+ ##
65
+ # Prints a success message after installation.
66
+ #
67
+ # @return [void]
68
+ #
69
+ def show_success_message
70
+ say "\n✅ Smriti installed! Don't forget to run: rails db:migrate\n", :green
71
+ end
72
+
73
+ ##
74
+ # Computes the next migration number for copied migrations.
75
+ #
76
+ # Required by Rails to generate timestamped migration filenames.
77
+ #
78
+ # @param path [String] destination path for migrations
79
+ # @return [String] the next migration number (timestamp)
80
+ #
81
+ def self.next_migration_number(path)
82
+ ActiveRecord::Generators::Base.next_migration_number(path)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ # This migration creates the mat_view_definitions table, which stores definitions for materialised views.
9
+ # It includes fields for the view name, SQL definition, refresh strategy, schedule, unique index columns,
10
+ # dependencies, last refreshed timestamp, and timestamps for creation and updates.
11
+ class CreateMatViewDefinitions < ActiveRecord::Migration[7.1]
12
+ def change
13
+ create_table :mat_view_definitions do |t|
14
+ t.string :name, null: false, comment: 'The name of the materialised view'
15
+ t.text :sql, null: false, comment: 'The SQL query defining the materialised view'
16
+ # refresh_strategy can be
17
+ # regular: 0 - Default strategy, in-place refresh.
18
+ # concurrent: 1 - Concurrent refresh, requires at least one unique index.
19
+ # swap: 2 - Swap the materialised view with a new one, uses more memory.
20
+ t.integer :refresh_strategy, default: 0, null: false,
21
+ comment: 'Strategy for refreshing the materialised view. Options: regular, concurrent, swap'
22
+ t.string :schedule_cron, comment: 'Cron schedule for automatic refresh of the materialised view'
23
+ t.jsonb :unique_index_columns, default: [], comment: 'Columns used for unique indexing, if any'
24
+ t.jsonb :dependencies, default: [],
25
+ comment: 'Dependencies of the materialised view, such as other views or tables'
26
+ t.timestamps
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ # This migration creates the mat_view_runs table, which tracks the mutation runs(create,refresh,drop) of materialised views.
9
+ # It includes references to the materialised view definition, status, operation type, timestamps,
10
+ # duration, error messages, and additional metadata.
11
+ class CreateMatViewRuns < ActiveRecord::Migration[7.1]
12
+ def change
13
+ create_table :mat_view_runs do |t|
14
+ t.references :mat_view_definition,
15
+ null: false,
16
+ foreign_key: true,
17
+ comment: 'Reference to the materialised view definition'
18
+
19
+ # 0=running, 1=success, 2=failed
20
+ t.integer :status, null: false, default: 0, comment: '0=running,1=success,2=failed'
21
+ # 0=create, 1=refresh, 2=drop
22
+ t.integer :operation, null: false, default: 0, comment: '0=create,1=refresh,2=drop'
23
+ t.datetime :started_at, comment: 'Timestamp when the operation started'
24
+ t.datetime :finished_at, comment: 'Timestamp when the operation finished'
25
+ t.integer :duration_ms, comment: 'Duration of the operation in milliseconds'
26
+ t.jsonb :error, comment: 'Error details if the operation failed. :message, :class, :backtrace'
27
+ t.jsonb :meta, null: false, default: {}, comment: 'Additional metadata about the run, such as job ID, row count or parameters'
28
+
29
+ t.timestamps
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ Smriti.configure do |config|
9
+ ### Job Adapter Configuration
10
+ # Set job adapter for Smriti
11
+ # This can be set to :active_job, :sidekiq, and :resque,
12
+ # defaults to :active_job.
13
+ #
14
+ # Depending on your application's job processing setup.
15
+ # Uncomment the line below to set the job adapter.
16
+ # config.job_adapter = :active_job
17
+
18
+ # job_queue is the queue name for the job adapter.
19
+ # Default is :default.
20
+ # This is used to specify the queue where Smriti jobs will be enqueued.
21
+ # Uncomment the line below to set the job queue.
22
+ # config.job_queue = :default
23
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ module Smriti
9
+ module Admin
10
+ #
11
+ # Smriti::Admin::AuthBridge
12
+ # ---------------------------
13
+ # Bridge module that wires the Smriti admin engine to a **host-provided**
14
+ # authentication/authorization layer, while providing safe defaults.
15
+ #
16
+ # ### How it works
17
+ # - Includes {Smriti::Admin::DefaultAuth} first (fallback, no-op/hostable).
18
+ # - Then includes the **host auth module** returned by {.host_auth_module}.
19
+ # Because Ruby searches the most recently included module first, the host
20
+ # module cleanly **overrides** any defaults from `DefaultAuth`.
21
+ # - Registers a before_action `authenticate_smriti!`.
22
+ # - Exposes helpers: `smriti_current_user` and its alias {#user}.
23
+ #
24
+ # ### Host integration options (define one of these):
25
+ # 1) A top-level module:
26
+ # ```ruby
27
+ # # app/lib/smriti_admin.rb (or any autoloaded path)
28
+ # module SmritiAdmin
29
+ # def authenticate_smriti!; end
30
+ # def authorize_smriti!(*); end
31
+ # def smriti_current_user; end
32
+ # end
33
+ # ```
34
+ # 2) A namespaced module:
35
+ # ```ruby
36
+ # # app/lib/smriti/admin/host_auth.rb
37
+ # module Smriti
38
+ # module Admin
39
+ # module HostAuth
40
+ # def authenticate_smriti!; end
41
+ # def authorize_smriti!(*); end
42
+ # def smriti_current_user; end
43
+ # end
44
+ # end
45
+ # end
46
+ # ```
47
+ #
48
+ # If neither module is present, a blank `Module.new` is included and the
49
+ # defaults in {Smriti::Admin::DefaultAuth} remain in effect.
50
+ #
51
+ # @see Smriti::Admin::DefaultAuth
52
+ #
53
+ module AuthBridge
54
+ extend ActiveSupport::Concern
55
+
56
+ included do
57
+ # Include defaults first, so the host module (included below) can override.
58
+ include Smriti::Admin::DefaultAuth
59
+ include host_auth_module
60
+
61
+ before_action :authenticate_smriti!
62
+ helper_method :smriti_current_user, :user
63
+ end
64
+
65
+ # Convenience alias for `smriti_current_user` exposed to views.
66
+ #
67
+ # @return [Object, nil] the current user object as defined by host auth
68
+ def user = smriti_current_user
69
+
70
+ class_methods do
71
+ # Resolves the host's auth module, if any.
72
+ #
73
+ # Lookup order:
74
+ # 1. `::SmritiAdmin`
75
+ # 2. `::Smriti::Admin::HostAuth`
76
+ # 3. Fallback: a blank Module (no overrides)
77
+ #
78
+ # @return [Module] the module to include for host auth overrides
79
+ def host_auth_module
80
+ if Object.const_defined?('SmritiAdmin')
81
+ ::SmritiAdmin
82
+ elsif Object.const_defined?('Smriti') &&
83
+ Smriti.const_defined?('Admin') &&
84
+ Smriti::Admin.const_defined?('HostAuth')
85
+ ::Smriti::Admin::HostAuth
86
+ else
87
+ Module.new
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ module Smriti
9
+ module Admin
10
+ # Smriti::Admin::DefaultAuth
11
+ # ----------------------------
12
+ # Development-friendly **fallback** authentication/authorization for the Smriti
13
+ # admin UI. It is included first by {Smriti::Admin::AuthBridge}, and is meant
14
+ # to be overridden by a host-provided module (`SmritiAdmin` or
15
+ # `Smriti::Admin::HostAuth`).
16
+ #
17
+ # ❗ **Not for production**: this module allows all access and returns a dummy user.
18
+ #
19
+ # @see Smriti::Admin::AuthBridge
20
+ #
21
+ module DefaultAuth
22
+ # Minimal stand-in user object used by the default auth.
23
+ #
24
+ # @!attribute [rw] email
25
+ # @return [String] the email address of the sample user
26
+ class SampleUser
27
+ attr_accessor :email
28
+
29
+ # @param email [String]
30
+ def initialize(email) = @email = email
31
+
32
+ # @return [String] the user's email
33
+ def to_s = email
34
+ end
35
+
36
+ # Authenticates the current request.
37
+ # Always returns true in the default implementation.
38
+ #
39
+ # @return [Boolean] true
40
+ # rubocop:disable Naming/PredicateMethod
41
+ def authenticate_smriti! = true
42
+ # rubocop:enable Naming/PredicateMethod
43
+
44
+ # Returns the current user object.
45
+ # In the default implementation this is a {SampleUser}.
46
+ #
47
+ # @return [SampleUser]
48
+ def smriti_current_user = SampleUser.new('sample-user@example.com')
49
+
50
+ # Authorizes an action on a record.
51
+ # Always returns true in the default implementation.
52
+ #
53
+ # @param _action [Symbol, String] the attempted action (ignored)
54
+ # @param _type [Symbol, String] the type of resource (ignored)
55
+ # @param _record [Object] the target record or symbol (ignored)
56
+ # @return [Boolean] true
57
+ # rubocop:disable Naming/PredicateMethod
58
+ def authorize_smriti!(_action, _type, _record = nil) = true
59
+ # rubocop:enable Naming/PredicateMethod
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ module Smriti
9
+ ##
10
+ # Configuration for the Smriti engine.
11
+ #
12
+ # This class provides customization points for how Smriti integrates
13
+ # with background job systems and controls default behavior across
14
+ # the engine.
15
+ #
16
+ # @example Configure in an initializer
17
+ # Smriti.configure do |config|
18
+ # config.job_adapter = :sidekiq
19
+ # config.job_queue = :low_priority
20
+ # config.admin_ui = { row_count_strategy: :estimated }
21
+ # end
22
+ #
23
+ # Supported job adapters:
24
+ # - `:active_job` (default)
25
+ # - `:sidekiq`
26
+ # - `:resque`
27
+ #
28
+ class Configuration
29
+ ##
30
+ # The job adapter to use for enqueuing jobs.
31
+ #
32
+ # @return [Symbol] :active_job, :sidekiq, or :resque
33
+ attr_accessor :job_adapter
34
+
35
+ ##
36
+ # The default queue name to use for jobs.
37
+ #
38
+ # @return [Symbol, String]
39
+ attr_accessor :job_queue
40
+
41
+ ##
42
+ # admin_ui configuration
43
+ # @return [Hash]
44
+ attr_accessor :admin_ui
45
+
46
+ ##
47
+ # Initialize with defaults.
48
+ #
49
+ # @return [void]
50
+ def initialize
51
+ @job_adapter = :active_job
52
+ @job_queue = :default
53
+ @admin_ui = {
54
+ row_count_strategy: :none
55
+ }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ ##
9
+ # Smriti is a Rails engine that provides first-class support for
10
+ # PostgreSQL materialised views in Rails applications.
11
+ module Smriti
12
+ class << self
13
+ attr_accessor :importmap
14
+ end
15
+ ##
16
+ # Rails Engine for Smriti.
17
+ #
18
+ # This engine encapsulates all functionality related to
19
+ # materialised views, including:
20
+ # - Defining materialised view definitions
21
+ # - Creating and refreshing views
22
+ # - Managing background jobs for refresh/create/delete
23
+ #
24
+ # By isolating the namespace, it ensures that routes, models,
25
+ # and helpers do not conflict with the host application.
26
+ #
27
+ # @example Mounting the engine in a Rails application
28
+ # # config/routes.rb
29
+ # Rails.application.routes.draw do
30
+ # mount Smriti::Engine => "/smriti"
31
+ # end
32
+ #
33
+ class Engine < ::Rails::Engine
34
+ isolate_namespace Smriti
35
+
36
+ initializer 'smriti.load_config' do
37
+ Smriti.configuration ||= Smriti::Configuration.new
38
+ end
39
+
40
+ initializer 'smriti.javascript' do |app|
41
+ app.config.assets.paths << root.join('app/javascript')
42
+ end
43
+
44
+ initializer 'smriti.importmap', before: 'importmap' do |_app|
45
+ next unless defined?(Importmap)
46
+
47
+ Smriti.importmap = Importmap::Map.new
48
+ Smriti.importmap.draw(root.join('config/importmap.rb'))
49
+ Smriti.importmap.cache_sweeper(watches: root.join('app/javascript'))
50
+
51
+ ActiveSupport.on_load(:action_controller_base) do
52
+ before_action { Smriti.importmap.cache_sweeper.execute_if_updated }
53
+ end
54
+ end
55
+
56
+ def self.locale_code_mapping
57
+ @locale_code_mapping ||= begin
58
+ mappings = Dir[root.join('config', 'locales', '*.yml')].map.to_h do |file|
59
+ code = File.basename(file, '.yml').to_sym
60
+ name = I18n.t('i18n.name', locale: code)
61
+ [code, name]
62
+ end
63
+ mappings.sort_by { |code, _name| code.to_s }.to_h
64
+ end
65
+ end
66
+
67
+ def self.available_locales
68
+ @available_locales ||= locale_code_mapping.keys.freeze
69
+ end
70
+
71
+ def self.default_locale = :en
72
+ def self.loaded_spec = Gem.loaded_specs['smriti']
73
+ def self.project_name = loaded_spec&.name
74
+ def self.project_version = Smriti::VERSION
75
+ def self.project_homepage = loaded_spec&.homepage
76
+ def self.company_name = 'Codevedas Inc.'
77
+ def self.documentation_uri = loaded_spec&.metadata&.[]('documentation_uri')
78
+ def self.bug_tracker_uri = loaded_spec&.metadata&.[]('bug_tracker_uri')
79
+ def self.support_uri = loaded_spec&.metadata&.[]('support_uri')
80
+ def self.rubygems_uri = loaded_spec&.metadata&.[]('rubygems_uri')
81
+ end
82
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ module Smriti
9
+ module Helpers
10
+ module UiTestIds
11
+ GEM_LINK = 'gem_link'
12
+ PROJECT_HOMEPAGE_LINK = 'project_homepage_link'
13
+ OPEN_ISSUE_LINK = 'open_issue_link'
14
+ DOCUMENTATION_LINK = 'documentation_link'
15
+ SUPPORT_LINK = 'support_link'
16
+
17
+ DRAWER_REFRESH_LINK = 'drawer_refresh_link'
18
+ DRAWER_CLOSE_LINK = 'drawer_close_link'
19
+
20
+ HEADER_LINK = 'header_link'
21
+ PREFERENCES_LINK = 'preferences_link'
22
+
23
+ DEFINITIONS_TAB_LINK = 'definitions_tab_link'
24
+ RUNS_TAB_LINK = 'runs_tab_link'
25
+
26
+ NEW_DEFINITION_LINK = 'new_definition_link'
27
+ SUBMIT_BUTTON = 'submit_button'
28
+ CANCEL_BUTTON = 'cancel_button'
29
+ VIEW_HISTORY_LINK = 'view_history_link'
30
+ VIEW_LINK = 'view_link'
31
+ EDIT_LINK = 'edit_link'
32
+ DELETE_LINK = 'delete_link'
33
+ REFRESH_LINK = 'refresh_link'
34
+ DROP_LINK = 'drop_link'
35
+ DROP_CASCADE_LINK = 'drop_cascade_link'
36
+ CREATE_MV_LINK = 'create_mv_link'
37
+ RESET_FILTERS_LINK = 'reset_filters_link'
38
+
39
+ PREFERENCES_SAVE_BUTTON = 'preferences_save_button'
40
+ PREFERENCES_CANCEL_BUTTON = 'preferences_cancel_button'
41
+
42
+ TOGGLE_SORT_BUTTON = 'toggle_sort_button'
43
+ DT_SEARCH_INPUT = 'dt_search_input'
44
+ DT_FILTER_SELECT = 'dt_filter_select'
45
+ DT_CLEAR_SEARCH_BTN = 'dt_clear_search_btn'
46
+ DT_PAGINATION_BTN = 'dt_pagination_btn'
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright Codevedas Inc. 2025-present
4
+ #
5
+ # This source code is licensed under the MIT license found in the
6
+ # LICENSE file in the root directory of this source tree.
7
+
8
+ ##
9
+ # Top-level namespace for the smriti engine.
10
+ module Smriti
11
+ ##
12
+ # Namespace for job-related utilities and integrations.
13
+ module Jobs
14
+ ##
15
+ # Adapter class for handling job enqueuing across different backends.
16
+ #
17
+ # This class abstracts the job enqueueing process so Smriti can work
18
+ # with multiple background processing frameworks without changing core code.
19
+ #
20
+ # Supported adapters (configured via `Smriti.configuration.job_adapter`):
21
+ # - `:active_job` → {ActiveJob}
22
+ # - `:sidekiq` → {Sidekiq::Client}
23
+ # - `:resque` → {Resque}
24
+ #
25
+ # @example Enqueue via ActiveJob
26
+ # Smriti.configuration.job_adapter = :active_job
27
+ # Smriti::Jobs::Adapter.enqueue(MyJob, queue: :low, args: [1, "foo"])
28
+ #
29
+ # @example Enqueue via Sidekiq
30
+ # Smriti.configuration.job_adapter = :sidekiq
31
+ # Smriti::Jobs::Adapter.enqueue(MyWorker, queue: :critical, args: [42])
32
+ #
33
+ # @example Enqueue via Resque
34
+ # Smriti.configuration.job_adapter = :resque
35
+ # Smriti::Jobs::Adapter.enqueue(MyWorker, queue: :default, args: %w[a b c])
36
+ #
37
+ # @raise [ArgumentError] if the configured adapter is not recognized
38
+ #
39
+ class Adapter
40
+ ##
41
+ # Enqueue a job across supported backends.
42
+ #
43
+ # @api public
44
+ #
45
+ # @param job_class [Class] The job or worker class to enqueue.
46
+ # - For `:active_job`, this should be a subclass of {ActiveJob::Base}.
47
+ # - For `:sidekiq`, this should be a Sidekiq worker class.
48
+ # - For `:resque`, this should be a Resque worker class.
49
+ #
50
+ # @param queue [String, Symbol] Target queue name.
51
+ # @param args [Array] Arguments to pass into the job/worker.
52
+ #
53
+ # @return [Object] Framework-dependent:
54
+ # - For ActiveJob → enqueued {ActiveJob::Base} instance
55
+ # - For Sidekiq → job ID hash
56
+ # - For Resque → `true` if enqueue succeeded
57
+ #
58
+ # @raise [ArgumentError] if the configured adapter is not recognized.
59
+ #
60
+ def self.enqueue(job_class, queue:, args: [])
61
+ queue_str = queue.to_s
62
+ job_adapter = Smriti.configuration.job_adapter
63
+
64
+ case job_adapter
65
+ when :active_job
66
+ job_class.set(queue: queue_str).perform_later(*args)
67
+ when :sidekiq
68
+ Sidekiq::Client.push(
69
+ 'class' => job_class.name,
70
+ 'queue' => queue_str,
71
+ 'args' => args
72
+ )
73
+ when :resque
74
+ Resque.enqueue_to(queue_str, job_class, *args)
75
+ else
76
+ raise ArgumentError, "Unknown job adapter: #{job_adapter.inspect}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end