graphiti 1.8.0 → 1.8.2
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/.github/workflows/ci.yml +55 -3
- data/CHANGELOG.md +9 -0
- data/README.md +218 -12
- data/gemfiles/rails_7_2_graphiti_rails.gemfile +19 -0
- data/gemfiles/rails_8_0_graphiti_rails.gemfile +19 -0
- data/lib/graphiti/scope.rb +35 -16
- data/lib/graphiti/version.rb +1 -1
- data/package.json +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 694b6036077d9ea14373be4b15e8e2d9cfab59253d79ce36d85303aa182a5482
|
4
|
+
data.tar.gz: 64afa2d52f244239c2b099f84500d18446ba04482e2b45447a8c8d9d93164be4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31f0a5953dbbb9526c33d9710528cd1410cf120ce8b036d9d9cbcb3983b62cab77d0adaaf641b9dd3e342e6096eb85a3427353ea58396bdad76593bbcf392161
|
7
|
+
data.tar.gz: 692cb0d0042334e2e92847dc5aee81e2ecb090329b6763adf4d757da205ab61df88e24b3c54230d28285c1cae9007a9ca1c554769ed2d02452fba8afd623d2eb
|
data/.github/workflows/ci.yml
CHANGED
@@ -2,7 +2,7 @@ name: CI
|
|
2
2
|
|
3
3
|
on:
|
4
4
|
push:
|
5
|
-
branches: [
|
5
|
+
branches: [main]
|
6
6
|
pull_request: {}
|
7
7
|
|
8
8
|
concurrency:
|
@@ -33,6 +33,7 @@ jobs:
|
|
33
33
|
- "3.1"
|
34
34
|
- "3.2"
|
35
35
|
- "3.3"
|
36
|
+
- "3.4"
|
36
37
|
gemfile:
|
37
38
|
- Gemfile
|
38
39
|
- gemfiles/rails_5_2.gemfile
|
@@ -42,6 +43,8 @@ jobs:
|
|
42
43
|
- gemfiles/rails_6_graphiti_rails.gemfile
|
43
44
|
- gemfiles/rails_7_graphiti_rails.gemfile
|
44
45
|
- gemfiles/rails_7_1_graphiti_rails.gemfile
|
46
|
+
- gemfiles/rails_7_2_graphiti_rails.gemfile
|
47
|
+
- gemfiles/rails_8_0_graphiti_rails.gemfile
|
45
48
|
appraisal:
|
46
49
|
- true
|
47
50
|
- false
|
@@ -49,6 +52,12 @@ jobs:
|
|
49
52
|
- ruby: ruby-head
|
50
53
|
gemfile: gemfiles/rails_7_1.gemfile
|
51
54
|
appraisal: true
|
55
|
+
- ruby: ruby-head
|
56
|
+
gemfile: gemfiles/rails_7_2_graphiti_rails.gemfile
|
57
|
+
appraisal: true
|
58
|
+
- ruby: ruby-head
|
59
|
+
gemfile: gemfiles/rails_8_0_graphiti_rails.gemfile
|
60
|
+
appraisal: true
|
52
61
|
- ruby: ruby-head
|
53
62
|
gemfile: Gemfile
|
54
63
|
appraisal: false
|
@@ -70,7 +79,46 @@ jobs:
|
|
70
79
|
appraisal: false
|
71
80
|
- gemfile: gemfiles/rails_7_1_graphiti_rails.gemfile
|
72
81
|
appraisal: false
|
73
|
-
|
82
|
+
- gemfile: gemfiles/rails_7_2_graphiti_rails.gemfile
|
83
|
+
appraisal: false
|
84
|
+
- gemfile: gemfiles/rails_8_0_graphiti_rails.gemfile
|
85
|
+
appraisal: false
|
86
|
+
|
87
|
+
# Rails 8 needs ruby 3.2 +
|
88
|
+
- gemfile: gemfiles/rails_8_0_graphiti_rails.gemfile
|
89
|
+
ruby: 2.7
|
90
|
+
- gemfile: gemfiles/rails_8_0_graphiti_rails.gemfile
|
91
|
+
ruby: 3.0
|
92
|
+
- gemfile: gemfiles/rails_8_0_graphiti_rails.gemfile
|
93
|
+
ruby: 3.1
|
94
|
+
|
95
|
+
# Rails 7.2 needs ruby 3.1 +
|
96
|
+
- gemfile: gemfiles/rails_7_2_graphiti_rails.gemfile
|
97
|
+
ruby: 2.7
|
98
|
+
- gemfile: gemfiles/rails_7_2_graphiti_rails.gemfile
|
99
|
+
ruby: 3.0
|
100
|
+
|
101
|
+
# Rails 7.1 needs ruby 3.0 +
|
102
|
+
- gemfile: gemfiles/rails_7_1_graphiti_rails.gemfile
|
103
|
+
ruby: 2.7
|
104
|
+
- gemfile: gemfiles/rails_7_1_graphiti_rails.gemfile
|
105
|
+
ruby: 3.0
|
106
|
+
|
107
|
+
# Rails 7.0 needs ruby 3.1 +
|
108
|
+
- gemfile: gemfiles/rails_7_0_graphiti_rails.gemfile
|
109
|
+
ruby: 3.2
|
110
|
+
- gemfile: gemfiles/rails_7_0_graphiti_rails.gemfile
|
111
|
+
ruby: 3.3
|
112
|
+
- gemfile: gemfiles/rails_7_0_graphiti_rails.gemfile
|
113
|
+
ruby: 3.4
|
114
|
+
|
115
|
+
# Rails 6 needs < ruby 3.4
|
116
|
+
- gemfile: gemfiles/rails_6.gemfile
|
117
|
+
ruby: 3.4
|
118
|
+
- gemfile: gemfiles/rails_6_graphiti_rails.gemfile
|
119
|
+
ruby: 3.4
|
120
|
+
|
121
|
+
# Rails 5 can't run on Ruby 3
|
74
122
|
- gemfile: gemfiles/rails_5_2.gemfile
|
75
123
|
ruby: 3.0
|
76
124
|
- gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
|
@@ -87,6 +135,10 @@ jobs:
|
|
87
135
|
ruby: 3.3
|
88
136
|
- gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
|
89
137
|
ruby: 3.3
|
138
|
+
- gemfile: gemfiles/rails_5_2.gemfile
|
139
|
+
ruby: 3.4
|
140
|
+
- gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
|
141
|
+
ruby: 3.4
|
90
142
|
continue-on-error: ${{ matrix.ruby == 'ruby-head' }}
|
91
143
|
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
92
144
|
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
@@ -104,7 +156,7 @@ jobs:
|
|
104
156
|
publish:
|
105
157
|
name: Release
|
106
158
|
runs-on: ubuntu-latest
|
107
|
-
if: github.ref == 'refs/heads/
|
159
|
+
if: github.ref == 'refs/heads/main'
|
108
160
|
needs: [test]
|
109
161
|
steps:
|
110
162
|
- name: Dispatch Release
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
graphiti changelog
|
2
2
|
|
3
|
+
## [1.8.2](https://github.com/graphiti-api/graphiti/compare/v1.8.1...v1.8.2) (2025-05-20)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* prevent context loss by always setting thread and fiber locals ([#497](https://github.com/graphiti-api/graphiti/issues/497)) ([5f45f76](https://github.com/graphiti-api/graphiti/commit/5f45f76f590a8a15e9ae3d47d0673c483da11e66))
|
9
|
+
|
10
|
+
## [1.8.1](https://github.com/graphiti-api/graphiti/compare/v1.8.0...v1.8.1) (2025-03-17)
|
11
|
+
|
3
12
|
# [1.8.0](https://github.com/graphiti-api/graphiti/compare/v1.7.9...v1.8.0) (2025-03-17)
|
4
13
|
|
5
14
|
|
data/README.md
CHANGED
@@ -1,22 +1,228 @@
|
|
1
|
+
#### Graphiti
|
2
|
+
|
1
3
|
[](https://github.com/graphiti-api/graphiti/actions/workflows/ci.yml)
|
2
4
|
[](https://badge.fury.io/rb/graphiti)
|
3
5
|
[](https://github.com/testdouble/standard)
|
4
6
|
[](https://github.com/semantic-release/semantic-release)
|
5
7
|
|
6
|
-
<p align="center">
|
7
|
-
<a href="https://www.graphiti.dev/guides">
|
8
|
-
<img " src="https://user-images.githubusercontent.com/55264/54884141-c10ada00-4e43-11e9-866b-e3c01e33a7c7.png" />
|
9
|
-
</a>
|
10
|
-
</p>
|
11
|
-
|
12
|
-
Stylish Graph APIs.
|
13
8
|
|
14
|
-
[
|
9
|
+
[](https://discord.gg/wgqkMBsSRV)
|
10
|
+
[](https://www.graphiti.dev)
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
<img align="right" src="https://user-images.githubusercontent.com/55264/54884141-c10ada00-4e43-11e9-866b-e3c01e33a7c7.png" alt="Graphiti logo" width="150px" />
|
15
|
+
Graphiti is a resource-oriented framework that sits on top of your models (usually ActiveRecord) and exposes them via a JSON:API-compliant interface. It abstracts common concerns like serialization, filtering, sorting, pagination, and sideloading relationships, so you can build powerful APIs with minimal boilerplate. By defining resources instead of controllers and serializers, Graphiti helps you keep your API logic organized, consistent, and easy to maintain.
|
16
|
+
|
17
|
+
|
18
|
+
#### Examples
|
19
|
+
Here's an example resource from the [example app](https://github.com/graphiti-api/employee_directory/) just to give you a taste of the possibilities.
|
20
|
+
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class EmployeeResource < ApplicationResource
|
24
|
+
attribute :first_name, :string
|
25
|
+
attribute :last_name, :string
|
26
|
+
attribute :age, :integer
|
27
|
+
attribute :created_at, :datetime, writable: false
|
28
|
+
attribute :updated_at, :datetime, writable: false
|
29
|
+
attribute :title, :string, only: [:filterable, :sortable]
|
30
|
+
|
31
|
+
has_many :positions
|
32
|
+
has_many :tasks
|
33
|
+
many_to_many :teams
|
34
|
+
polymorphic_has_many :notes, as: :notable
|
35
|
+
has_one :current_position, resource: PositionResource do
|
36
|
+
params do |hash|
|
37
|
+
hash[:filter][:current] = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
filter :title, only: [:eq] do
|
42
|
+
eq do |scope, value|
|
43
|
+
scope.joins(:current_position).merge(Position.where(title: value))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
sort :title do |scope, value|
|
48
|
+
scope.joins(:current_position).merge(Position.order(title: value))
|
49
|
+
end
|
50
|
+
|
51
|
+
sort :department_name, :string do |scope, value|
|
52
|
+
scope.joins(current_position: :department)
|
53
|
+
.merge(Department.order(name: value))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
A pretty boilerplate controller that just interfaces with the resource
|
59
|
+
```ruby
|
60
|
+
class EmployeesController < ApplicationController
|
61
|
+
def index
|
62
|
+
employees = EmployeeResource.all(params)
|
63
|
+
respond_with(employees)
|
64
|
+
end
|
65
|
+
|
66
|
+
def show
|
67
|
+
employee = EmployeeResource.find(params)
|
68
|
+
respond_with(employee)
|
69
|
+
end
|
70
|
+
|
71
|
+
def create
|
72
|
+
employee = EmployeeResource.build(params)
|
73
|
+
|
74
|
+
if employee.save
|
75
|
+
render jsonapi: employee, status: 201
|
76
|
+
else
|
77
|
+
render jsonapi_errors: employee
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def update
|
82
|
+
employee = EmployeeResource.find(params)
|
83
|
+
|
84
|
+
if employee.update_attributes
|
85
|
+
render jsonapi: employee
|
86
|
+
else
|
87
|
+
render jsonapi_errors: employee
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def destroy
|
92
|
+
employee = EmployeeResource.find(params)
|
93
|
+
|
94
|
+
if employee.destroy
|
95
|
+
render jsonapi: { meta: {} }, status: 200
|
96
|
+
else
|
97
|
+
render jsonapi_errors: employee
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
</details>
|
104
|
+
|
105
|
+
|
106
|
+
Now you can query your endpoints simply and powerfully, like:
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
Request:
|
111
|
+
```http://localhost:3000/api/v1/employees?filter[title][eq]=Future Government Administrator&filter[age][lt]=40```
|
112
|
+
|
113
|
+
<details>
|
114
|
+
<summary>JSON-API response</summary>
|
115
|
+
|
116
|
+
```json
|
117
|
+
{
|
118
|
+
"data": [
|
119
|
+
{
|
120
|
+
"id": "1",
|
121
|
+
"type": "employees",
|
122
|
+
"attributes": {
|
123
|
+
"first_name": "Quinn",
|
124
|
+
"last_name": "Homenick",
|
125
|
+
"age": 36,
|
126
|
+
"created_at": "2025-03-21T23:04:40+00:00",
|
127
|
+
"updated_at": "2025-03-21T23:04:40+00:00"
|
128
|
+
},
|
129
|
+
"relationships": {
|
130
|
+
"positions": {
|
131
|
+
"links": {
|
132
|
+
"related": "/api/v1/positions?filter[employee_id]=1"
|
133
|
+
},
|
134
|
+
"data": [
|
135
|
+
{
|
136
|
+
"type": "positions",
|
137
|
+
"id": "1"
|
138
|
+
},
|
139
|
+
{
|
140
|
+
"type": "positions",
|
141
|
+
"id": "2"
|
142
|
+
}
|
143
|
+
]
|
144
|
+
},
|
145
|
+
"tasks": {
|
146
|
+
"links": {
|
147
|
+
"related": "/api/v1/tasks?filter[employee_id]=1"
|
148
|
+
}
|
149
|
+
},
|
150
|
+
"teams": {
|
151
|
+
"links": {
|
152
|
+
"related": "/api/v1/teams?filter[employee_id]=1"
|
153
|
+
}
|
154
|
+
},
|
155
|
+
"notes": {
|
156
|
+
"links": {
|
157
|
+
"related": "/api/v1/notes?filter[notable_id]=1&filter[notable_type][eql]=Employee"
|
158
|
+
}
|
159
|
+
},
|
160
|
+
"current_position": {
|
161
|
+
"links": {
|
162
|
+
"related": "/api/v1/positions?filter[current]=true&filter[employee_id]=1"
|
163
|
+
},
|
164
|
+
"data": {
|
165
|
+
"type": "positions",
|
166
|
+
"id": "1"
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
],
|
172
|
+
"included": [
|
173
|
+
{
|
174
|
+
"id": "1",
|
175
|
+
"type": "positions",
|
176
|
+
"attributes": {
|
177
|
+
"title": "Future Government Administrator",
|
178
|
+
"active": true
|
179
|
+
},
|
180
|
+
"relationships": {
|
181
|
+
"employee": {
|
182
|
+
"links": {
|
183
|
+
"related": "/api/v1/employees/1"
|
184
|
+
}
|
185
|
+
},
|
186
|
+
"department": {
|
187
|
+
"links": {
|
188
|
+
"related": "/api/v1/departments/3"
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
},
|
193
|
+
{
|
194
|
+
"id": "2",
|
195
|
+
"type": "positions",
|
196
|
+
"attributes": {
|
197
|
+
"title": "Manufacturing Specialist",
|
198
|
+
"active": false
|
199
|
+
},
|
200
|
+
"relationships": {
|
201
|
+
"employee": {
|
202
|
+
"links": {
|
203
|
+
"related": "/api/v1/employees/1"
|
204
|
+
}
|
205
|
+
},
|
206
|
+
"department": {
|
207
|
+
"links": {
|
208
|
+
"related": "/api/v1/departments/2"
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
],
|
214
|
+
"meta": {}
|
215
|
+
}
|
216
|
+
```
|
217
|
+
|
218
|
+
</details>
|
219
|
+
|
220
|
+
|
221
|
+
|
222
|
+
[Graphiti Guides](https://www.graphiti.dev/guides/)
|
223
|
+
|
224
|
+
[Join the Discord](https://discord.gg/wgqkMBsSRV)
|
15
225
|
|
16
|
-
[Join the Slack Channel](https://join.slack.com/t/graphiti-api/shared_invite/enQtMjkyMTA3MDgxNTQzLTU5MDI4MDllNTEzOTE1Nzk0ZGJlNTcxZDYzMGY2ZTczMDY2OWZhM2RmNTU0YWNiOWZhZDhkMmU4MzQ5NzIyNWM)
|
17
226
|
|
18
|
-
Direct Contact: richmolj@gmail.com
|
19
227
|
|
20
|
-
Supports Rails >= 4.1
|
21
228
|
|
22
|
-
*Looking for JSONAPI-Suite? You're in the right place. Graphiti is the 1.0 version of JSONAPI Suite. For the deprecated Suite gem, go [here](https://github.com/jsonapi-suite/jsonapi_suite_deprecated)*
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rails", "~> 7.2"
|
6
|
+
gem "rspec-rails"
|
7
|
+
gem "sqlite3", "~> 2.1"
|
8
|
+
gem "database_cleaner"
|
9
|
+
gem "graphiti-rails", "~> 0.4.0"
|
10
|
+
|
11
|
+
group :test do
|
12
|
+
gem "pry"
|
13
|
+
gem "pry-byebug", platform: [:mri]
|
14
|
+
gem "appraisal"
|
15
|
+
gem "guard"
|
16
|
+
gem "guard-rspec"
|
17
|
+
end
|
18
|
+
|
19
|
+
gemspec path: "../"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rails", "~> 8.0"
|
6
|
+
gem "rspec-rails"
|
7
|
+
gem "sqlite3", "~> 2.1"
|
8
|
+
gem "database_cleaner"
|
9
|
+
gem "graphiti-rails", "~> 0.4.0"
|
10
|
+
|
11
|
+
group :test do
|
12
|
+
gem "pry"
|
13
|
+
gem "pry-byebug", platform: [:mri]
|
14
|
+
gem "appraisal"
|
15
|
+
gem "guard"
|
16
|
+
gem "guard-rspec"
|
17
|
+
end
|
18
|
+
|
19
|
+
gemspec path: "../"
|
data/lib/graphiti/scope.rb
CHANGED
@@ -140,7 +140,7 @@ module Graphiti
|
|
140
140
|
end
|
141
141
|
fiber_storage =
|
142
142
|
if Fiber.current.respond_to?(:storage)
|
143
|
-
Fiber.current
|
143
|
+
Fiber.current.storage&.keys&.each_with_object({}) do |key, memo|
|
144
144
|
memo[key] = Fiber[key]
|
145
145
|
end
|
146
146
|
end
|
@@ -149,27 +149,46 @@ module Graphiti
|
|
149
149
|
self.class.global_thread_pool_executor, Thread.current.object_id, thread_storage, fiber_storage, *args
|
150
150
|
) do |thread_id, thread_storage, fiber_storage, *args|
|
151
151
|
wrap_in_rails_executor do
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
fiber_storage&.keys&.each_with_object(Fiber) do |key, fiber_current|
|
158
|
-
fiber_current[key] = fiber_storage[key]
|
152
|
+
with_thread_locals(thread_storage) do
|
153
|
+
with_fiber_locals(fiber_storage) do
|
154
|
+
Graphiti.broadcast(:global_thread_pool_task_run, self.class.global_thread_pool_stats) do
|
155
|
+
yield(*args)
|
156
|
+
end
|
159
157
|
end
|
160
158
|
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
161
162
|
|
162
|
-
|
163
|
-
|
164
|
-
|
163
|
+
def with_thread_locals(thread_locals)
|
164
|
+
new_thread_locals = []
|
165
|
+
thread_locals.each do |key, value|
|
166
|
+
if !Thread.current[key]
|
167
|
+
new_thread_locals << key
|
168
|
+
end
|
169
|
+
Thread.current[key] = value
|
170
|
+
end
|
171
|
+
yield
|
172
|
+
ensure
|
173
|
+
new_thread_locals.each do |key|
|
174
|
+
Thread.current[key] = nil
|
175
|
+
end
|
176
|
+
end
|
165
177
|
|
166
|
-
|
167
|
-
|
168
|
-
fiber_storage&.keys&.each { |key| Fiber[key] = nil }
|
169
|
-
end
|
178
|
+
def with_fiber_locals(fiber_locals)
|
179
|
+
return yield unless fiber_locals
|
170
180
|
|
171
|
-
|
181
|
+
new_fiber_locals = []
|
182
|
+
fiber_locals.each do |key, value|
|
183
|
+
if !Fiber[key]
|
184
|
+
new_fiber_locals << key
|
172
185
|
end
|
186
|
+
Fiber[key] = value
|
187
|
+
end
|
188
|
+
yield
|
189
|
+
ensure
|
190
|
+
new_fiber_locals&.each do |key|
|
191
|
+
Fiber[key] = nil
|
173
192
|
end
|
174
193
|
end
|
175
194
|
|
data/lib/graphiti/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphiti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Richmond
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jsonapi-serializable
|
@@ -261,7 +261,9 @@ files:
|
|
261
261
|
- gemfiles/rails_7.gemfile
|
262
262
|
- gemfiles/rails_7_1.gemfile
|
263
263
|
- gemfiles/rails_7_1_graphiti_rails.gemfile
|
264
|
+
- gemfiles/rails_7_2_graphiti_rails.gemfile
|
264
265
|
- gemfiles/rails_7_graphiti_rails.gemfile
|
266
|
+
- gemfiles/rails_8_0_graphiti_rails.gemfile
|
265
267
|
- graphiti.gemspec
|
266
268
|
- lib/graphiti.rb
|
267
269
|
- lib/graphiti/adapters/abstract.rb
|