rails_age 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 272f8908dc8fb8a98adb443411e4b439eff914c8173b5eb64b53fa5362fa1572
4
- data.tar.gz: bf1921611698ffc1b651787f2e1b1a5d1bc503cbe1300639b2f9dada8202cdde
3
+ metadata.gz: 8228c60b43732a31b364b658e65b5d6a2e1b76018b573b1ec5b7fa25582f519c
4
+ data.tar.gz: 60f5211cb37aa6605523f76cde81158b6495448e90d4fbeabecd020c38520c4e
5
5
  SHA512:
6
- metadata.gz: 51592c31e872a9b8dc6e96fe8fa42374241496e4da6a17ce70bf63f5f118ac078e81200259c048529e7e16b2147c8c5bbef00315cee8f26237295d04ffaea887
7
- data.tar.gz: 0b24560f7703e4dc4f97d3d36de626906a47a2cda5f5137cc6c1840a5281bbcf2693743666fb6301b26723c9723244bd1854c9c8b21d5d657eb621d4caf0d864
6
+ metadata.gz: eec16e9c7b4512793b4aac9a3ac1c9ee0ce6280a1033712cc6aed5466218ffa17a47c1fca4d1f4d0508ce38e4a12a9a0c392d927f72a62c5ebcf8d2ea7c343f5
7
+ data.tar.gz: 3ccdeba21d32bc35de9162698c5c340efce5b0557b5930a3b1e0d9caaf5697f5afcd2b39ad65d0c976b5b3bc46df5edaf18a7bb96e023a2090642b08eb002786
data/CHANGELOG.md CHANGED
@@ -1,21 +1,64 @@
1
1
  # Change Log
2
2
 
3
- ## VERSION 0.4.0 - 2024-xx-xx
3
+ ## VERSION 0.5.0 - 2024-xx-xx
4
+
5
+ - **AGE Schema override** (instance and class methods) assumes db and migrations up-to-date
4
6
 
5
7
  - **cypher**
8
+ * schema override
6
9
  * query support
7
10
  * paths support
8
11
  * select attributes support
12
+
9
13
  - **Paths**
10
- * ?
11
14
 
12
- ## VERSION 0.3.1 - 2024-xx-xx
15
+ ## VERSION 0.4.4 - 2024-xx-xx
16
+
17
+ - **Edge Scaffold** (generates edge, type, view and controller)
18
+ * add `rails generate apache_age:edge_scaffold HasJob employee_role start_node:person end_node:company`
19
+
20
+ ## VERSION 0.4.3 - 2024-xx-xx
21
+
22
+ - **Node Scaffold** (generates node, type, view and controller)
23
+ * add `rails generate apache_age:node_scaffold Person first_name last_name age:integer`
24
+
25
+ ## VERSION 0.4.2 - 2024-xx-xx
26
+
27
+ - **Edge Generator**
28
+ * add `rails generate apache_age:edge HasPet owner_role` just a property
29
+ * add `rails generate apache_age:edge HasPet owner_role start_node:person end_node:pet`
30
+ with property and specified start-/end-nodes (person and pet nodes must have already been created)
31
+
32
+ ## VERSION 0.4.1 - 2024-xx-xx
33
+
34
+ - **OPTIONAL Installer**
35
+ * add `config_migrate` to `rails generate apache_age:install` auto fix the schema after `rails db:migrate`
36
+
37
+ ## VERSION 0.4.0 - 2024-06-14
38
+
39
+ Minor breaking change: type (:vertix) is now required in core for edges
40
+
41
+ - **Installer**
42
+ * AGE types added to installer (with tests)
43
+
44
+ - **Node Generator**
45
+ * add also creates node types (with tests)
46
+
47
+ - **Apache AGE Migrate**
48
+ * add `bin/rails apache_age:migrate` runs `bin/rails db:migrate` followed by `bin/rails apache_age:config_schema` to fix the schema file after `bin/rails db:migrate`
49
+
50
+ ## VERSION 0.3.2 - 2024-06-08
51
+
52
+ - **Node Generator**
53
+ * add `rails generate apache_age:node Pets/Cat name age:integer` creates a node with a namespace and attributes at: `app/nodes/pets/cat.rb`
54
+ * add `rails generate apache_age:node Cat name age:integer` creates a node with attributes at: `app/nodes/cat.rb`
55
+ * add `rails destroy apache_age:node Cat` deletes an existing node at: `app/nodes/cat.rb`
56
+
57
+ ## VERSION 0.3.1 - 2024-06-02
13
58
 
14
- - **Generators**
15
- * add `rails generate apache_age:node` to create a node model (with its type in initializer)
16
- * add `rails generate apache_age:edge` to create an edge model (with its type in initializer)
17
59
  - **Installer**
18
60
  * refactor into multiple independent tasks with tests
61
+
19
62
  - **Documentation**
20
63
  * updated README with additional information
21
64
  * added `db/structure.sql` config to README
@@ -24,6 +67,7 @@
24
67
 
25
68
  - **Edges**
26
69
  * `find_by(start_node:, :end_node:, properties:)` to find an edge with specific nodes & properties (deprecated `find_edge`)
70
+
27
71
  - **Installer** (`rails generate apache_age:install`)
28
72
  * copy Age PG Extenstion migration to `db/migrate`
29
73
  * run the AGE PG Migration
@@ -39,6 +83,7 @@ NOTE: the `rails generate apache_age:install` can be run at any time to repair t
39
83
  * add missing methods to use in rails controllers
40
84
  * validate edge start- & end-nodes are valid
41
85
  * add unique edge validations
86
+
42
87
  - **Nodes**
43
88
  * add missing methods to use in rails controllers
44
89
  * add unique node validations
@@ -50,9 +95,11 @@ Initial release has the following features:
50
95
  - **Nodes:**
51
96
  * `.create`, `.read`, `.update`, `.delete`, `.all`, `.find(by id)`, `.find_by(age_properties)`
52
97
  * verified with usage in a controller and views
98
+
53
99
  - **Edges:**
54
100
  *`.create`, `.read`, `.update`, `.delete`, `.all`, `.find(by id)`, `.find_by(age_properties)`
55
101
  * verified with usage in a controller and views
102
+
56
103
  - **Entities:**
57
104
  * `.all`, `.find(id)`, `.find_by(age_property)` use these when class, label, edge, node
58
105
 
data/README.md CHANGED
@@ -12,368 +12,109 @@ Add this line to your application's Gemfile:
12
12
  gem "rails_age"
13
13
  ```
14
14
 
15
- ### Quick Install
15
+ ## Quick Start
16
16
 
17
17
  using the installer, creates the migration to install age, runs the migration, and adjusts the schema file, and updates the `config/database.yml` file.
18
18
 
19
+ setup (& Test) postgresql with AGE (using the docker version of AGE DB may be the easiest way to get started)
20
+ using the docker version of AGE DB, you can confirm psql AGE with the following commands:
19
21
  ```bash
20
- $ bundle
21
- $ bin/rails apache_age:install
22
- $ git add .
23
- $ git commit -m "Add Apache Age to Rails"
22
+ psql -h localhost -p 5455 -U docker_username
23
+ > CREATE EXTENSION IF NOT EXISTS age;
24
+ > LOAD 'age';
25
+ > SET search_path = ag_catalog, "$user", public;
26
+ > SELECT create_graph('age_schema');
27
+ > \q
24
28
  ```
25
29
 
26
- NOTE: it is important to commit the `db/schema.rb` to git because `rails db:migrate` inappropriately modifies the schema file (I haven't yet tested `db/structure.sql`). **You can run `bin/rails apache_age:install` at any time to repair the schema file as needed.**
27
-
28
- For now, if you are using `db/structure.sql` you will need to manually configure Apache Age (RailsAge) as described below.
29
-
30
- ### Manual Install
31
-
32
- create a migration to add the Apache Age extension to your database
30
+ create a new Rails app (WITH POSTGRESQL!)
33
31
  ```bash
34
- $ bin/rails g migration AddApacheAge
32
+ rails new age_demo -d postgresql
33
+ cd age_demo
34
+ git add .
35
+ git commit -m "Initial Rails App"
35
36
  ```
36
- copy the contents of https://github.com/marpori/rails_age/blob/main/db/migrate/20240521062349_add_apache_age.rb
37
- ```ruby
38
- class AddApacheAge < ActiveRecord::Migration[7.1]
39
- def up
40
- # Allow age extension
41
- execute('CREATE EXTENSION IF NOT EXISTS age;')
42
-
43
- # Load the age code
44
- execute("LOAD 'age';")
45
-
46
- # Load the ag_catalog into the search path
47
- execute('SET search_path = ag_catalog, "$user", public;')
48
-
49
- # Create age_schema graph if it doesn't exist
50
- execute("SELECT create_graph('age_schema');")
51
- end
52
-
53
- def down
54
- execute <<-SQL
55
- DO $$
56
- BEGIN
57
- IF EXISTS (
58
- SELECT 1
59
- FROM pg_constraint
60
- WHERE conname = 'fk_graph_oid'
61
- ) THEN
62
- ALTER TABLE ag_catalog.ag_label
63
- DROP CONSTRAINT fk_graph_oid;
64
- END IF;
65
- END $$;
66
- SQL
67
-
68
- execute("SELECT drop_graph('age_schema', true);")
69
- execute('DROP SCHEMA IF EXISTS ag_catalog CASCADE;')
70
- execute('DROP EXTENSION IF EXISTS age;')
71
- end
72
- end
37
+ configure `config/database.yml` when using the docker version of AGE DB my config looks like:
38
+ ```yaml
39
+ port: 5455
40
+ host: localhost
41
+ username: docker_username
42
+ password: dockerized_password
73
43
  ```
74
- into your new migration file
75
44
 
76
- then run the migration
45
+ now you should be able to create the rails database:
77
46
  ```bash
78
- $ bin/rails db:migrate
79
- ```
80
-
81
- Rails migrate will mangle the schema `db/schema.rb` file. You need to remove the lines that look like:
82
- ```ruby
83
- ActiveRecord::Schema[7.1].define(version: 2024_05_21_062349) do
84
- create_schema "ag_catalog"
85
- create_schema "age_schema"
86
-
87
- # These are extensions that must be enabled in order to support this database
88
- enable_extension "age"
89
- enable_extension "plpgsql"
90
-
91
- # Could not dump table "_ag_label_edge" because of following StandardError
92
- # Unknown type 'graphid' for column 'id'
93
-
94
- # Could not dump table "_ag_label_vertex" because of following StandardError
95
- # Unknown type 'graphid' for column 'id'
96
-
97
- # Could not dump table "ag_graph" because of following StandardError
98
- # Unknown type 'regnamespace' for column 'namespace'
99
-
100
- # Could not dump table "ag_label" because of following StandardError
101
- # Unknown type 'regclass' for column 'relation'
102
-
103
- add_foreign_key "ag_label", "ag_graph", column: "graph", primary_key: "graphid", name: "fk_graph_oid"
104
-
105
- # other migrations
106
- # ...
107
- end
108
- ```
109
-
110
- and replace them with the following lines:
111
- ```ruby
112
- ActiveRecord::Schema[7.1].define(version: 2024_05_21_062349) do
113
- # These are extensions that must be enabled in order to support this database
114
- enable_extension 'plpgsql'
115
-
116
- # Allow age extension
117
- execute('CREATE EXTENSION IF NOT EXISTS age;')
118
-
119
- # Load the age code
120
- execute("LOAD 'age';")
121
-
122
- # Load the ag_catalog into the search path
123
- execute('SET search_path = ag_catalog, "$user", public;')
124
-
125
- # Create age_schema graph if it doesn't exist
126
- execute("SELECT create_graph('age_schema');")
127
-
128
- # other migrations
129
- # ...
130
- end
47
+ rails db:create
48
+ rails db:migrate
49
+ git add .
50
+ git commit -m "Add Apache Age Postgres DB configured with Rails App"
131
51
  ```
132
52
 
133
- NOTE: if using `db/structure.sql` use:
134
- ```sql
135
- -- These are extensions that must be enabled in order to support this database
136
- CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA public;
137
-
138
- -- Allow age extension (if not already enabled), this builds the age_catalog schema
139
- CREATE EXTENSION IF NOT EXISTS age;
140
-
141
- -- Load the age module
142
- LOAD 'age';
143
-
144
- -- Load the ag_catalog into the search path
145
- SET search_path = ag_catalog, "$user", public;
146
-
147
- -- Create age_schema graph if it doesn't exist
148
- SELECT create_graph('age_schema');
149
-
150
- # other migrations
151
- # ...
152
-
153
- INSERT INTO "schema_migrations" (version) VALUES
154
- ('20110315075839'),
155
- --- ...
156
- ('20240521062349');
53
+ install Apache Age (you can ignore the `unknown OID` warnings)
54
+ ```bash
55
+ bundle add rails_age
56
+ bundle install
57
+ bin/rails apache_age:install
58
+ git add .
59
+ git commit -m "Add Apache Age to Rails"
157
60
  ```
158
61
 
159
- ## Contributing
160
-
161
- Create an merge request (with tests) and I will review it/merge it when ready.
162
-
163
- ## License
164
-
165
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
166
-
167
- ## Usage
168
-
169
- I suggest you creat a folder create a folder called `app/nodes` and `app/edges` to keep the code organized.
170
- I frequently use the `app/graphs` folder to keep all the graph related code together in a Module (as is done in the [rails age demo app](https://github.com/marpori/rails_age_demo_app))
171
-
172
- I suggest you creat a folder within app called `graphs` and under that create a folder called `nodes` and `edges`. This will help you keep your code organized.
173
-
174
- A trival, but fully functional [rails age demo app](https://github.com/marpori/rails_age_demo_app), based on the Flintstones Commic, is available for reference.
175
-
176
- ### Nodes
177
-
178
- ```ruby
179
- # app/graphs/nodes/company.rb
180
- module Nodes
181
- class Company
182
- include ApacheAge::Entities::Vertex
183
-
184
- attribute :company_name, :string
185
-
186
- validates :company_name, presence: true
187
- validates_with(
188
- ApacheAge::Validators::UniqueVertexValidator,
189
- attributes: [:company_name]
190
- )
191
- end
192
- end
62
+ make some nodes :string is the default type
63
+ ```bash
64
+ rails generate apache_age:node Company company_name
65
+ rails generate apache_age:node Person first_name last_name
66
+ rails generate apache_age:node Pet pet_name:string age:integer
193
67
  ```
68
+ make some edges (`:vertex` is the default type) for start_node and end_node
69
+ ```bash
70
+ # when start node and end node are not specified they are of type `:vertex`
71
+ # this is generally not recommended - exept when very generic relationships are needed
72
+ rails generate apache_age:edge HasJob employee_role
194
73
 
195
- ```ruby
196
- # app/graphs/nodes/person.rb
197
- module Nodes
198
- class Person
199
- include ApacheAge::Entities::Vertex
200
-
201
- attribute :first_name, :string, default: nil
202
- attribute :last_name, :string, default: nil
203
- attribute :given_name, :string, default: nil
204
- attribute :nick_name, :string, default: nil
205
- attribute :gender, :string, default: nil
206
-
207
- validates :gender, :first_name, :last_name, :given_name, :nick_name,
208
- presence: true
209
-
210
- def initialize(**attributes)
211
- super
212
- # use unless present? since attributes when empty sets to "" by default
213
- self.nick_name = first_name unless nick_name.present?
214
- self.given_name = last_name unless given_name.present?
215
- end
216
- end
217
- end
74
+ # this is recommended - use explicit start_node and end_node types
75
+ rails generate apache_age:node HasPet start_node:person end_node:pet caretaker_role
218
76
  ```
219
77
 
220
- ### Edges
221
-
222
- ```ruby
223
- # app/graphs/edges/has_job.rb
224
- module Edges
225
- class HasJob
226
- include ApacheAge::Entities::Edge
227
-
228
- attribute :employee_role, :string
229
- attribute :start_node, :person
230
- attribute :end_node, :company
231
-
232
- validates :employee_role, presence: true
233
- validate :validate_unique
234
- # or with a one-liner
235
- # validates_with(
236
- # ApacheAge::Validators::UniqueEdgeValidator,
237
- # attributes: %i[employee_role start_node end_node]
238
- # )
78
+ **NOTE:** the default `rails db:migrate` inappropriately modifies the schema file. This installer patches the migration to prevent this (however this might break on rails updates, etc). **You can run `bin/rails apache_age:install` at any time to repair the schema file as needed.**
239
79
 
240
- private
241
-
242
- def validate_unique
243
- ApacheAge::Validators::UniqueEdgeValidator
244
- .new(attributes: %i[employee_role start_node end_node])
245
- .validate(self)
246
- end
247
- end
248
- end
249
- ```
80
+ For now, if you are using `db/structure.sql` you will need to manually configure Apache Age (RailsAge) as described below.
250
81
 
251
82
  ### Rails Console Usage
252
83
 
253
84
  ```ruby
254
- fred = Nodes::Person.create(first_name: 'Fredrick Jay', nick_name: 'Fred', last_name: 'Flintstone', gender: 'male')
255
- fred.to_h
256
-
257
- quarry = Nodes::Company.create(company_name: 'Bedrock Quarry')
258
- quarry.to_h
259
-
260
- job = Edges::HasJob.create(start_node: fred, end_node: quarry, employee_role: 'Crane Operator')
261
- job.to_h
262
- ```
263
-
264
- ### Update Routes
265
-
266
- ```ruby
267
- Rails.application.routes.draw do
268
- # mount is not needed with the engine
269
- # mount RailsAge::Engine => "/rails_age"
270
-
271
- # defines the route for the people controller
272
- resources :people
273
-
274
- # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
275
- # Can be used by load balancers and uptime monitors to verify that the app is live.
276
- get 'up' => 'rails/health#show', as: :rails_health_check
277
-
278
- # Defines the root path route ("/")
279
- root 'people#index'
280
- end
281
- ```
282
-
283
- ### Types (Optional)
284
-
285
- ```ruby
286
- # spec/dummy/config/initializers/types.rb
287
- require 'apache_age/types/age_type_generator'
288
-
289
- Rails.application.config.to_prepare do
290
- # Ensure the files are loaded
291
- require_dependency 'nodes/company'
292
- require_dependency 'nodes/person'
293
-
294
- # Register the custom types
295
- ActiveModel::Type.register(:company, ApacheAge::Types::AgeTypeGenerator.create_type_for(Nodes::Company))
296
- ActiveModel::Type.register(:person, ApacheAge::Types::AgeTypeGenerator.create_type_for(Nodes::Person))
297
- end
298
- ```
299
-
300
- ### Controller Usage
301
-
302
- ```ruby
303
- # app/controllers/people_controller.rb
304
- class PeopleController < ApplicationController
305
- before_action :set_person, only: %i[show edit update destroy]
306
-
307
- # GET /people or /people.json
308
- def index
309
- @people = Nodes::Person.all
310
- end
311
-
312
- # GET /people/1 or /people/1.json
313
- def show; end
314
-
315
- # GET /people/new
316
- def new
317
- @person = Nodes::Person.new
318
- end
319
-
320
- # GET /people/1/edit
321
- def edit; end
322
-
323
- # POST /people or /people.json
324
- def create
325
- @person = Nodes::Person.new(**person_params)
326
- respond_to do |format|
327
- if @person.save
328
- format.html { redirect_to person_url(@person), notice: 'Person was successfully created.' }
329
- format.json { render :show, status: :created, location: @person }
330
- else
331
- format.html { render :new, status: :unprocessable_entity }
332
- format.json { render json: @person.errors, status: :unprocessable_entity }
333
- end
334
- end
335
- end
336
-
337
- # PATCH/PUT /people/1 or /people/1.json
338
- def update
339
- respond_to do |format|
340
- if @person.update(**person_params)
341
- format.html { redirect_to person_url(@person), notice: 'Person was successfully updated.' }
342
- format.json { render :show, status: :ok, location: @person }
343
- else
344
- format.html { render :edit, status: :unprocessable_entity }
345
- format.json { render json: @person.errors, status: :unprocessable_entity }
346
- end
347
- end
348
- end
349
-
350
- # DELETE /people/1 or /people/1.json
351
- def destroy
352
- @person.destroy!
353
-
354
- respond_to do |format|
355
- format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
356
- format.json { head :no_content }
357
- end
358
- end
359
-
360
- private
361
-
362
- # Use callbacks to share common setup or constraints between actions.
363
- def set_person
364
- @person = Nodes::Person.find(params[:id])
365
- end
366
-
367
- # Only allow a list of trusted parameters through.
368
- def person_params
369
- # params.fetch(:person, {})
370
- params.require(:nodes_person).permit(:first_name, :last_name, :nick_name, :given_name, :gender)
371
- end
372
- end
373
- ```
374
-
375
- ### Views
376
-
377
- ```erb
378
-
379
- ```
85
+ bin/rails c
86
+
87
+ fred = Person.new(first_name: 'Fredrick Jay', last_name: 'Flintstone')
88
+ fred.valid?
89
+ fred.save
90
+ fred.to_h # should have an ID
91
+
92
+ # fails because of a missing required field (Property)
93
+ incomplete = Person.new(first_name: 'Fredrick Jay')
94
+ incomplete.valid?
95
+ incomplete.errors
96
+ incomplete.to_h
97
+
98
+ # fails because of uniqueness constraints
99
+ jay = Person.create(first_name: 'Fredrick Jay', last_name: 'Flintstone')
100
+ jay.to_h
101
+ => {:id=>nil, :first_name=>"Fredrick Jay", :last_name=>"Flintstone"}
102
+ jay.valid?
103
+ => false
104
+ jay.errors
105
+ => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=record not unique, options={}>, #<ActiveModel::Error attribute=first_name, type=property combination not unique, options={}>, #<ActiveModel::Error attribute=last_name, type=property combination not unique, options={}>]>
106
+ irb(main):008> jav.to_h
107
+ => {:id=>nil, :first_name=>"Fredrick Jay", :last_name=>"Flintstone"}
108
+
109
+ # .create is a shortcut for .new and .save
110
+ quarry = Company.create(company_name: 'Bedrock Quarry')
111
+ quarry.to_h # should have an ID
112
+
113
+ # create an edge (no generator yet)
114
+ job = HasJob.create(start_node: fred, end_node: quarry, employee_role: 'Crane Operator')
115
+ job.to_h # should have an ID
116
+ ```
117
+
118
+ ## Manual Install, Config and Usage
119
+
120
+ see [Manuel Installation, Configuration and Usage](MANUAL_INSTALL.md)
@@ -11,9 +11,9 @@ module ApacheAge
11
11
  attribute :id, :integer
12
12
  attribute :end_id, :integer
13
13
  attribute :start_id, :integer
14
- # allow user to optionally specify the class type (or not) thus not adding: `:vertex`
15
- attribute :end_node
16
- attribute :start_node
14
+ # type: `:vertex` can be overriden with a specific node type
15
+ attribute :end_node, :vertex
16
+ attribute :start_node, :vertex
17
17
 
18
18
  validates :end_node, :start_node, presence: true
19
19
  validate :validate_nodes
@@ -35,10 +35,10 @@ module ApacheAge
35
35
  query = record.class.find_by(edge_attribs.compact)
36
36
  return if query.blank? || (query.id == record.id)
37
37
 
38
- record.errors.add(:base, 'attribute combination not unique')
39
- record.errors.add(:end_node, 'attribute combination not unique')
40
- record.errors.add(:start_node, 'attribute combination not unique')
41
- attributes.each { record.errors.add(_1, 'attribute combination not unique') }
38
+ record.errors.add(:base, 'record not unique')
39
+ record.errors.add(:end_node, 'node combination not unique')
40
+ record.errors.add(:start_node, 'node combination not unique')
41
+ attributes.each { record.errors.add(_1, 'prpoerty combination not unique') }
42
42
  end
43
43
 
44
44
  private
@@ -20,8 +20,8 @@ module ApacheAge
20
20
  # if no match is found or if it finds itself, it's valid
21
21
  return if query.blank? || (query.id == record.id)
22
22
 
23
- record.errors.add(:base, 'attribute combination not unique')
24
- attributes.each { record.errors.add(_1, 'attribute combination not unique') }
23
+ record.errors.add(:base, 'record not unique')
24
+ attributes.each { record.errors.add(_1, 'property combination not unique') }
25
25
  end
26
26
  end
27
27
  end
@@ -0,0 +1,54 @@
1
+ Description:
2
+ This creates Apache AGE nodes that work seamlessly with Rails.
3
+ A node can be created with or without a namespace.
4
+ See the below examples.
5
+
6
+ Example:
7
+ `bin/rails g apache_age:node Cat name age:integer`
8
+
9
+ This creates:
10
+ `app/nodes/cat.rb`
11
+
12
+ with the contents:
13
+ ```
14
+ class Cat
15
+ include ApacheAge::Entities::Vertex
16
+
17
+ attribute :name, :string
18
+ attribute :age, :integer
19
+
20
+ validates :name, presence: true
21
+ validates :age, presence: true
22
+
23
+ # unique node validator (remove any attributes that are not important to uniqueness)
24
+ validates_with(
25
+ ApacheAge::Validators::UniqueVertexValidator,
26
+ attributes: [:name, :age]
27
+ )
28
+ end
29
+ ```
30
+
31
+ A namespace can also be used:
32
+ `bin/rails g apache_age:node Animals/Cat name age:integer`
33
+
34
+ This creates:
35
+ `app/nodes/animals/cat.rb`
36
+
37
+ with the contents
38
+ ```
39
+ class Animals::Cat
40
+ include ApacheAge::Entities::Vertex
41
+
42
+ attribute :name, :string
43
+ attribute :age, :integer
44
+
45
+ validates :name, presence: true
46
+ validates :age, presence: true
47
+
48
+ # unique node validator (remove any attributes that are not important to uniqueness)
49
+ validates_with(
50
+ ApacheAge::Validators::UniqueVertexValidator,
51
+ attributes: [:name, :age]
52
+ )
53
+ end
54
+ ```