Module: RailsAuditLog::Graphql::Queries::AuditLogEntriesQueryMixin

Defined in:
lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 7

def self.included(base)
  base.field(
    :audit_log_entry,
    RailsAuditLog::Graphql::Types::AuditLogEntryType,
    null: true,
    description: "Fetch a single audit log entry by ID. Returns nil if not found.",
    resolver_method: :resolve_audit_log_entry
  ) do
    argument :id, GraphQL::Types::ID, required: true,
      description: "ID of the audit log entry."
    argument :for_tenant, String, required: false,
      description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
  end

  base.field(
    :audit_log_entries,
    [RailsAuditLog::Graphql::Types::AuditLogEntryType, null: false],
    null: false,
    description: "List audit log entries with optional filters. Offset-paginated.",
    resolver_method: :resolve_audit_log_entries
  ) do
    argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
    argument :item_type, String, required: false, description: "Filter by audited model class name."
    argument :item_id, GraphQL::Types::ID, required: false, description: "Filter by audited record ID."
    argument :actor_id, GraphQL::Types::ID, required: false, description: "Filter by actor ID."
    argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
    argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Return entries created at or after this time."
    argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
    argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
    argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
    argument :for_tenant, String, required: false,
      description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
    argument :page, GraphQL::Types::Int, required: false, default_value: 1, description: "Page number (1-based)."
    argument :per_page, GraphQL::Types::Int, required: false, default_value: 25, description: "Number of results per page."
  end

  base.field(
    :audit_log_entries_connection,
    RailsAuditLog::Graphql::Types::AuditLogEntryType.connection_type,
    null: false,
    description: "List audit log entries with optional filters. Cursor-paginated (Relay connection).",
    resolver_method: :resolve_audit_log_entries_connection
  ) do
    argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
    argument :item_type, String, required: false, description: "Filter by audited model class name."
    argument :item_id, GraphQL::Types::ID, required: false, description: "Filter by audited record ID."
    argument :actor_id, GraphQL::Types::ID, required: false, description: "Filter by actor ID."
    argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
    argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Return entries created at or after this time."
    argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
    argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
    argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
    argument :for_tenant, String, required: false,
      description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
  end

  base.field(
    :audit_log_reify,
    Types::AuditLogJsonScalar,
    null: true,
    description: "Reconstruct the attribute state of a record at a given point in time. Returns nil when no entry exists at or before `at`, or when the record was destroyed.",
    resolver_method: :resolve_audit_log_reify
  ) do
    argument :item_type, String, required: true, description: "The audited model class name."
    argument :item_id, GraphQL::Types::ID, required: true, description: "The audited record ID."
    argument :at, GraphQL::Types::ISO8601DateTime, required: true, description: "Reconstruct state as of this time."
    argument :for_tenant, String, required: false,
      description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
  end

  base.field(
    :audit_log_entries_count,
    GraphQL::Types::Int,
    null: false,
    description: "Count audit log entries with optional filters. Respects auto-tenant when RailsAuditLog.current_tenant is configured.",
    resolver_method: :resolve_audit_log_entries_count
  ) do
    argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
    argument :item_type, String, required: false, description: "Filter by audited model class name."
    argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
    argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Count entries created at or after this time."
    argument :for_tenant, String, required: false,
      description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
  end
end

Instance Method Details

#resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil, page: 1, per_page: 25) ⇒ Object



100
101
102
103
104
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 100

def resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil, page: 1, per_page: 25)
  check_authentication!
  scope = build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, actor_type: actor_type, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
  scope.limit(per_page).offset((page - 1) * per_page)
end

#resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil) ⇒ Object



106
107
108
109
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 106

def resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
  check_authentication!
  build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, actor_type: actor_type, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
end

#resolve_audit_log_entries_count(event: nil, item_type: nil, actor_type: nil, since: nil, for_tenant: nil) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 124

def resolve_audit_log_entries_count(event: nil, item_type: nil, actor_type: nil, since: nil, for_tenant: nil)
  check_authentication!
  scope = RailsAuditLog::AuditLogEntry.all
  scope = scope.where(event: event) if event
  scope = scope.where(item_type: item_type) if item_type
  scope = scope.where(actor_type: actor_type) if actor_type
  scope = scope.where("created_at >= ?", since) if since
  tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
  scope = scope.for_tenant(tenant_id) if tenant_id
  scope.count
end

#resolve_audit_log_entry(id:, for_tenant: nil) ⇒ Object



93
94
95
96
97
98
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 93

def resolve_audit_log_entry(id:, for_tenant: nil)
  check_authentication!
  tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
  base = tenant_id ? RailsAuditLog::AuditLogEntry.for_tenant(tenant_id) : RailsAuditLog::AuditLogEntry
  base.find_by(id: id)
end

#resolve_audit_log_reify(item_type:, item_id:, at:, for_tenant: nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 111

def resolve_audit_log_reify(item_type:, item_id:, at:, for_tenant: nil)
  check_authentication!
  tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
  scope = RailsAuditLog::AuditLogEntry
    .where(item_type: item_type, item_id: item_id)
    .where("created_at <= ?", at)
  scope = scope.for_tenant(tenant_id) if tenant_id
  entry = scope.order(created_at: :desc, id: :desc).first
  return nil if entry.nil? || entry.event == "destroy"
  to_attrs = (entry.object_changes || {}).transform_values { |v| v[1] }
  entry.object.present? ? entry.object.merge(to_attrs) : to_attrs
end