active_version 1.0.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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +36 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +492 -0
  5. data/SECURITY.md +29 -0
  6. data/lib/active_version/adapters/active_record/audits.rb +36 -0
  7. data/lib/active_version/adapters/active_record/base.rb +37 -0
  8. data/lib/active_version/adapters/active_record/revisions.rb +49 -0
  9. data/lib/active_version/adapters/active_record/translations.rb +45 -0
  10. data/lib/active_version/adapters/active_record.rb +10 -0
  11. data/lib/active_version/adapters/sequel/versioning.rb +282 -0
  12. data/lib/active_version/adapters/sequel.rb +9 -0
  13. data/lib/active_version/adapters.rb +5 -0
  14. data/lib/active_version/audits/audit_record/callbacks.rb +180 -0
  15. data/lib/active_version/audits/audit_record/serializers.rb +49 -0
  16. data/lib/active_version/audits/audit_record.rb +522 -0
  17. data/lib/active_version/audits/has_audits/audit_callbacks.rb +46 -0
  18. data/lib/active_version/audits/has_audits/audit_combiner.rb +212 -0
  19. data/lib/active_version/audits/has_audits/audit_writer.rb +282 -0
  20. data/lib/active_version/audits/has_audits/change_filters.rb +114 -0
  21. data/lib/active_version/audits/has_audits/database_adapter_helper.rb +86 -0
  22. data/lib/active_version/audits/has_audits.rb +891 -0
  23. data/lib/active_version/audits/sql_builder.rb +263 -0
  24. data/lib/active_version/audits.rb +10 -0
  25. data/lib/active_version/column_mapper.rb +92 -0
  26. data/lib/active_version/configuration.rb +124 -0
  27. data/lib/active_version/database/triggers/postgresql.rb +243 -0
  28. data/lib/active_version/database.rb +7 -0
  29. data/lib/active_version/instrumentation.rb +226 -0
  30. data/lib/active_version/migrators/audited.rb +84 -0
  31. data/lib/active_version/migrators/base.rb +191 -0
  32. data/lib/active_version/migrators.rb +8 -0
  33. data/lib/active_version/query.rb +105 -0
  34. data/lib/active_version/railtie.rb +17 -0
  35. data/lib/active_version/revisions/has_revisions/revision_manipulation.rb +499 -0
  36. data/lib/active_version/revisions/has_revisions/revision_queries.rb +182 -0
  37. data/lib/active_version/revisions/has_revisions.rb +443 -0
  38. data/lib/active_version/revisions/revision_record.rb +287 -0
  39. data/lib/active_version/revisions/sql_builder.rb +266 -0
  40. data/lib/active_version/revisions.rb +10 -0
  41. data/lib/active_version/runtime.rb +148 -0
  42. data/lib/active_version/sharding/connection_router.rb +20 -0
  43. data/lib/active_version/sharding.rb +7 -0
  44. data/lib/active_version/tasks/active_version.rake +29 -0
  45. data/lib/active_version/translations/has_translations.rb +350 -0
  46. data/lib/active_version/translations/translation_record.rb +258 -0
  47. data/lib/active_version/translations.rb +9 -0
  48. data/lib/active_version/version.rb +3 -0
  49. data/lib/active_version/version_registry.rb +87 -0
  50. data/lib/active_version.rb +329 -0
  51. data/lib/generators/active_version/audits/audits_generator.rb +65 -0
  52. data/lib/generators/active_version/audits/templates/audit_model.rb.erb +16 -0
  53. data/lib/generators/active_version/audits/templates/migration_jsonb.rb.erb +33 -0
  54. data/lib/generators/active_version/audits/templates/migration_table.rb.erb +34 -0
  55. data/lib/generators/active_version/install/install_generator.rb +19 -0
  56. data/lib/generators/active_version/install/templates/initializer.rb.erb +38 -0
  57. data/lib/generators/active_version/revisions/revisions_generator.rb +71 -0
  58. data/lib/generators/active_version/revisions/templates/backfill_migration.rb.erb +19 -0
  59. data/lib/generators/active_version/revisions/templates/migration.rb.erb +20 -0
  60. data/lib/generators/active_version/revisions/templates/revision_model.rb.erb +8 -0
  61. data/lib/generators/active_version/translations/templates/migration.rb.erb +16 -0
  62. data/lib/generators/active_version/translations/templates/translation_model.rb.erb +15 -0
  63. data/lib/generators/active_version/translations/translations_generator.rb +73 -0
  64. data/lib/generators/active_version/triggers/templates/migration.rb.erb +100 -0
  65. data/lib/generators/active_version/triggers/triggers_generator.rb +74 -0
  66. data/sig/active_version/advanced.rbs +51 -0
  67. data/sig/active_version/audits.rbs +128 -0
  68. data/sig/active_version/configuration.rbs +38 -0
  69. data/sig/active_version/core.rbs +53 -0
  70. data/sig/active_version/instrumentation.rbs +17 -0
  71. data/sig/active_version/registry_and_mapping.rbs +18 -0
  72. data/sig/active_version/revisions.rbs +70 -0
  73. data/sig/active_version/runtime.rbs +29 -0
  74. data/sig/active_version/translations.rbs +43 -0
  75. data/sig/active_version.rbs +3 -0
  76. metadata +443 -0
@@ -0,0 +1,86 @@
1
+ module ActiveVersion
2
+ module Audits
3
+ module HasAudits
4
+ # Helper methods for database adapter-agnostic operations
5
+ # Relies on ActiveRecord's built-in adapter abstractions
6
+ module DatabaseAdapterHelper
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # Check if a column is a JSON/JSONB type (not text)
11
+ def json_column?(model_class, column_name)
12
+ column = model_class.columns_hash[column_name.to_s]
13
+ return false unless column
14
+
15
+ # Check column type
16
+ type = column.type.to_s.downcase
17
+ type == "json" || type == "jsonb"
18
+ end
19
+
20
+ # Get adapter-agnostic condition to filter out empty JSON objects
21
+ # Uses ActiveRecord's abstractions (where.not) which handle adapter differences
22
+ def filter_empty_json_condition(relation, column_name, model_class = nil)
23
+ model_class ||= relation.klass
24
+ column = model_class.columns_hash[column_name.to_s]
25
+
26
+ # Check column type to determine best approach
27
+ if column
28
+ column_type = column.type.to_s.downcase
29
+
30
+ case column_type
31
+ when "jsonb", "json"
32
+ # For JSON/JSONB columns, use string comparison
33
+ # ActiveRecord's where.not handles adapter-specific SQL generation
34
+ relation.where.not(column_name => "{}")
35
+ else
36
+ # For TEXT columns, use Arel function for length check
37
+ # ActiveRecord adapters will translate this appropriately
38
+ table = model_class.arel_table
39
+ column_arel = table[column_name.to_sym]
40
+ length_func = Arel::Nodes::NamedFunction.new("LENGTH", [column_arel])
41
+ relation.where(length_func.gt(2))
42
+ end
43
+ else
44
+ # Fallback: use length check via Arel
45
+ table = model_class.arel_table
46
+ column_arel = table[column_name.to_sym]
47
+ length_func = Arel::Nodes::NamedFunction.new("LENGTH", [column_arel])
48
+ relation.where(length_func.gt(2))
49
+ end
50
+ end
51
+
52
+ # Get adapter-agnostic condition for checking if JSON is NOT empty
53
+ # Returns an Arel node that can be used in where clauses
54
+ def not_empty_json_condition(column_name, model_class = ActiveRecord::Base)
55
+ column = model_class.columns_hash[column_name.to_s]
56
+ table = model_class.arel_table
57
+ column_arel = table[column_name.to_sym]
58
+
59
+ if column
60
+ column_type = column.type.to_s.downcase
61
+
62
+ case column_type
63
+ when "jsonb", "json"
64
+ # For JSON/JSONB: use Arel's not_eq - ActiveRecord adapters handle this
65
+ column_arel.not_eq("{}")
66
+ else
67
+ # For TEXT: use Arel function for length (adapter-agnostic)
68
+ length_func = Arel::Nodes::NamedFunction.new("LENGTH", [column_arel])
69
+ length_func.gt(2)
70
+ end
71
+ else
72
+ # Fallback: use length check via Arel
73
+ length_func = Arel::Nodes::NamedFunction.new("LENGTH", [column_arel])
74
+ length_func.gt(2)
75
+ end
76
+ end
77
+ end
78
+
79
+ # Instance methods
80
+ def json_column?(column_name)
81
+ self.class.json_column?(self.class, column_name)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end