rails_age 0.5.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -7
  3. data/README.md +108 -57
  4. data/config/initializers/types.rb +20 -0
  5. data/lib/apache_age/edge.rb +5 -0
  6. data/lib/apache_age/entities/common_methods.rb +6 -0
  7. data/lib/apache_age/entities/edge.rb +4 -3
  8. data/lib/apache_age/entities/node.rb +53 -0
  9. data/lib/apache_age/entities/vertex.rb +1 -1
  10. data/lib/apache_age/node.rb +36 -0
  11. data/lib/apache_age/types/age_type_factory.rb +46 -0
  12. data/lib/apache_age/validators/expected_node_type.rb +17 -0
  13. data/lib/apache_age/validators/unique_node.rb +32 -0
  14. data/lib/apache_age/validators/{vertex_type_validator.rb → vertex_type_validator copy.rb } +2 -1
  15. data/lib/generators/apache_age/edge/edge_generator.rb +4 -2
  16. data/lib/generators/apache_age/edge/templates/edge.rb.tt +3 -3
  17. data/lib/generators/apache_age/{generate_entity_methods.rb → generator_entity_helpers.rb} +7 -4
  18. data/lib/generators/apache_age/generator_resource_helpers.rb +6 -0
  19. data/lib/generators/apache_age/node/node_generator.rb +4 -2
  20. data/lib/generators/apache_age/scaffold_edge/USAGE +16 -0
  21. data/lib/generators/apache_age/scaffold_edge/scaffold_edge_generator.rb +67 -0
  22. data/lib/generators/apache_age/scaffold_edge/scaffold_node_generator.rb +67 -0
  23. data/lib/generators/apache_age/scaffold_edge/templates/controller.rb.tt +50 -0
  24. data/lib/generators/apache_age/scaffold_edge/templates/views/_form.html.erb.tt +47 -0
  25. data/lib/generators/apache_age/scaffold_edge/templates/views/edit.html.erb.tt +12 -0
  26. data/lib/generators/apache_age/scaffold_edge/templates/views/index.html.erb.tt +16 -0
  27. data/lib/generators/apache_age/scaffold_edge/templates/views/new.html.erb.tt +11 -0
  28. data/lib/generators/apache_age/scaffold_edge/templates/views/partial.html.erb.tt +26 -0
  29. data/lib/generators/apache_age/scaffold_edge/templates/views/show.html.erb.tt +10 -0
  30. data/lib/generators/apache_age/scaffold_node/USAGE +16 -0
  31. data/lib/generators/apache_age/scaffold_node/scaffold_node_generator.rb +67 -0
  32. data/lib/generators/apache_age/scaffold_node/templates/controller.rb.tt +50 -0
  33. data/lib/generators/apache_age/scaffold_node/templates/views/_form.html.erb.tt +37 -0
  34. data/lib/generators/apache_age/scaffold_node/templates/views/edit.html.erb.tt +12 -0
  35. data/lib/generators/apache_age/scaffold_node/templates/views/index.html.erb.tt +16 -0
  36. data/lib/generators/apache_age/scaffold_node/templates/views/new.html.erb.tt +11 -0
  37. data/lib/generators/apache_age/scaffold_node/templates/views/partial.html.erb.tt +17 -0
  38. data/lib/generators/apache_age/scaffold_node/templates/views/show.html.erb.tt +10 -0
  39. data/lib/rails_age/version.rb +1 -1
  40. data/lib/rails_age.rb +7 -1
  41. data/lib/tasks/config_types.rake +4 -4
  42. metadata +59 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccc1964e751ea0670eeab5cc406f1d73d0ac4a188c3f0c97ff410cf0a12aa664
4
- data.tar.gz: 9de0e59661db92464c6505c9dc3d6a2eb314f35333eeb4f97d92d2f4b628275b
3
+ metadata.gz: cd10883497fc245765a9e8313265e4d06c7a602a2f83cad592ecb5a951ab488d
4
+ data.tar.gz: ce03c6dc4535e2a54dddc9f2b9df8e4b413c6aeb690ee00138c4120fe1d72ce1
5
5
  SHA512:
6
- metadata.gz: 15179f421eaa5fcf6180af0fd7865b1c69884064a2030b7f03300898eeda08d7bb2f871c43ec3b5ad1ae49db98b30cf274c582e3906fd66fe24b68812fb78b9a
7
- data.tar.gz: 1a83d773effad75f2e90f89ee06f8585fa5a9fe40104df7913b0e0470d3026b7cc160ecb8e3ce3e2f2fcf7c1831a902fb61b1140974cc5f792d15e43ee3de4f1
6
+ metadata.gz: dcb00b35abd3a931c95ffce304c079eee2d1ba1b09ee3aa17f9c9150f4bc3b55276e7670cf3925e4ae484a117bef66bddc0242efc0cbc8295da03538ae628805
7
+ data.tar.gz: d6ac9aaa1ba0b04c9a48ed320e53a4de65a74e6cb6574f42c407b0c1124fafc650def68df4c41beaad27607b6f1fa22a7962518108c2fc39cd7c0e95f76d8c09
data/CHANGELOG.md CHANGED
@@ -20,19 +20,36 @@ breaking change?: namespaces (by default) will use their own schema? (add to dat
20
20
 
21
21
  - **multiple AGE Schema**
22
22
 
23
- ## VERSION 0.5.3 - 2024-xx-xx
23
+ ## VERSION 0.5.4 - 2024-xx-xx
24
24
 
25
- - **Edge Scaffold** (generates edge, type, view and controller)
26
- * add `rails generate apache_age:edge_scaffold HasJob employee_role start_node:person end_node:company`
27
-
28
- ## VERSION 0.5.2 - 2024-xx-xx
25
+ - **Fix**
26
+ * show validation errors in scaffold views
29
27
 
30
28
  - **Edge Generator**
31
29
  * add start-/end-nodes types to edge generator (would make scaffold easier), ie:
32
30
  `rails generate apache_age:edge HasPet owner_role start_node:person end_node:pet`
33
31
  with property and specified start-/end-nodes (person and pet nodes must have already been created)
34
32
 
35
- ## VERSION 0.5.1 - 2024-xx-xx
33
+ - **Edge Scaffold** (generates edge, type, view and controller)
34
+ * add `rails generate apache_age:edge_scaffold HasJob employee_role start_node:person end_node:company`
35
+
36
+ ## VERSION 0.5.3 - 2024-06-23
37
+
38
+ - **Edge Scaffold** (generates edge, type, view and controller) - without start-/end-nodes types!?
39
+ * add `rails generate apache_age:edge_scaffold HasJob employee_role`
40
+ * add system test (to dummy app after scaffold_node is run)
41
+
42
+ - **Node Scaffold** (generates node, type, view and controller)
43
+ * add system test (to dummy app after scaffold_node is run)
44
+
45
+ ## VERSION 0.5.2 - 2024-06-16
46
+
47
+ - **Node Scaffold** (generates node, type, view and controller)
48
+ * add `rails generate apache_age:node_scaffold Person first_name last_name age:integer`
49
+
50
+ ## VERSION 0.5.1 - 2024-06-16 (yanked)
51
+
52
+ **yanked** (2024-06-16) - had an issue with the generator
36
53
 
37
54
  - **Node Scaffold** (generates node, type, view and controller)
38
55
  * add `rails generate apache_age:node_scaffold Person first_name last_name age:integer`
@@ -43,7 +60,7 @@ breaking change?: namespaces (by default) will use their own schema? (add to dat
43
60
 
44
61
  - **Edge Generator**
45
62
  * add `rails generate apache_age:edge HasPet owner_role`
46
- caveate: start_node and end_node are of type `:vertex` in the generator but can be changed manually in the class file - having trouble with the generator loading the types (the generator rejects custom types - but rails still works with custom types)
63
+ caveate: start_node and end_node are of type `:node` in the generator but can be changed manually in the class file - having trouble with the generator loading the types (the generator rejects custom types - but rails still works with custom types)
47
64
 
48
65
  ## VERSION 0.4.1 - 2024-06-15
49
66
 
data/README.md CHANGED
@@ -1,25 +1,76 @@
1
1
  # RailsAge
2
2
 
3
- Simplify Apache Age usage within a Rails application.
3
+ Apache Age integration within a Rails application.
4
4
 
5
- ## Installation
5
+ ## Quick Start - Essentials
6
6
 
7
7
  **NOTE:** you must be using Postgres as your database! Apache Age requires it.
8
8
 
9
- Add this line to your application's Gemfile:
9
+ ```bash
10
+ bundle add rails_age
11
+ bundle install
12
+ bin/rails apache_age:install
13
+ # optional: prevents `bin/rails db:migrate` from modifying the schema file,
14
+ # bin/rails apache_age:override_db_migrate
15
+ git add .
16
+ git commit -m "Add & configure Apache Age within Rails"
17
+ ```
18
+
19
+ ## Generators
20
+
21
+ **NODES**
22
+
23
+ ```bash
24
+ rails generate apache_age:scaffold_node Company company_name
25
+
26
+ rails generate apache_age:scaffold_node Person first_name last_name
27
+ ```
28
+
29
+ **EDGES**
10
30
 
31
+ ```bash
32
+ rails generate apache_age:scaffold_edge HasJob employee_role start_date:date
33
+ ```
34
+
35
+ Ideally, edit the HasJob class so that `start_node` would use a type `:person` and the `end_node` uses at type `:company`
36
+
37
+ ie:
11
38
  ```ruby
12
- gem "rails_age"
39
+ # app/edges/has_job.rb
40
+ class HasJob
41
+ include ApacheAge::Entities::Edge
42
+
43
+ attribute :employee_role, :string
44
+ attribute :start_node, :person # instead of `:node`
45
+ attribute :end_node, :company # instead of `:node`
46
+
47
+ validates :employee_role, presence: true
48
+ validate :validate_unique_edge
49
+
50
+ private
51
+
52
+ def validate_unique_edge
53
+ ApacheAge::Validators::UniqueEdge
54
+ .new(attributes: %i[employee_role start_node end_node])
55
+ .validate(self)
56
+ end
57
+ end
13
58
  ```
14
59
 
15
- ## Quick Start
60
+ ## Installation in Detail
16
61
 
17
62
  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
63
 
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:
64
+ ### Install Apache Age
65
+
66
+ see: [Apache AGE Installation](https://age.apache.org/age-manual/master/intro/setup.html#installation)
67
+ (The docker install is probably the easiest way to get started with a new application - for existing applications you may need to compile the extension from source.)
68
+
69
+ Verify your PostgreSQL AGE with the following commands:
70
+
21
71
  ```bash
22
- psql -h localhost -p 5455 -U docker_username
72
+ $ psql -h localhost -p 5455 -U docker_username
73
+
23
74
  > CREATE EXTENSION IF NOT EXISTS age;
24
75
  > LOAD 'age';
25
76
  > SET search_path = ag_catalog, "$user", public;
@@ -27,7 +78,12 @@ psql -h localhost -p 5455 -U docker_username
27
78
  > \q
28
79
  ```
29
80
 
81
+ ### Install and Configure Rails (if not done already)
82
+
83
+ AGE REQUIRES POSTGRESQL!
84
+
30
85
  create a new Rails app (WITH POSTGRESQL!)
86
+
31
87
  ```bash
32
88
  rails new age_demo -d postgresql
33
89
  cd age_demo
@@ -35,6 +91,7 @@ git add .
35
91
  git commit -m "Initial Rails App"
36
92
  ```
37
93
  configure `config/database.yml` when using the docker version of AGE DB my config looks like:
94
+
38
95
  ```yaml
39
96
  port: 5455
40
97
  host: localhost
@@ -42,15 +99,19 @@ username: docker_username
42
99
  password: dockerized_password
43
100
  ```
44
101
 
45
- now you should be able to create the rails database:
102
+ If both the Rails DB config and AGE DB are correctly configured, you should be able to run the following command without error:
103
+
46
104
  ```bash
47
105
  rails db:create
48
106
  rails db:migrate
49
107
  git add .
50
- git commit -m "Add Apache Age Postgres DB configured with Rails App"
108
+ git commit -m "Basic Rails Configuration"
51
109
  ```
52
110
 
53
- install Apache Age (you can ignore the `unknown OID` warnings)
111
+ ### install Apache Age Plugin
112
+
113
+ NOTE: _ignore the `unknown OID` warnings_
114
+
54
115
  ```bash
55
116
  bundle add rails_age
56
117
  bundle install
@@ -62,62 +123,52 @@ git add .
62
123
  git commit -m "Add & configure Apache Age within Rails"
63
124
  ```
64
125
 
65
- make some nodes :string is the default type
126
+ ### Optional Migration override (OPTIONAL)
127
+
128
+ run `bin/rails apache_age:override_db_migrate` to ensure that running `rails db:migrate` does not inappropriately modify the schema file.
129
+
130
+ However, if you are familiar with the schema file and git then you can safely ignore this step and manage the changes after a migration manually - only submitting changes directly related to the newest migration and not those related AGE.
131
+
132
+ **NOTE:**
133
+ * **You can run `bin/rails apache_age:config_schema` at any time to repair the schema file as needed.**
134
+ ( **You can run `bin/rails apache_age:install` at any time to repair any AGE related config file**
135
+
136
+ If you are using `db/structure.sql` you will need to manually configure Apache Age (RailsAge).
137
+
138
+ ### NODE Scaffold Generation
139
+
66
140
  ```bash
67
- rails generate apache_age:node Company company_name
68
- rails generate apache_age:node Person first_name last_name
69
- rails generate apache_age:node Pet pet_name:string age:integer
141
+ rails generate apache_age:scaffold_node Company company_name:string
142
+
143
+ # string is the default type (so it can be omitted)
144
+ rails generate apache_age:scaffold_node Person first_name last_name
145
+
146
+ # with a namespace
147
+ rails generate apache_age:scaffold_node Animals/Pet pet_name birthdate:date
70
148
  ```
71
- make some edges (`:vertex` is the default type) for start_node and end_node
149
+
150
+ ### EDGE Scaffold Generation**
151
+
152
+ NOTE: the generator will only allow `:node` (default type) for start_node and end_node, however, it is strongly recommended to specify the start_node and end_node types manually. _Hopefully, I can find a way to get the generators to recognize and allow the usage of custom node types. Thus eventually, I hope: `rails generate apache_age:node HasPet start_node:person end_node:pet caretaker_role` will work._
153
+
72
154
  ```bash
73
- # when start node and end node are not specified they are of type `:vertex`
74
- # this is generally not recommended - exept when very generic relationships are needed
75
155
  rails generate apache_age:edge HasJob employee_role begin_date:date
76
-
77
- # # this is recommended - (but not yet working) add explicit start_node and end_node types manually
78
- # rails generate apache_age:node HasPet start_node:person end_node:pet caretaker_role
79
156
  ```
80
157
 
81
- **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.**
82
-
83
- For now, if you are using `db/structure.sql` you will need to manually configure Apache Age (RailsAge) as described below.
158
+ _edge scaffold is coming soon._
84
159
 
85
- ### Rails Console Usage
160
+ ```bash
161
+ # without a namespace
162
+ rails generate apache_age:scaffold_edge HasPet caretaker_role
86
163
 
87
- ```ruby
88
- bin/rails c
89
-
90
- fred = Person.new(first_name: 'Fredrick Jay', last_name: 'Flintstone')
91
- fred.valid?
92
- fred.save
93
- fred.to_h # should have an ID
94
-
95
- # fails because of a missing required field (Property)
96
- incomplete = Person.new(first_name: 'Fredrick Jay')
97
- incomplete.valid?
98
- incomplete.errors
99
- incomplete.to_h
100
-
101
- # fails because of uniqueness constraints
102
- jay = Person.create(first_name: 'Fredrick Jay', last_name: 'Flintstone')
103
- jay.to_h
104
- => {:id=>nil, :first_name=>"Fredrick Jay", :last_name=>"Flintstone"}
105
- jay.valid?
106
- => false
107
- jay.errors
108
- => #<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={}>]>
109
- irb(main):008> jav.to_h
110
- => {:id=>nil, :first_name=>"Fredrick Jay", :last_name=>"Flintstone"}
111
-
112
- # .create is a shortcut for .new and .save
113
- quarry = Company.create(company_name: 'Bedrock Quarry')
114
- quarry.to_h # should have an ID
115
-
116
- # create an edge (no generator yet)
117
- job = HasJob.create(start_node: fred, end_node: quarry, employee_role: 'Crane Operator')
118
- job.to_h # should have an ID
164
+ # with a namespace
165
+ rails generate apache_age:scaffold_edge People/HasSpouse spousal_role
119
166
  ```
120
167
 
168
+ ### AGE Usage within Rails Console
169
+
170
+ see [AGE Usage within Rails Console](AGE_CONSOLE_USAGE.md)
171
+
121
172
  ## Manual Install, Config and Usage
122
173
 
123
174
  see [Manuel Installation, Configuration and Usage](MANUAL_INSTALL.md)
@@ -0,0 +1,20 @@
1
+ # config/initializers/types.rb
2
+
3
+ require 'apache_age/types/age_type_factory'
4
+ # USAGE (with edges or nodes) - ie:
5
+ # require_dependency 'nodes/company'
6
+ # ActiveModel::Type.register(
7
+ # :company, ApacheAge::Types::AgeTypeFactory.create_type_for(Nodes::Company)
8
+ # )
9
+
10
+ Rails.application.config.to_prepare do
11
+ # Register AGE types
12
+ require_dependency 'apache_age/node'
13
+ ActiveModel::Type.register(
14
+ :node, ApacheAge::Types::AgeTypeFactory.create_type_for(ApacheAge::Node)
15
+ )
16
+ require_dependency 'apache_age/edge'
17
+ ActiveModel::Type.register(
18
+ :edge, ApacheAge::Types::AgeTypeFactory.create_type_for(ApacheAge::Edge)
19
+ )
20
+ end
@@ -0,0 +1,5 @@
1
+ module ApacheAge
2
+ class Edge
3
+ include ApacheAge::Entities::Edge
4
+ end
5
+ end
@@ -7,6 +7,12 @@ module ApacheAge
7
7
  def persisted? = id.present?
8
8
  def to_s = ":#{age_label} #{properties_to_s}"
9
9
 
10
+ # default display value
11
+ def display
12
+ info = age_properties&.values&.first
13
+ info.blank? ? "#{age_label} (#{id})" : "#{info} (#{age_label})"
14
+ end
15
+
10
16
  def to_h
11
17
  base_h = attributes.to_hash
12
18
  if age_type == 'edge'
@@ -9,11 +9,12 @@ module ApacheAge
9
9
  include ActiveModel::Attributes
10
10
 
11
11
  attribute :id, :integer
12
+ # attribute :label, :string
12
13
  attribute :end_id, :integer
13
14
  attribute :start_id, :integer
14
- # type: `:vertex` can be overriden with a specific node type
15
- attribute :end_node, :vertex
16
- attribute :start_node, :vertex
15
+ # override with a specific node type in the defining class
16
+ attribute :end_node
17
+ attribute :start_node
17
18
 
18
19
  validates :end_node, :start_node, presence: true
19
20
  validate :validate_nodes
@@ -0,0 +1,53 @@
1
+ module ApacheAge
2
+ module Entities
3
+ module Vertex
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include ActiveModel::Model
8
+ include ActiveModel::Dirty
9
+ include ActiveModel::Attributes
10
+
11
+ attribute :id, :integer
12
+
13
+ extend ApacheAge::Entities::ClassMethods
14
+ include ApacheAge::Entities::CommonMethods
15
+ end
16
+
17
+ def age_type = 'vertex'
18
+
19
+ # AgeSchema::Nodes::Company.create(company_name: 'Bedrock Quarry')
20
+ # SELECT *
21
+ # FROM cypher('age_schema', $$
22
+ # CREATE (company:Company {company_name: 'Bedrock Quarry'})
23
+ # RETURN company
24
+ # $$) as (Company agtype);
25
+ def create_sql
26
+ alias_name = age_alias || age_label.downcase
27
+ <<-SQL
28
+ SELECT *
29
+ FROM cypher('#{age_graph}', $$
30
+ CREATE (#{alias_name}#{self})
31
+ RETURN #{alias_name}
32
+ $$) as (#{age_label} agtype);
33
+ SQL
34
+ end
35
+
36
+ # So far just properties of string type with '' around them
37
+ def update_sql
38
+ alias_name = age_alias || age_label.downcase
39
+ set_caluse =
40
+ age_properties.map { |k, v| v ? "#{alias_name}.#{k} = '#{v}'" : "#{alias_name}.#{k} = NULL" }.join(', ')
41
+ <<-SQL
42
+ SELECT *
43
+ FROM cypher('#{age_graph}', $$
44
+ MATCH (#{alias_name}:#{age_label})
45
+ WHERE id(#{alias_name}) = #{id}
46
+ SET #{set_caluse}
47
+ RETURN #{alias_name}
48
+ $$) as (#{age_label} agtype);
49
+ SQL
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,6 +1,6 @@
1
1
  module ApacheAge
2
2
  module Entities
3
- module Vertex
3
+ module Node
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
@@ -0,0 +1,36 @@
1
+ module ApacheAge
2
+ class Node
3
+ include ApacheAge::Entities::Node
4
+
5
+ attribute :label, :string
6
+ attribute :properties
7
+ # attribute :properties, :hash
8
+
9
+ # def display = [label, properties&.values&.first].compact.join(' - ')
10
+ def display
11
+ info = properties&.values&.first
12
+ info.blank? ? "#{label} (#{id})" : "#{info} (#{label})"
13
+ end
14
+
15
+ def self.all
16
+ all_nodes_sql = <<~SQL
17
+ SELECT *
18
+ FROM cypher('age_schema', $$
19
+ MATCH (node)
20
+ RETURN node
21
+ $$) as (node agtype);
22
+ SQL
23
+ age_results = ActiveRecord::Base.connection.execute(all_nodes_sql)
24
+ return [] if age_results.values.count.zero?
25
+
26
+ age_results.values.map do |result|
27
+ json_string = result.first.split('::').first
28
+ hash = JSON.parse(json_string)
29
+ attribs = hash.slice('id', 'label').symbolize_keys
30
+ attribs[:properties] = hash['properties'].symbolize_keys
31
+
32
+ new(**attribs)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ # lib/apache_age/types/age_type_factory.rb
2
+ # Automatically generates ActiveModel::Type classes
3
+ # Dynamically builds this (as a concrete example):
4
+ # module ApacheAge
5
+ # module Types
6
+ # class CompanyType < ActiveModel::Type::Value
7
+ # def cast(value)
8
+ # case value
9
+ # when Nodes::Company
10
+ # value
11
+ # when Hash
12
+ # Nodes::Company.new(value)
13
+ # else
14
+ # nil
15
+ # end
16
+ # end
17
+ # def serialize(value)
18
+ # value.is_a?(Nodes::Company) ? value.attributes : nil
19
+ # end
20
+ # end
21
+ # end
22
+ # end
23
+ module ApacheAge
24
+ module Types
25
+ class AgeTypeFactory
26
+ def self.create_type_for(klass)
27
+ Class.new(ActiveModel::Type::Value) do
28
+ define_method(:cast) do |value|
29
+ case value
30
+ when klass
31
+ value
32
+ when Hash
33
+ klass.new(value)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ define_method(:serialize) do |value|
40
+ value.is_a?(klass) ? value.attributes : nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ module ApacheAge
2
+ module Validators
3
+ module ExpectedNodeType
4
+ def
5
+ # Register the AGE types vertex_attribute(attribute_name, type_symbol, klass)
6
+ attribute attribute_name, type_symbol
7
+
8
+ validate do
9
+ value = send(attribute_name)
10
+ unless value.is_a?(klass)
11
+ errors.add(attribute_name, "must be a #{klass.name}")
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ # lib/apache_age/validators/unique_node.rb
2
+
3
+ # Usage:
4
+ # validates_with(
5
+ # ApacheAge::Validators::UniqueNode,
6
+ # attributes: [:first_name, :last_name, :gender]
7
+ # )
8
+
9
+ module ApacheAge
10
+ module Validators
11
+ class UniqueNode < ActiveModel::Validator
12
+ def validate(record)
13
+ allowed_keys = record.age_properties.keys
14
+ attributes = options[:attributes]
15
+ return if attributes.blank?
16
+
17
+ record_attribs =
18
+ attributes
19
+ .map { |attr| [attr, record.send(attr)] }
20
+ .to_h.symbolize_keys
21
+ .slice(*allowed_keys)
22
+ query = record.class.find_by(record_attribs)
23
+
24
+ # if no match is found or if it finds itself, it's valid
25
+ return if query.blank? || (query.id == record.id)
26
+
27
+ record.errors.add(:base, 'record not unique')
28
+ attributes.each { record.errors.add(_1, 'property combination not unique') }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,7 @@
1
1
  module ApacheAge
2
2
  module VertexTypeValidator
3
- def vertex_attribute(attribute_name, type_symbol, klass)
3
+ def
4
+ # Register the AGE typesvertex_attribute(attribute_name, type_symbol, klass)
4
5
  attribute attribute_name, type_symbol
5
6
 
6
7
  validate do
@@ -2,13 +2,15 @@
2
2
  require 'rails/generators'
3
3
  require 'rails/generators/named_base'
4
4
 
5
- require_relative '../generate_entity_methods'
5
+ require_relative '../generator_entity_helpers'
6
6
  # TODO: get generators to work with custom types!
7
7
  # require_relative "#{Rails.root}/config/initializers/types"
8
8
 
9
9
  module ApacheAge
10
10
  class EdgeGenerator < Rails::Generators::NamedBase
11
- include ApacheAge::GenerateEntityMethods
11
+ include ApacheAge::GeneratorEntityHelpers
12
+
13
+ desc "Generates edge (model) with attributes."
12
14
 
13
15
  source_root File.expand_path('templates', __dir__)
14
16
  argument :attributes, type: :array, default: [], banner: "field:type field:type"
@@ -4,10 +4,10 @@ class <%= class_name %>
4
4
  <%- attributes_list.each do |attribute| -%>
5
5
  attribute :<%= attribute[:name] %>, :<%= attribute[:reference] || attribute[:type] %>
6
6
  <%- end -%>
7
- # recommendation for (start_node and end_node): change `:vertex` with the 'node' type
7
+ # recommendation for (start_node and end_node): change `:node` with the actual 'node' type
8
8
  # see `config/initializers/apache_age.rb` for the list of available node types
9
- attribute :start_node, :vertex
10
- attribute :end_node, :vertex
9
+ attribute :start_node
10
+ attribute :end_node
11
11
 
12
12
  <%- attributes_list.each do |attribute| -%>
13
13
  validates :<%= attribute[:name] %>, presence: true
@@ -1,14 +1,17 @@
1
- # lib/generators/apache_age/generate_entity_methods.rb
1
+ # lib/generators/apache_age/generator_entity_helpers.rb
2
2
 
3
3
  module ApacheAge
4
- module GenerateEntityMethods
4
+ module GeneratorEntityHelpers
5
5
  def generate_age_entity(age_type)
6
- template "#{age_type}.rb.tt", File.join(destination_root, "app/#{age_type}s", class_path, "#{file_name}.rb")
6
+ template(
7
+ "#{age_type}.rb.tt",
8
+ File.join(Rails.root, "app/#{age_type}s", class_path, "#{file_name}.rb")
9
+ )
7
10
  add_type_config
8
11
  end
9
12
 
10
13
  def destroy_age_entity(age_type)
11
- file_path = File.join(destination_root, "app/#{age_type}s", class_path, "#{file_name}.rb")
14
+ file_path = File.join(Rails.root, "app/#{age_type}s", class_path, "#{file_name}.rb")
12
15
  File.delete(file_path) if File.exist?(file_path)
13
16
  remove_type_config
14
17
  end
@@ -0,0 +1,6 @@
1
+ module ApacheAge
2
+ # Some helpers for generating scaffolding
3
+ module GeneratorResourceHelpers
4
+
5
+ end
6
+ end
@@ -2,11 +2,13 @@
2
2
  require 'rails/generators'
3
3
  require 'rails/generators/named_base'
4
4
 
5
- require_relative '../generate_entity_methods'
5
+ require_relative '../generator_entity_helpers'
6
6
 
7
7
  module ApacheAge
8
8
  class NodeGenerator < Rails::Generators::NamedBase
9
- include ApacheAge::GenerateEntityMethods
9
+ include ApacheAge::GeneratorEntityHelpers
10
+
11
+ desc "Generates node (model) with attributes."
10
12
 
11
13
  source_root File.expand_path('templates', __dir__)
12
14
  argument :attributes, type: :array, default: [], banner: "field:type field:type"
@@ -0,0 +1,16 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ bin/rails generate apache_age:scaffold_edge HasPet careciver_role
6
+
7
+ This will create:
8
+ create app/edge/has_pet.rb
9
+ modified: config/initializers/types.rb
10
+ create app/controllers/has_pets_controller.rb
11
+ route resources :has_pets
12
+ create app/views/pets/index.html.erb
13
+ create app/views/pets/edit.html.erb
14
+ create app/views/pets/show.html.erb
15
+ create app/views/pets/new.html.erb
16
+ create app/views/pets/partial.html.erb