dbdoc_engine 0.1.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.
- checksums.yaml +7 -0
- data/README.md +331 -0
- data/Rakefile +8 -0
- data/app/assets/builds/dbdoc_engine/application.css +5 -0
- data/app/assets/images/dbdoc_engine/arrowdown.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowhorizontal.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowleft.svg +3 -0
- data/app/assets/images/dbdoc_engine/changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/column_stats_dbdocs.svg +23 -0
- data/app/assets/images/dbdoc_engine/diagram.svg +3 -0
- data/app/assets/images/dbdoc_engine/double_arrow.svg +4 -0
- data/app/assets/images/dbdoc_engine/group_bu.svg +3 -0
- data/app/assets/images/dbdoc_engine/japan_circle.png +0 -0
- data/app/assets/images/dbdoc_engine/log_in_image.png +0 -0
- data/app/assets/images/dbdoc_engine/logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/orange_fields.svg +23 -0
- data/app/assets/images/dbdoc_engine/orange_logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_table.svg +21 -0
- data/app/assets/images/dbdoc_engine/orange_updates.svg +43 -0
- data/app/assets/images/dbdoc_engine/orange_wiki.svg +3 -0
- data/app/assets/images/dbdoc_engine/search.svg +3 -0
- data/app/assets/images/dbdoc_engine/setting.svg +3 -0
- data/app/assets/images/dbdoc_engine/table_dbdocs.svg +21 -0
- data/app/assets/images/dbdoc_engine/uk_circle_transparent.png +0 -0
- data/app/assets/images/dbdoc_engine/update_stats_dbdocs.svg +43 -0
- data/app/assets/images/dbdoc_engine/wiki.svg +3 -0
- data/app/assets/stylesheets/dbdoc_engine/admin.css +176 -0
- data/app/assets/stylesheets/dbdoc_engine/admin_header.css +179 -0
- data/app/assets/stylesheets/dbdoc_engine/application.scss +1 -0
- data/app/assets/stylesheets/dbdoc_engine/changelog.css +173 -0
- data/app/assets/stylesheets/dbdoc_engine/dashboard.css +513 -0
- data/app/assets/stylesheets/dbdoc_engine/dbdoc_application.css +117 -0
- data/app/assets/stylesheets/dbdoc_engine/ecommerce.css +253 -0
- data/app/assets/stylesheets/dbdoc_engine/group_details.css +178 -0
- data/app/assets/stylesheets/dbdoc_engine/header.css +212 -0
- data/app/assets/stylesheets/dbdoc_engine/loading_spinner.css +127 -0
- data/app/assets/stylesheets/dbdoc_engine/login.css +213 -0
- data/app/assets/stylesheets/dbdoc_engine/schema_diagram.css +149 -0
- data/app/assets/stylesheets/dbdoc_engine/sidebar.css +296 -0
- data/app/assets/stylesheets/dbdoc_engine/table_details.css +417 -0
- data/app/controllers/dbdoc_engine/admin/base_controller.rb +23 -0
- data/app/controllers/dbdoc_engine/admin/dashboard_controller.rb +16 -0
- data/app/controllers/dbdoc_engine/admin/data_transfer_controller.rb +63 -0
- data/app/controllers/dbdoc_engine/admin/db_design_dynamic_tables_controller.rb +198 -0
- data/app/controllers/dbdoc_engine/admin/db_design_table_groups_controller.rb +107 -0
- data/app/controllers/dbdoc_engine/application_controller.rb +65 -0
- data/app/controllers/dbdoc_engine/concerns/internationalization.rb +57 -0
- data/app/controllers/dbdoc_engine/db_doc_sessions_controller.rb +33 -0
- data/app/controllers/dbdoc_engine/home_controller.rb +79 -0
- data/app/controllers/dbdoc_engine/schema_diagram_controller.rb +293 -0
- data/app/helper/dbdoc_engine/application_helper.rb +35 -0
- data/app/helpers/dbdoc_engine/application_helper.rb +4 -0
- data/app/helpers/dbdoc_engine/changelogs_helper.rb +27 -0
- data/app/helpers/dbdoc_engine/column_helper.rb +30 -0
- data/app/helpers/dbdoc_engine/db_design_dynamic_tables_helper.rb +15 -0
- data/app/helpers/dbdoc_engine/home_helper.rb +75 -0
- data/app/javascript/dbdoc_engine/application.js +12 -0
- data/app/javascript/dbdoc_engine/controllers/application.js +29 -0
- data/app/javascript/dbdoc_engine/controllers/auto_submit_controller.js +17 -0
- data/app/javascript/dbdoc_engine/controllers/chart_controller.js +58 -0
- data/app/javascript/dbdoc_engine/controllers/column-type_controller.js +149 -0
- data/app/javascript/dbdoc_engine/controllers/column_controller.js +362 -0
- data/app/javascript/dbdoc_engine/controllers/column_search_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/dbdoc_accordion_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/ecommerce_controller.js +73 -0
- data/app/javascript/dbdoc_engine/controllers/group_details_controller.js +88 -0
- data/app/javascript/dbdoc_engine/controllers/import_export_controller.js +200 -0
- data/app/javascript/dbdoc_engine/controllers/index.js +9 -0
- data/app/javascript/dbdoc_engine/controllers/language_controller.js +100 -0
- data/app/javascript/dbdoc_engine/controllers/loading_spinner_controller.js +48 -0
- data/app/javascript/dbdoc_engine/controllers/login_controller.js +75 -0
- data/app/javascript/dbdoc_engine/controllers/notification_controller.js +15 -0
- data/app/javascript/dbdoc_engine/controllers/schema_diagram_controller.js +1129 -0
- data/app/javascript/dbdoc_engine/controllers/select2_controller.js +67 -0
- data/app/javascript/dbdoc_engine/controllers/sidebar_controller.js +943 -0
- data/app/javascript/dbdoc_engine/controllers/table_details_controller.js +245 -0
- data/app/javascript/dbdoc_engine/controllers/table_group_validation_controller.js +148 -0
- data/app/javascript/dbdoc_engine/controllers/table_validation_controller.js +423 -0
- data/app/jobs/dbdoc_engine/application_job.rb +4 -0
- data/app/mailers/dbdoc_engine/application_mailer.rb +6 -0
- data/app/models/dbdoc_engine/application_record.rb +6 -0
- data/app/models/dbdoc_engine/concerns/soft_deletable.rb +30 -0
- data/app/models/dbdoc_engine/db_design_changelog.rb +44 -0
- data/app/models/dbdoc_engine/db_design_dynamic_column.rb +211 -0
- data/app/models/dbdoc_engine/db_design_dynamic_table.rb +124 -0
- data/app/models/dbdoc_engine/db_design_table_group.rb +88 -0
- data/app/models/dbdoc_engine/user.rb +21 -0
- data/app/queries/dbdoc_engine/admin_dashboard_queries.rb +71 -0
- data/app/queries/dbdoc_engine/db_design_changelog_queries.rb +68 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_column_queries.rb +37 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_commands.rb +106 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_queries.rb +194 -0
- data/app/queries/dbdoc_engine/db_design_table_group_queries.rb +154 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_export_service.rb +38 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_handler_service.rb +49 -0
- data/app/services/dbdoc_engine/db_design_dynamic_tables_service.rb +21 -0
- data/app/services/dbdoc_engine/error_handler_service.rb +43 -0
- data/app/services/dbdoc_engine/schema_rb_import_service.rb +194 -0
- data/app/services/dbdoc_engine/schema_rb_parser_service.rb +339 -0
- data/app/services/dbdoc_engine/table_filter_service.rb +35 -0
- data/app/services/dbdoc_engine/table_groups_service.rb +199 -0
- data/app/services/dbdoc_engine/table_management_service.rb +192 -0
- data/app/views/dbdoc_engine/admin/dashboard/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_rows.html.erb +22 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_table_headers.html.erb +8 -0
- data/app/views/dbdoc_engine/admin/dashboard/_filter_fields.html.erb +43 -0
- data/app/views/dbdoc_engine/admin/dashboard/index.html.erb +159 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_column_fields.html.erb +225 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_deleted_table_index.html.erb +110 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_foreign_key_fields.html.erb +51 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_form.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_recent_activity.html.erb +39 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_columns.html.erb +127 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_information.html.erb +99 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/deleted_tables.html.erb +95 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/edit.html.erb +23 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_all_to_excel.xlsx.axlsx +240 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_to_excel.xlsx.axlsx +135 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/new.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/show_table_info.html.erb +125 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_deleted_table_groups_list.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_form.html.erb +88 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_table_groups_list.html.erb +82 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/deleted_groups.html.erb +60 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/edit.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/index.html.erb +85 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/new.html.erb +26 -0
- data/app/views/dbdoc_engine/db_doc_sessions/new.html.erb +59 -0
- data/app/views/dbdoc_engine/home/changelog_details.html.erb +80 -0
- data/app/views/dbdoc_engine/home/changelogs.html.erb +20 -0
- data/app/views/dbdoc_engine/home/group_details.html.erb +94 -0
- data/app/views/dbdoc_engine/home/index.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_breadcrumb_navigation.html.erb +30 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_rows.html.erb +35 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_table_headers.html.erb +16 -0
- data/app/views/dbdoc_engine/home/partials/_column_headers.html.erb +23 -0
- data/app/views/dbdoc_engine/home/partials/_column_row.html.erb +157 -0
- data/app/views/dbdoc_engine/home/partials/_filter_form.html.erb +47 -0
- data/app/views/dbdoc_engine/home/partials/_group_section.html.erb +84 -0
- data/app/views/dbdoc_engine/home/partials/_pagination.html.erb +5 -0
- data/app/views/dbdoc_engine/home/partials/_stats_container.html.erb +46 -0
- data/app/views/dbdoc_engine/home/partials/_table_groups.html.erb +7 -0
- data/app/views/dbdoc_engine/home/partials/_table_information_section.html.erb +50 -0
- data/app/views/dbdoc_engine/home/partials/_table_section.html.erb +48 -0
- data/app/views/dbdoc_engine/home/table_details.html.erb +9 -0
- data/app/views/dbdoc_engine/schema_diagram/index.html.erb +102 -0
- data/app/views/dbdoc_engine/shared/_admin_header.html.erb +78 -0
- data/app/views/dbdoc_engine/shared/_header.html.erb +94 -0
- data/app/views/dbdoc_engine/shared/_js_translations.html.erb +3 -0
- data/app/views/dbdoc_engine/shared/_language_button.html.erb +14 -0
- data/app/views/dbdoc_engine/shared/_sidebar.html.erb +128 -0
- data/app/views/kaminari/dbdoc_engine/_first_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_gap.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_last_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_next_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_page.html.erb +9 -0
- data/app/views/kaminari/dbdoc_engine/_paginator.html.erb +17 -0
- data/app/views/kaminari/dbdoc_engine/_prev_page.html.erb +3 -0
- data/app/views/layouts/dbdoc_engine/application.html.erb +107 -0
- data/app/views/layouts/dbdoc_engine/header.html.erb +108 -0
- data/config/importmap.rb +11 -0
- data/config/locales/en.yml +307 -0
- data/config/locales/ja.yml +306 -0
- data/config/routes.rb +73 -0
- data/db/migrate/rails7/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails7/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails7/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails7/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails7/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails7/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/migrate/rails8/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails8/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails8/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails8/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails8/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails8/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/seeds.rb +28 -0
- data/lib/dbdoc_engine/engine.rb +57 -0
- data/lib/dbdoc_engine/version.rb +3 -0
- data/lib/dbdoc_engine.rb +9 -0
- data/lib/generators/dbdoc_engine/install/install_generator.rb +245 -0
- data/lib/generators/dbdoc_engine/uninstall/uninstall_generator.rb +196 -0
- data/lib/tasks/dbdoc_engine_tasks.rake +44 -0
- data/public/dbdoc_engine_assets/images/camel_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/dblogo.svg +4 -0
- data/public/dbdoc_engine_assets/images/japan_circle.png +0 -0
- data/public/dbdoc_engine_assets/images/king_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/login-bg.svg +44 -0
- data/public/dbdoc_engine_assets/images/logo.png +0 -0
- data/public/dbdoc_engine_assets/images/logo.svg +12 -0
- data/public/dbdoc_engine_assets/images/queen_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/soldier_chess_headd.png +0 -0
- data/public/dbdoc_engine_assets/images/uk_circle_transparent.png +0 -0
- metadata +415 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Model for dynamically created columns
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class DbDesignDynamicColumn < ApplicationRecord
|
|
4
|
+
include DbdocEngine::Concerns::SoftDeletable
|
|
5
|
+
self.table_name = 'db_design_dynamic_columns'
|
|
6
|
+
|
|
7
|
+
# Constants for relationship types
|
|
8
|
+
RELATIONSHIP_ONE_TO_ONE = 'one_to_one'.freeze
|
|
9
|
+
RELATIONSHIP_ONE_TO_MANY = 'one_to_many'.freeze
|
|
10
|
+
RELATIONSHIP_MANY_TO_ONE = 'many_to_one'.freeze
|
|
11
|
+
RELATIONSHIP_MANY_TO_MANY = 'many_to_many'.freeze
|
|
12
|
+
RELATIONSHIP_TYPES = [RELATIONSHIP_ONE_TO_ONE, RELATIONSHIP_ONE_TO_MANY, RELATIONSHIP_MANY_TO_ONE, RELATIONSHIP_MANY_TO_MANY].freeze
|
|
13
|
+
|
|
14
|
+
# Association: Each column belongs to a dynamic table
|
|
15
|
+
belongs_to :db_design_dynamic_table
|
|
16
|
+
|
|
17
|
+
# === Validations ===
|
|
18
|
+
|
|
19
|
+
# Ensures the column name is present, unique within the table, and follows naming conventions
|
|
20
|
+
validates :column_name,
|
|
21
|
+
presence: true,
|
|
22
|
+
uniqueness: { scope: :db_design_dynamic_table_id },
|
|
23
|
+
format: { with: /\A[a-z_]+\z/ }
|
|
24
|
+
|
|
25
|
+
# Ensures the physical column name is present
|
|
26
|
+
validates :physical_column_name, presence: true
|
|
27
|
+
|
|
28
|
+
# Ensures a data type is selected
|
|
29
|
+
validates :data_type, presence: true
|
|
30
|
+
|
|
31
|
+
# Ensures the creator's name is recorded
|
|
32
|
+
validates :created_by, presence: true
|
|
33
|
+
|
|
34
|
+
# Ensures foreign key constraints are properly defined when applicable
|
|
35
|
+
validates :foreign_table_name, presence: true, if: -> { is_foreign_key }
|
|
36
|
+
validates :foreign_column_name, presence: true, if: -> { is_foreign_key }
|
|
37
|
+
|
|
38
|
+
# Validates relationship_type when it's a foreign key
|
|
39
|
+
validates :relationship_type, inclusion: { in: RELATIONSHIP_TYPES }, if: -> { is_foreign_key && relationship_type.present? }
|
|
40
|
+
|
|
41
|
+
# === Callbacks ===
|
|
42
|
+
|
|
43
|
+
# Normalizes column name format before saving
|
|
44
|
+
before_save :normalize_column_name
|
|
45
|
+
|
|
46
|
+
# Prevents deletion if the column is referenced as a foreign key
|
|
47
|
+
before_destroy :check_foreign_key_dependencies
|
|
48
|
+
|
|
49
|
+
# Logs changes after creation, update, and deletion
|
|
50
|
+
after_create :log_creation
|
|
51
|
+
after_update :log_update
|
|
52
|
+
before_destroy :log_deletion
|
|
53
|
+
|
|
54
|
+
# Default scope to exclude soft-deleted records
|
|
55
|
+
default_scope { without_deleted }
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Converts column name to lowercase and replaces spaces with underscores
|
|
60
|
+
def normalize_column_name
|
|
61
|
+
self.column_name = column_name.downcase.gsub(/\s+/, '_')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Prevents deletion if the column is referenced as a foreign key in another table
|
|
65
|
+
def check_foreign_key_dependencies
|
|
66
|
+
table_name = db_design_dynamic_table.table_name
|
|
67
|
+
return unless DbdocEngine::DbDesignDynamicColumnQueries.column_referenced_as_foreign_key?(table_name, column_name)
|
|
68
|
+
|
|
69
|
+
errors.add(:base, "Cannot delete column '#{column_name}' because it is referenced as a foreign key in another table.")
|
|
70
|
+
throw :abort
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Logs column creation in the changelog
|
|
74
|
+
def log_creation
|
|
75
|
+
table_name = db_design_dynamic_table.table_name
|
|
76
|
+
entity_name = "#{table_name}.#{column_name}"
|
|
77
|
+
|
|
78
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
79
|
+
DbDesignChangelog::ACTION_CREATE,
|
|
80
|
+
DbDesignChangelog::ENTITY_COLUMN,
|
|
81
|
+
entity_name,
|
|
82
|
+
"Added column '#{column_name}' to table '#{table_name}'",
|
|
83
|
+
created_by,
|
|
84
|
+
nil,
|
|
85
|
+
{
|
|
86
|
+
column_name: column_name,
|
|
87
|
+
physical_column_name: physical_column_name,
|
|
88
|
+
data_type: data_type,
|
|
89
|
+
length: length,
|
|
90
|
+
decimal_precision: decimal_precision,
|
|
91
|
+
is_primary_key: is_primary_key,
|
|
92
|
+
is_foreign_key: is_foreign_key,
|
|
93
|
+
foreign_table_name: foreign_table_name,
|
|
94
|
+
foreign_column_name: foreign_column_name,
|
|
95
|
+
relationship_type: relationship_type,
|
|
96
|
+
not_null: not_null,
|
|
97
|
+
default_value: default_value,
|
|
98
|
+
sample_value: sample_value,
|
|
99
|
+
description: description
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Logs updates to column attributes in the changelog
|
|
105
|
+
def log_update
|
|
106
|
+
changes_data = collect_attribute_changes
|
|
107
|
+
return unless changes_data[:changes_desc].any?
|
|
108
|
+
|
|
109
|
+
# Use updated_by from the associated dynamic_table instead of created_by
|
|
110
|
+
user_who_updated = db_design_dynamic_table&.updated_by || updated_by || created_by
|
|
111
|
+
|
|
112
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
113
|
+
DbDesignChangelog::ACTION_UPDATE,
|
|
114
|
+
DbDesignChangelog::ENTITY_COLUMN,
|
|
115
|
+
changes_data[:entity_name],
|
|
116
|
+
"Updated column '#{column_name}' in table '#{changes_data[:table_name]}': #{changes_data[:changes_desc].join(', ')}",
|
|
117
|
+
user_who_updated,
|
|
118
|
+
changes_data[:previous_values],
|
|
119
|
+
changes_data[:new_values]
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Collects changes to column attributes for logging
|
|
124
|
+
def collect_attribute_changes
|
|
125
|
+
table_name = db_design_dynamic_table.table_name
|
|
126
|
+
entity_name = "#{table_name}.#{column_name}"
|
|
127
|
+
changes_desc = []
|
|
128
|
+
previous_values = {}
|
|
129
|
+
new_values = {}
|
|
130
|
+
|
|
131
|
+
# Mapping attribute names to human-readable labels for logging
|
|
132
|
+
attribute_mappings.each do |attr, label|
|
|
133
|
+
next unless saved_change_to_attribute?(attr.to_s)
|
|
134
|
+
|
|
135
|
+
old_val, new_val = saved_change_to_attribute(attr.to_s)
|
|
136
|
+
|
|
137
|
+
# Format boolean values for better readability
|
|
138
|
+
if [true, false].include?(old_val)
|
|
139
|
+
old_val = old_val ? 'Yes' : 'No'
|
|
140
|
+
new_val = new_val ? 'Yes' : 'No'
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
changes_desc << "#{label} changed from '#{old_val}' to '#{new_val}'"
|
|
144
|
+
previous_values[attr] = old_val
|
|
145
|
+
new_values[attr] = new_val
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
{
|
|
149
|
+
table_name: table_name,
|
|
150
|
+
entity_name: entity_name,
|
|
151
|
+
changes_desc: changes_desc,
|
|
152
|
+
previous_values: previous_values,
|
|
153
|
+
new_values: new_values
|
|
154
|
+
}
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Define attribute mappings for logging
|
|
158
|
+
def attribute_mappings
|
|
159
|
+
{
|
|
160
|
+
column_name: 'name',
|
|
161
|
+
physical_column_name: 'physical name',
|
|
162
|
+
data_type: 'data type',
|
|
163
|
+
length: 'length',
|
|
164
|
+
decimal_precision: 'decimal_precision',
|
|
165
|
+
is_primary_key: 'primary key status',
|
|
166
|
+
is_foreign_key: 'foreign key status',
|
|
167
|
+
foreign_table_name: 'foreign table',
|
|
168
|
+
foreign_column_name: 'foreign column',
|
|
169
|
+
relationship_type: 'relationship type',
|
|
170
|
+
is_candidate_key: 'candidate key status',
|
|
171
|
+
is_unique_key: 'unique key status',
|
|
172
|
+
is_indexed: 'index status',
|
|
173
|
+
not_null: 'nullable status',
|
|
174
|
+
default_value: 'default value',
|
|
175
|
+
sample_value: 'sample value',
|
|
176
|
+
description: 'description'
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Logs column deletion in the changelog
|
|
181
|
+
def log_deletion
|
|
182
|
+
table_name = db_design_dynamic_table.table_name
|
|
183
|
+
entity_name = "#{table_name}.#{column_name}"
|
|
184
|
+
|
|
185
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
186
|
+
DbDesignChangelog::ACTION_DELETE,
|
|
187
|
+
DbDesignChangelog::ENTITY_COLUMN,
|
|
188
|
+
entity_name,
|
|
189
|
+
"Deleted column '#{column_name}' from table '#{table_name}'",
|
|
190
|
+
created_by,
|
|
191
|
+
{
|
|
192
|
+
column_name: column_name,
|
|
193
|
+
physical_column_name: physical_column_name,
|
|
194
|
+
data_type: data_type,
|
|
195
|
+
length: length,
|
|
196
|
+
decimal_precision: decimal_precision,
|
|
197
|
+
is_primary_key: is_primary_key,
|
|
198
|
+
is_foreign_key: is_foreign_key,
|
|
199
|
+
foreign_table_name: foreign_table_name,
|
|
200
|
+
foreign_column_name: foreign_column_name,
|
|
201
|
+
relationship_type: relationship_type,
|
|
202
|
+
not_null: not_null,
|
|
203
|
+
default_value: default_value,
|
|
204
|
+
sample_value: sample_value,
|
|
205
|
+
description: description
|
|
206
|
+
},
|
|
207
|
+
nil
|
|
208
|
+
)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Model for dynamic tables
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class DbDesignDynamicTable < ApplicationRecord
|
|
4
|
+
# Include concern to support soft deletion functionality
|
|
5
|
+
include DbdocEngine::Concerns::SoftDeletable
|
|
6
|
+
self.table_name = 'db_design_dynamic_tables'
|
|
7
|
+
# Associations
|
|
8
|
+
belongs_to :db_design_table_group
|
|
9
|
+
has_many :db_design_dynamic_columns, dependent: :destroy
|
|
10
|
+
|
|
11
|
+
# Validations
|
|
12
|
+
validates :table_name, presence: true, uniqueness: { case_sensitive: false },
|
|
13
|
+
format: { with: /\A[a-z0-9_]+\z/ } # Only lowercase and underscores allowed
|
|
14
|
+
validates :created_by, presence: true
|
|
15
|
+
validates :physical_table_name, presence: true
|
|
16
|
+
validates :db_design_table_group_id, presence: true
|
|
17
|
+
|
|
18
|
+
# Accept nested attributes for associated models
|
|
19
|
+
accepts_nested_attributes_for :db_design_dynamic_columns, allow_destroy: true
|
|
20
|
+
|
|
21
|
+
# Lifecycle callbacks
|
|
22
|
+
before_save :normalize_table_name
|
|
23
|
+
before_destroy :prevent_deletion_if_referenced
|
|
24
|
+
before_destroy :log_deletion
|
|
25
|
+
after_create :log_creation
|
|
26
|
+
after_update :log_update
|
|
27
|
+
|
|
28
|
+
# Scope to exclude soft-deleted records
|
|
29
|
+
default_scope { without_deleted }
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Normalize the table name: downcase, remove extra spaces, convert spaces to underscores
|
|
34
|
+
def normalize_table_name
|
|
35
|
+
self.table_name = table_name.downcase.strip.gsub(/\s+/, '_').gsub(/_{2,}/, '_')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Prevent deletion if this table is referenced by any foreign key in another table
|
|
39
|
+
def prevent_deletion_if_referenced
|
|
40
|
+
DbDesignDynamicColumn.joins(:referencing_relations).where(db_design_dynamic_table_id: id)
|
|
41
|
+
# NOTE: You might want to add a condition to actually abort deletion with an error here.
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Log creation of a new dynamic table
|
|
45
|
+
def log_creation
|
|
46
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
47
|
+
DbDesignChangelog::ACTION_CREATE,
|
|
48
|
+
DbDesignChangelog::ENTITY_TABLE,
|
|
49
|
+
table_name,
|
|
50
|
+
"Created new table '#{table_name}'",
|
|
51
|
+
created_by,
|
|
52
|
+
nil,
|
|
53
|
+
{
|
|
54
|
+
table_name: table_name,
|
|
55
|
+
group_id: db_design_table_group_id,
|
|
56
|
+
description: description
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Log updates with a summary of changes
|
|
62
|
+
def log_update
|
|
63
|
+
changes_desc = []
|
|
64
|
+
previous_values = {}
|
|
65
|
+
new_values = {}
|
|
66
|
+
|
|
67
|
+
# Track table name change
|
|
68
|
+
if saved_change_to_table_name?
|
|
69
|
+
old_name, new_name = saved_change_to_table_name
|
|
70
|
+
changes_desc << "name changed from '#{old_name}' to '#{new_name}'"
|
|
71
|
+
previous_values[:table_name] = old_name
|
|
72
|
+
new_values[:table_name] = new_name
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Track table group change
|
|
76
|
+
if saved_change_to_db_design_table_group_id?
|
|
77
|
+
old_group_id, new_group_id = saved_change_to_db_design_table_group_id
|
|
78
|
+
old_group = DbdocEngine::DbDesignTableGroupQueries.find_group_name(old_group_id) || 'unknown'
|
|
79
|
+
new_group = DbdocEngine::DbDesignTableGroupQueries.find_group_name(new_group_id) || 'unknown'
|
|
80
|
+
changes_desc << "group changed from '#{old_group}' to '#{new_group}'"
|
|
81
|
+
previous_values[:group_id] = old_group_id
|
|
82
|
+
new_values[:group_id] = new_group_id
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Track description change
|
|
86
|
+
if saved_change_to_description?
|
|
87
|
+
old_desc, new_desc = saved_change_to_description
|
|
88
|
+
changes_desc << 'description updated'
|
|
89
|
+
previous_values[:description] = old_desc
|
|
90
|
+
new_values[:description] = new_desc
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Only log if there are changes
|
|
94
|
+
return unless changes_desc.any?
|
|
95
|
+
|
|
96
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
97
|
+
DbDesignChangelog::ACTION_UPDATE,
|
|
98
|
+
DbDesignChangelog::ENTITY_TABLE,
|
|
99
|
+
table_name,
|
|
100
|
+
"Updated table '#{table_name}': #{changes_desc.join(', ')}",
|
|
101
|
+
updated_by,
|
|
102
|
+
previous_values,
|
|
103
|
+
new_values
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Log deletion of the dynamic table
|
|
108
|
+
def log_deletion
|
|
109
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
110
|
+
DbDesignChangelog::ACTION_DELETE,
|
|
111
|
+
DbDesignChangelog::ENTITY_TABLE,
|
|
112
|
+
table_name,
|
|
113
|
+
"Deleted table '#{table_name}'",
|
|
114
|
+
updated_by,
|
|
115
|
+
{
|
|
116
|
+
table_name: table_name,
|
|
117
|
+
group_id: db_design_table_group_id,
|
|
118
|
+
description: description
|
|
119
|
+
},
|
|
120
|
+
nil
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Model representing a group of dynamic tables
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class DbDesignTableGroup < ApplicationRecord
|
|
4
|
+
# Include concern to enable soft deletion functionality
|
|
5
|
+
include DbdocEngine::Concerns::SoftDeletable
|
|
6
|
+
self.table_name = 'db_design_table_groups'
|
|
7
|
+
# Associations
|
|
8
|
+
has_many :db_design_dynamic_tables, dependent: :destroy # Deleting a group will delete all its associated tables
|
|
9
|
+
|
|
10
|
+
# Validations
|
|
11
|
+
validates :group_name, presence: true, uniqueness: true # Ensure unique group name
|
|
12
|
+
validates :group_color, presence: true # Group must have a color assigned
|
|
13
|
+
validates :created_by, presence: true, if: :new_record? # Track who created the group
|
|
14
|
+
validates :updated_by, presence: true, unless: :new_record?, on: :update
|
|
15
|
+
|
|
16
|
+
# Callbacks
|
|
17
|
+
after_create :log_creation # Log group creation
|
|
18
|
+
after_update :log_update # Log group updates
|
|
19
|
+
before_destroy :log_deletion # Log group deletion before removing it
|
|
20
|
+
|
|
21
|
+
# Scope to exclude soft-deleted records from default queries
|
|
22
|
+
default_scope { without_deleted }
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# Log the creation of a new table group
|
|
27
|
+
def log_creation
|
|
28
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
29
|
+
DbDesignChangelog::ACTION_CREATE,
|
|
30
|
+
DbDesignChangelog::ENTITY_TABLE_GROUP,
|
|
31
|
+
group_name,
|
|
32
|
+
"Created new table group '#{group_name}'",
|
|
33
|
+
created_by || updated_by || 'system', # Default to 'system' if no user info is available
|
|
34
|
+
nil, # No previous values for creation
|
|
35
|
+
{ group_name: group_name, group_color: group_color } # New values being logged
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Log changes made to the table group
|
|
40
|
+
def log_update
|
|
41
|
+
changes_desc = [] # Store descriptions of changes
|
|
42
|
+
previous_values = {} # Store old values
|
|
43
|
+
new_values = {} # Store new values
|
|
44
|
+
|
|
45
|
+
# Track group name changes
|
|
46
|
+
if saved_change_to_group_name?
|
|
47
|
+
old_name, new_name = saved_change_to_group_name
|
|
48
|
+
changes_desc << "name changed from '#{old_name}' to '#{new_name}'"
|
|
49
|
+
previous_values[:group_name] = old_name
|
|
50
|
+
new_values[:group_name] = new_name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Track group color changes
|
|
54
|
+
if saved_change_to_group_color?
|
|
55
|
+
old_color, new_color = saved_change_to_group_color
|
|
56
|
+
changes_desc << "color changed from '#{old_color}' to '#{new_color}'"
|
|
57
|
+
previous_values[:group_color] = old_color
|
|
58
|
+
new_values[:group_color] = new_color
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Only log updates if there are actual changes
|
|
62
|
+
return unless changes_desc.any?
|
|
63
|
+
|
|
64
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
65
|
+
DbDesignChangelog::ACTION_UPDATE,
|
|
66
|
+
DbDesignChangelog::ENTITY_TABLE_GROUP,
|
|
67
|
+
group_name,
|
|
68
|
+
"Updated table group '#{group_name}': #{changes_desc.join(', ')}",
|
|
69
|
+
updated_by || 'system',
|
|
70
|
+
previous_values,
|
|
71
|
+
new_values
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Log deletion of a table group
|
|
76
|
+
def log_deletion
|
|
77
|
+
DbdocEngine::DbDesignChangelogQueries.log_change(
|
|
78
|
+
DbDesignChangelog::ACTION_DELETE,
|
|
79
|
+
DbDesignChangelog::ENTITY_TABLE_GROUP,
|
|
80
|
+
group_name,
|
|
81
|
+
"Deleted table group '#{group_name}'",
|
|
82
|
+
updated_by || 'system',
|
|
83
|
+
{ group_name: group_name, group_color: group_color }, # Old values being removed
|
|
84
|
+
nil # No new values after deletion
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module DbdocEngine
|
|
2
|
+
class User < ApplicationRecord
|
|
3
|
+
self.table_name = "dbdoc_engine_users"
|
|
4
|
+
has_secure_password
|
|
5
|
+
|
|
6
|
+
validates :username, presence: true, uniqueness: true
|
|
7
|
+
validates :role, presence: true, inclusion: { in: %w[user admin superadmin] }
|
|
8
|
+
|
|
9
|
+
def admin?
|
|
10
|
+
role == "admin"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def superadmin?
|
|
14
|
+
role == "superadmin"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def admin_or_higher?
|
|
18
|
+
admin? || superadmin?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# app/queries/admin_dashboard_queries.rb
|
|
2
|
+
|
|
3
|
+
# Service class for handling admin dashboard statistics and data formatting
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
class AdminDashboardQueries
|
|
6
|
+
class << self
|
|
7
|
+
# Get total count of table groups
|
|
8
|
+
# @return [Integer] Number of existing table groups
|
|
9
|
+
def groups_count
|
|
10
|
+
DbDesignTableGroup.count
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Get total count of dynamic tables
|
|
14
|
+
# @return [Integer] Number of existing tables
|
|
15
|
+
def tables_count
|
|
16
|
+
DbDesignDynamicTable.count
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get total count of columns across all tables
|
|
20
|
+
# @return [Integer] Number of existing columns
|
|
21
|
+
def columns_count
|
|
22
|
+
DbDesignDynamicColumn.count
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get filtered changelogs for audit history
|
|
26
|
+
# @param params [Hash] Filter parameters:
|
|
27
|
+
# - :action_type (optional) Filter by specific action type
|
|
28
|
+
# @return [ActiveRecord::Relation] Filtered changelogs ordered by timestamp
|
|
29
|
+
def filtered_changelogs(params)
|
|
30
|
+
scope = DbDesignChangelog.order(change_timestamp: :desc)
|
|
31
|
+
scope = scope.where(action_type: params[:action_type]) if params[:action_type].present?
|
|
32
|
+
scope
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Format changelog data for chart visualization
|
|
36
|
+
# @param changelogs [Array<DbDesignChangelog>] Collection of changelog records
|
|
37
|
+
# @return [Hash] Structured data for chart rendering with:
|
|
38
|
+
# - labels: Chart category labels
|
|
39
|
+
# - datasets: Chart data series with colors and values
|
|
40
|
+
def prepare_chart_data(changelogs)
|
|
41
|
+
# Define entity types for chart categorization
|
|
42
|
+
entities = %w[table_group table column]
|
|
43
|
+
|
|
44
|
+
# Extract unique action types from changelogs
|
|
45
|
+
action_types = changelogs.pluck(:action_type).uniq
|
|
46
|
+
|
|
47
|
+
# Build datasets for each action type
|
|
48
|
+
datasets = action_types.map do |action|
|
|
49
|
+
{
|
|
50
|
+
label: action.titleize,
|
|
51
|
+
# Count occurrences per entity type for this action
|
|
52
|
+
data: entities.map { |e| changelogs.count { |log| log.action_type == action && log.entity_type == e } },
|
|
53
|
+
# Assign color based on action type
|
|
54
|
+
backgroundColor: case action
|
|
55
|
+
when 'create' then '#4CAF50' # Green
|
|
56
|
+
when 'update' then '#FFC107' # Amber
|
|
57
|
+
when 'delete' then '#F44336' # Red
|
|
58
|
+
else '#CCCCCC' # Default gray
|
|
59
|
+
end
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Return structured chart data
|
|
64
|
+
{
|
|
65
|
+
labels: %w[Groups Tables Columns], # X-axis labels
|
|
66
|
+
datasets: datasets # Data series collection
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# queries/db_design_changelog_queries.rb
|
|
2
|
+
|
|
3
|
+
# Query class handling database operations for change logs
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
class DbDesignChangelogQueries
|
|
6
|
+
class << self
|
|
7
|
+
# Fetch filtered changelogs based on provided parameters
|
|
8
|
+
# @param params [Hash] Filter parameters including:
|
|
9
|
+
# - entity_type: Filter by entity type (table_group/table/column)
|
|
10
|
+
# - entity_name: Partial match for entity name
|
|
11
|
+
# - action_type: Filter by action type (create/update/delete)
|
|
12
|
+
# - date_from: Start date filter
|
|
13
|
+
# - date_to: End date filter
|
|
14
|
+
# @return [ActiveRecord::Relation] Filtered and ordered changelogs
|
|
15
|
+
def filtered_changelogs(params = {})
|
|
16
|
+
scope = DbDesignChangelog.all
|
|
17
|
+
|
|
18
|
+
scope = scope.where(entity_type: params[:entity_type]) if params[:entity_type].present?
|
|
19
|
+
scope = scope.where('entity_name ILIKE ?', "%#{params[:entity_name]}%") if params[:entity_name].present?
|
|
20
|
+
scope = scope.where(action_type: params[:action_type]) if params[:action_type].present?
|
|
21
|
+
|
|
22
|
+
if params[:date_from].present? && params[:date_to].present?
|
|
23
|
+
from_date = Date.parse(params[:date_from]).beginning_of_day
|
|
24
|
+
to_date = Date.parse(params[:date_to]).end_of_day
|
|
25
|
+
scope = scope.where(change_timestamp: from_date..to_date)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
scope.order(change_timestamp: :desc)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Find a specific changelog entry by ID
|
|
32
|
+
# @param id [Integer] Changelog ID to find
|
|
33
|
+
# @return [DbDesignChangelog, nil] Found changelog or nil
|
|
34
|
+
def find_changelog(id)
|
|
35
|
+
DbDesignChangelog.find_by(id: id)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Create a new changelog entry with audit information
|
|
39
|
+
# @param action_type [String] Type of action performed
|
|
40
|
+
# @param entity_type [String] Type of entity affected
|
|
41
|
+
# @param entity_name [String] Name of the affected entity
|
|
42
|
+
# @param description [String] Human-readable change description
|
|
43
|
+
# @param changed_by [String] Identifier of who made the change
|
|
44
|
+
# @param previous_values [Hash] Optional previous state values
|
|
45
|
+
# @param new_values [Hash] Optional new state values
|
|
46
|
+
# @return [DbDesignChangelog] Newly created changelog record
|
|
47
|
+
def log_change(action_type, entity_type, entity_name, description, changed_by, previous_values = nil, new_values = nil)
|
|
48
|
+
DbDesignChangelog.create!(
|
|
49
|
+
change_timestamp: Time.current,
|
|
50
|
+
action_type: action_type,
|
|
51
|
+
entity_type: entity_type,
|
|
52
|
+
entity_name: entity_name,
|
|
53
|
+
description: description,
|
|
54
|
+
changed_by: changed_by,
|
|
55
|
+
previous_values: previous_values,
|
|
56
|
+
new_values: new_values
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get group name by ID through TableGroupQueries
|
|
61
|
+
# @param id [Integer] Group ID to lookup
|
|
62
|
+
# @return [String, nil] Group name or nil if not found
|
|
63
|
+
def find_group_name(id)
|
|
64
|
+
DbDesignTableGroupQueries.find_group_name(id)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# queries/db_design_dynamic_column_queries.rb
|
|
2
|
+
|
|
3
|
+
# Query class for dynamic column-related database operations
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
class DbDesignDynamicColumnQueries
|
|
6
|
+
# Returns the DbDesignDynamicColumn model (centralized reference)
|
|
7
|
+
def self.model
|
|
8
|
+
DbDesignDynamicColumn
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# Counts the number of columns in the given table.
|
|
13
|
+
# Uses .size to leverage eager-loaded associations when available,
|
|
14
|
+
# avoiding N+1 COUNT queries in loops.
|
|
15
|
+
def count_columns_in_table(table)
|
|
16
|
+
table.db_design_dynamic_columns.size
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Checks if a column is referenced as a foreign key in any (non-deleted) table
|
|
20
|
+
def column_referenced_as_foreign_key?(table_name, column_name)
|
|
21
|
+
# Joins with parent table, filters by foreign key reference and non-deleted tables
|
|
22
|
+
model.joins(:db_design_dynamic_table)
|
|
23
|
+
.where(
|
|
24
|
+
foreign_table_name: table_name,
|
|
25
|
+
foreign_column_name: column_name,
|
|
26
|
+
db_design_dynamic_tables: { deleted_at: nil }
|
|
27
|
+
)
|
|
28
|
+
.exists?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def all_foreign_keys_with_tables
|
|
32
|
+
model.joins(:db_design_dynamic_table)
|
|
33
|
+
.where(is_foreign_key: true, db_design_dynamic_tables: { deleted_at: nil })
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|