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

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

Overview

Mixin that adds all audit log query fields to a host application’s QueryType.

Include in your QueryType:

class Types::QueryType < Types::BaseObject
  include RailsAuditLog::Graphql::Queries::AuditLogEntriesQueryMixin
end

This adds the following fields to the schema:

  • auditLogEntry(id:) — fetch a single entry by ID

  • auditLogEntries(…) — offset-paginated list with filters

  • auditLogEntriesConnection(…) — cursor-paginated Relay connection

  • auditLogEntriesCount(…) — count matching entries

  • auditLogReify(itemType:, itemId:, at:) — reconstruct record state at a point in time

See Also:

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 24

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) ⇒ ActiveRecord::Relation

Resolves the auditLogEntries field.

Returns:

  • (ActiveRecord::Relation)


125
126
127
128
129
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 125

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) ⇒ ActiveRecord::Relation

Resolves the auditLogEntriesConnection field.

Returns:

  • (ActiveRecord::Relation)


134
135
136
137
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 134

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) ⇒ Integer

Resolves the auditLogEntriesCount field.

Returns:

  • (Integer)


163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 163

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) ⇒ RailsAuditLog::AuditLogEntry?

Resolves the auditLogEntry field.

Parameters:

  • id (String)

    the entry ID

  • for_tenant (String, nil) (defaults to: nil)

    optional tenant scope

Returns:

  • (RailsAuditLog::AuditLogEntry, nil)


115
116
117
118
119
120
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 115

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) ⇒ Hash?

Resolves the auditLogReify field. Returns the reconstructed attribute hash for item_type/item_id as of at, or nil when no entry exists.

Parameters:

  • item_type (String)
  • item_id (String)
  • at (Time)
  • for_tenant (String, nil) (defaults to: nil)

Returns:

  • (Hash, nil)


147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb', line 147

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