rails_audit_log-graphql 0.4.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +38 -0
- data/ROADMAP.md +0 -8
- data/lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb +40 -7
- data/lib/rails_audit_log/graphql/version.rb +1 -1
- data/sig/rails_audit_log/graphql.rbs +12 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f64cce54638f8999c6489e0881a1fedfcb447b0b5b8f52270a0d8247719c8f19
|
|
4
|
+
data.tar.gz: 4b1225952a5a6adce3a5a03b804360765b0c70b9ad9a9688db96ba34139430c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b54b242a022b49d1917dd3c0370f96bde5ec210dad8959a34bc424132c7efd97aa0e1f781cebd0eaf21056b3b29c2c0c9632c08e94a4b0e2da851afe57044e5
|
|
7
|
+
data.tar.gz: fb448e67961e641eb6ce89081e832082cfa886856ccbd5f4d5de767d1bd21835d38034e6dd55a4d00b1f633f58da6a094e5d8e4e4886c24a6aece095386023f2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `forTenant:` argument on `auditLogEntry`, `auditLogEntries`, and `auditLogEntriesConnection` — explicitly scope results to a tenant ID; overrides auto-tenant
|
|
8
|
+
- Auto-tenant scoping — when `RailsAuditLog.current_tenant` is configured, all queries automatically filter to the current tenant without requiring an explicit argument
|
|
9
|
+
- `auditLogEntriesCount(event:, itemType:, since:)` — new aggregation query returning the count of matching entries; respects auto-tenant
|
|
10
|
+
|
|
3
11
|
## [0.4.0] - 2026-06-04
|
|
4
12
|
|
|
5
13
|
### Added
|
data/README.md
CHANGED
|
@@ -20,6 +20,8 @@ A [graphql-ruby](https://graphql-ruby.org) API layer for the [`rails_audit_log`]
|
|
|
20
20
|
- [auditLogEntry](#auditlogentryid-id-auditlogentry)
|
|
21
21
|
- [auditLogEntries](#auditlogentries-auditlogentry)
|
|
22
22
|
- [auditLogEntriesConnection](#auditlogentriesconnection-auditlogentryconnection)
|
|
23
|
+
- [auditLogEntriesCount](#auditlogentriescount-int)
|
|
24
|
+
- [Tenant scoping](#tenant-scoping)
|
|
23
25
|
- [Authentication](#authentication)
|
|
24
26
|
- [Subscriptions](#subscriptions)
|
|
25
27
|
- [AuditLogSubscriptionsMixin](#auditlogsubscriptionsmixin)
|
|
@@ -152,6 +154,7 @@ List entries with optional filters and offset pagination.
|
|
|
152
154
|
| `until` | `ISO8601DateTime` | — | Return entries created at or before this time |
|
|
153
155
|
| `touching` | `String` | — | Filter to entries that changed a specific attribute |
|
|
154
156
|
| `orderBy` | `AuditLogEntrySortInput` | `CREATED_AT DESC` | Sort field and direction |
|
|
157
|
+
| `forTenant` | `String` | — | Scope to a specific tenant ID; overrides auto-tenant |
|
|
155
158
|
| `page` | `Int` | `1` | Page number (1-based) |
|
|
156
159
|
| `perPage` | `Int` | `25` | Results per page |
|
|
157
160
|
|
|
@@ -167,6 +170,7 @@ Same filters as `auditLogEntries`, but returns a [Relay-style connection](https:
|
|
|
167
170
|
| `itemType` | `String` | Filter by audited model class name |
|
|
168
171
|
| `itemId` | `ID` | Filter by audited record ID |
|
|
169
172
|
| `actorId` | `ID` | Filter by actor ID |
|
|
173
|
+
| `forTenant` | `String` | Scope to a specific tenant ID; overrides auto-tenant |
|
|
170
174
|
| `first` | `Int` | Return the first N edges after `after` |
|
|
171
175
|
| `after` | `String` | Cursor to paginate forward from |
|
|
172
176
|
| `last` | `Int` | Return the last N edges before `before` |
|
|
@@ -207,6 +211,40 @@ Results are ordered by `created_at DESC`.
|
|
|
207
211
|
|
|
208
212
|
[↑ Back to top](#table-of-contents)
|
|
209
213
|
|
|
214
|
+
#### `auditLogEntriesCount(...): Int!`
|
|
215
|
+
|
|
216
|
+
Returns the count of matching audit log entries. Respects auto-tenant when `RailsAuditLog.current_tenant` is configured.
|
|
217
|
+
|
|
218
|
+
| Argument | Type | Description |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `event` | `String` | Filter by event type (`create`, `update`, `destroy`) |
|
|
221
|
+
| `itemType` | `String` | Filter by audited model class name |
|
|
222
|
+
| `since` | `ISO8601DateTime` | Count entries created at or after this time |
|
|
223
|
+
|
|
224
|
+
```graphql
|
|
225
|
+
{ auditLogEntriesCount(event: "update", itemType: "Post") }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
[↑ Back to top](#table-of-contents)
|
|
229
|
+
|
|
230
|
+
#### Tenant scoping
|
|
231
|
+
|
|
232
|
+
When `RailsAuditLog.current_tenant` is configured, all queries automatically filter to the current tenant:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
RailsAuditLog.configure do |c|
|
|
236
|
+
c.current_tenant { Current.tenant_id }
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
To override or explicitly specify a tenant per query, use the `forTenant:` argument (available on `auditLogEntry`, `auditLogEntries`, and `auditLogEntriesConnection`):
|
|
241
|
+
|
|
242
|
+
```graphql
|
|
243
|
+
{ auditLogEntries(forTenant: "acme") { id event } }
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
[↑ Back to top](#table-of-contents)
|
|
247
|
+
|
|
210
248
|
### Authentication
|
|
211
249
|
|
|
212
250
|
If `RailsAuditLog.authenticate` is configured, the block is called with the GraphQL context before every query. Return a truthy value to allow access; return falsy to raise `GraphQL::ExecutionError` with `"Unauthorized"`.
|
data/ROADMAP.md
CHANGED
|
@@ -4,14 +4,6 @@ This gem adds a GraphQL API layer on top of [`rails_audit_log`](https://github.c
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## 0.5.0 — Multi-tenancy & Advanced Filtering
|
|
8
|
-
|
|
9
|
-
- **Tenant scoping** — automatically scope queries via `RailsAuditLog.current_tenant` when configured
|
|
10
|
-
- **`forTenant:` argument** — explicit tenant filter on `auditLogEntries`
|
|
11
|
-
- **Aggregations** — `auditLogEntriesCount(event:, itemType:, since:)` for dashboard metrics
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
7
|
## 0.6.0 — Performance & Safety
|
|
16
8
|
|
|
17
9
|
- **Dataloader batch loading** — batch-resolve polymorphic `actor` and `item` associations using graphql-ruby's `dataloader` to eliminate N+1 queries on list responses
|
|
@@ -14,6 +14,8 @@ module RailsAuditLog
|
|
|
14
14
|
) do
|
|
15
15
|
argument :id, GraphQL::Types::ID, required: true,
|
|
16
16
|
description: "ID of the audit log entry."
|
|
17
|
+
argument :for_tenant, String, required: false,
|
|
18
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
base.field(
|
|
@@ -31,6 +33,8 @@ module RailsAuditLog
|
|
|
31
33
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
32
34
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
33
35
|
argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
|
|
36
|
+
argument :for_tenant, String, required: false,
|
|
37
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
34
38
|
argument :page, GraphQL::Types::Int, required: false, default_value: 1, description: "Page number (1-based)."
|
|
35
39
|
argument :per_page, GraphQL::Types::Int, required: false, default_value: 25, description: "Number of results per page."
|
|
36
40
|
end
|
|
@@ -50,28 +54,55 @@ module RailsAuditLog
|
|
|
50
54
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
51
55
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
52
56
|
argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
|
|
57
|
+
argument :for_tenant, String, required: false,
|
|
58
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
base.field(
|
|
62
|
+
:audit_log_entries_count,
|
|
63
|
+
GraphQL::Types::Int,
|
|
64
|
+
null: false,
|
|
65
|
+
description: "Count audit log entries with optional filters. Respects auto-tenant when RailsAuditLog.current_tenant is configured.",
|
|
66
|
+
resolver_method: :resolve_audit_log_entries_count
|
|
67
|
+
) do
|
|
68
|
+
argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
|
|
69
|
+
argument :item_type, String, required: false, description: "Filter by audited model class name."
|
|
70
|
+
argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Count entries created at or after this time."
|
|
53
71
|
end
|
|
54
72
|
end
|
|
55
73
|
|
|
56
|
-
def resolve_audit_log_entry(id:)
|
|
74
|
+
def resolve_audit_log_entry(id:, for_tenant: nil)
|
|
57
75
|
check_authentication!
|
|
58
|
-
RailsAuditLog
|
|
76
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
77
|
+
base = tenant_id ? RailsAuditLog::AuditLogEntry.for_tenant(tenant_id) : RailsAuditLog::AuditLogEntry
|
|
78
|
+
base.find_by(id: id)
|
|
59
79
|
end
|
|
60
80
|
|
|
61
|
-
def resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, page: 1, per_page: 25)
|
|
81
|
+
def resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil, page: 1, per_page: 25)
|
|
62
82
|
check_authentication!
|
|
63
|
-
scope = build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by)
|
|
83
|
+
scope = build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
64
84
|
scope.limit(per_page).offset((page - 1) * per_page)
|
|
65
85
|
end
|
|
66
86
|
|
|
67
|
-
def resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil)
|
|
87
|
+
def resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
68
88
|
check_authentication!
|
|
69
|
-
build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by)
|
|
89
|
+
build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def resolve_audit_log_entries_count(event: nil, item_type: nil, since: nil)
|
|
93
|
+
check_authentication!
|
|
94
|
+
scope = RailsAuditLog::AuditLogEntry.all
|
|
95
|
+
scope = scope.where(event: event) if event
|
|
96
|
+
scope = scope.where(item_type: item_type) if item_type
|
|
97
|
+
scope = scope.where("created_at >= ?", since) if since
|
|
98
|
+
tenant_id = RailsAuditLog.current_tenant&.call
|
|
99
|
+
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
100
|
+
scope.count
|
|
70
101
|
end
|
|
71
102
|
|
|
72
103
|
private
|
|
73
104
|
|
|
74
|
-
def build_scope(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil)
|
|
105
|
+
def build_scope(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
75
106
|
sort_field = order_by&.field || :created_at
|
|
76
107
|
sort_direction = order_by&.direction || :desc
|
|
77
108
|
scope = RailsAuditLog::AuditLogEntry.order(sort_field => sort_direction)
|
|
@@ -85,6 +116,8 @@ module RailsAuditLog
|
|
|
85
116
|
safe = ActiveRecord::Base.sanitize_sql_like(touching)
|
|
86
117
|
scope = scope.where("object_changes LIKE ?", "%\"#{safe}\":%")
|
|
87
118
|
end
|
|
119
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
120
|
+
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
88
121
|
scope
|
|
89
122
|
end
|
|
90
123
|
|
|
@@ -76,7 +76,7 @@ module RailsAuditLog
|
|
|
76
76
|
module AuditLogEntriesQueryMixin
|
|
77
77
|
def self.included: (untyped base) -> void
|
|
78
78
|
|
|
79
|
-
def resolve_audit_log_entry: (id: String) -> untyped
|
|
79
|
+
def resolve_audit_log_entry: (id: String, ?for_tenant: String?) -> untyped
|
|
80
80
|
|
|
81
81
|
def resolve_audit_log_entries: (
|
|
82
82
|
?event: String?,
|
|
@@ -87,6 +87,7 @@ module RailsAuditLog
|
|
|
87
87
|
?until_time: Time?,
|
|
88
88
|
?touching: String?,
|
|
89
89
|
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
90
|
+
?for_tenant: String?,
|
|
90
91
|
?page: Integer,
|
|
91
92
|
?per_page: Integer
|
|
92
93
|
) -> untyped
|
|
@@ -99,9 +100,16 @@ module RailsAuditLog
|
|
|
99
100
|
?since: Time?,
|
|
100
101
|
?until_time: Time?,
|
|
101
102
|
?touching: String?,
|
|
102
|
-
?order_by: InputObjects::AuditLogEntrySortInput
|
|
103
|
+
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
104
|
+
?for_tenant: String?
|
|
103
105
|
) -> untyped
|
|
104
106
|
|
|
107
|
+
def resolve_audit_log_entries_count: (
|
|
108
|
+
?event: String?,
|
|
109
|
+
?item_type: String?,
|
|
110
|
+
?since: Time?
|
|
111
|
+
) -> Integer
|
|
112
|
+
|
|
105
113
|
private
|
|
106
114
|
|
|
107
115
|
def build_scope: (
|
|
@@ -112,7 +120,8 @@ module RailsAuditLog
|
|
|
112
120
|
?since: Time?,
|
|
113
121
|
?until_time: Time?,
|
|
114
122
|
?touching: String?,
|
|
115
|
-
?order_by: InputObjects::AuditLogEntrySortInput
|
|
123
|
+
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
124
|
+
?for_tenant: String?
|
|
116
125
|
) -> untyped
|
|
117
126
|
|
|
118
127
|
def check_authentication!: () -> void
|