rails_age 0.5.0 → 0.5.3

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.
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