ashikawa-ar 0.1.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.
- data/.gitignore +18 -0
- data/.rvmrc +1 -0
- data/.travis.yml +13 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +4 -0
- data/Guardfile +18 -0
- data/LICENSE +202 -0
- data/README.md +15 -0
- data/Rakefile +54 -0
- data/ashikawa-ar.gemspec +38 -0
- data/lib/ashikawa-ar.rb +8 -0
- data/lib/ashikawa-ar/base.rb +48 -0
- data/lib/ashikawa-ar/exceptions/invalid_record.rb +6 -0
- data/lib/ashikawa-ar/exceptions/unsaved_record.rb +6 -0
- data/lib/ashikawa-ar/model.rb +24 -0
- data/lib/ashikawa-ar/persistence.rb +200 -0
- data/lib/ashikawa-ar/search.rb +89 -0
- data/lib/ashikawa-ar/setup.rb +18 -0
- data/lib/ashikawa-ar/version.rb +5 -0
- data/lib/rails/generators/ashikawa/model_generator.rb +23 -0
- data/lib/rails/generators/ashikawa/templates/model.rb.tt +7 -0
- data/spec/examples/person.rb +10 -0
- data/spec/integration/arango_helper.rb +27 -0
- data/spec/integration/basic_spec.rb +22 -0
- data/spec/integration/model_spec.rb +23 -0
- data/spec/integration/persistence_spec.rb +155 -0
- data/spec/integration/search_spec.rb +47 -0
- data/spec/integration/spec_helper.rb +6 -0
- data/spec/unit/spec_helper.rb +2 -0
- metadata +307 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "virtus"
|
|
2
|
+
require "aequitas"
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
require "ashikawa-ar/base"
|
|
5
|
+
require "ashikawa-ar/search"
|
|
6
|
+
require "ashikawa-ar/persistence"
|
|
7
|
+
|
|
8
|
+
module Ashikawa
|
|
9
|
+
module AR
|
|
10
|
+
module Model
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
include Base
|
|
13
|
+
include Search
|
|
14
|
+
include Persistence
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
class_eval do
|
|
18
|
+
include Virtus
|
|
19
|
+
include Aequitas
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
require "ashikawa-core"
|
|
2
|
+
require "ashikawa-ar/base"
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
require "ashikawa-ar/exceptions/invalid_record"
|
|
5
|
+
require "ashikawa-ar/exceptions/unsaved_record"
|
|
6
|
+
|
|
7
|
+
module Ashikawa
|
|
8
|
+
module AR
|
|
9
|
+
# Provides Persistence functionality for your model
|
|
10
|
+
module Persistence
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
# Save the document to the database returning false if invalid
|
|
13
|
+
#
|
|
14
|
+
# @return [self, false] Returns false if not saved
|
|
15
|
+
# @api public
|
|
16
|
+
# @example Save the document to the database
|
|
17
|
+
# sam = Person.new name: "Sam Lowry"
|
|
18
|
+
# sam.save
|
|
19
|
+
def save;end
|
|
20
|
+
|
|
21
|
+
# Save the document to the database throwing an exception if invalid
|
|
22
|
+
#
|
|
23
|
+
# @return [self]
|
|
24
|
+
# @raise [InvalidRecord] if the data is invalid
|
|
25
|
+
# @api public
|
|
26
|
+
# @example Save the document to the database
|
|
27
|
+
# sam = Person.new name: "Sam Lowry"
|
|
28
|
+
# sam.save!
|
|
29
|
+
def save!;end
|
|
30
|
+
|
|
31
|
+
# Save the document to the database even if it is invalid
|
|
32
|
+
#
|
|
33
|
+
# @return [self] Returns false if not saved
|
|
34
|
+
# @api public
|
|
35
|
+
# @example Save the document to the database
|
|
36
|
+
# sam = Person.new name: "Sam Lowry"
|
|
37
|
+
# sam.save_without_validation
|
|
38
|
+
def save_without_validation;end
|
|
39
|
+
|
|
40
|
+
# Reload the record from the database
|
|
41
|
+
#
|
|
42
|
+
# @return [self]
|
|
43
|
+
# @raise [UnsavedRecord] if the data is not yet saved
|
|
44
|
+
# @api public
|
|
45
|
+
# @example Get the updated version from the database
|
|
46
|
+
# sam.reload
|
|
47
|
+
def reload;end
|
|
48
|
+
|
|
49
|
+
# Delete the record from the database
|
|
50
|
+
#
|
|
51
|
+
# @return [self]
|
|
52
|
+
# @raise [UnsavedRecord] if the data is not yet saved
|
|
53
|
+
# @api public
|
|
54
|
+
# @example Get the updated version from the database
|
|
55
|
+
# sam.delete
|
|
56
|
+
def delete;end
|
|
57
|
+
|
|
58
|
+
# Update a single attribute and write to the database
|
|
59
|
+
#
|
|
60
|
+
# @param [String] key Name of the attribute
|
|
61
|
+
# @param [Object] value Value of the attribute
|
|
62
|
+
# @return [self]
|
|
63
|
+
# @raise [UnsavedRecord] if the data is not yet saved
|
|
64
|
+
# @api public
|
|
65
|
+
# @example Update the age
|
|
66
|
+
# sam.update_attribute "age", 39
|
|
67
|
+
def update_attribute(key, value);end
|
|
68
|
+
|
|
69
|
+
# Updates multiple attributes and write to the database
|
|
70
|
+
# returning false if they are invalid
|
|
71
|
+
#
|
|
72
|
+
# @param [Hash] attributes
|
|
73
|
+
# @return [self, false]
|
|
74
|
+
# @raise [UnsavedRecord] if the data is not yet saved
|
|
75
|
+
# @api public
|
|
76
|
+
# @example Update the age and favorite color
|
|
77
|
+
# sam.update_attributes age: 39, favorite_color: "Green"
|
|
78
|
+
def update_attributes(attributes);end
|
|
79
|
+
|
|
80
|
+
# Updates multiple attributes and write to the database
|
|
81
|
+
# throwing an exception if they are invalid
|
|
82
|
+
#
|
|
83
|
+
# @param [Hash] attributes
|
|
84
|
+
# @return [self]
|
|
85
|
+
# @raise [InvalidRecord] if the data is invalid
|
|
86
|
+
# @raise [UnsavedRecord] if the data is not yet saved
|
|
87
|
+
# @api public
|
|
88
|
+
# @example Update the age and favorite color
|
|
89
|
+
# sam.update_attributes! age: 39, favorite_color: "Green"
|
|
90
|
+
def update_attributes!(attributes);end
|
|
91
|
+
|
|
92
|
+
# Check, if the object has been persisted
|
|
93
|
+
#
|
|
94
|
+
# @return [Boolean]
|
|
95
|
+
# @api public
|
|
96
|
+
# @example Check, if sam is persisted
|
|
97
|
+
# sam.persisted?
|
|
98
|
+
def persisted?;end
|
|
99
|
+
|
|
100
|
+
# Check, if the object has been deleted
|
|
101
|
+
#
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
# @api public
|
|
104
|
+
# @example Check, if sam is deleted
|
|
105
|
+
# sam.deleted?
|
|
106
|
+
def deleted?;end
|
|
107
|
+
|
|
108
|
+
# Check, if the object is a new record
|
|
109
|
+
#
|
|
110
|
+
# @return [Boolean]
|
|
111
|
+
# @api public
|
|
112
|
+
# @example Check, if sam is a new record
|
|
113
|
+
# sam.new_record?
|
|
114
|
+
def new_record?;end
|
|
115
|
+
|
|
116
|
+
included do
|
|
117
|
+
class_eval do
|
|
118
|
+
def save
|
|
119
|
+
return false unless self.valid?
|
|
120
|
+
save_without_validation
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def save!
|
|
124
|
+
raise InvalidRecord unless self.valid?
|
|
125
|
+
save_without_validation
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def save_without_validation
|
|
129
|
+
if @id.nil?
|
|
130
|
+
response = self.class.collection.create self.attributes
|
|
131
|
+
@id = response.id
|
|
132
|
+
else
|
|
133
|
+
self.class.collection[@id] = self.attributes
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@status = :persisted
|
|
137
|
+
|
|
138
|
+
self
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def check_if_saved!
|
|
142
|
+
raise UnsavedRecord if @id.nil?
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def reload
|
|
146
|
+
check_if_saved!
|
|
147
|
+
self.attributes = self.class.collection[@id]
|
|
148
|
+
self
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def delete
|
|
152
|
+
check_if_saved!
|
|
153
|
+
self.class.collection[@id].delete
|
|
154
|
+
@id = nil
|
|
155
|
+
@status = :deleted
|
|
156
|
+
self
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
alias :destroy :delete
|
|
160
|
+
|
|
161
|
+
def update_attribute(key, value)
|
|
162
|
+
check_if_saved!
|
|
163
|
+
self[key] = value
|
|
164
|
+
self.save
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def update_attributes(attributes)
|
|
168
|
+
check_if_saved!
|
|
169
|
+
attributes.each_pair do |key, value|
|
|
170
|
+
self[key] = value
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
self.save
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def update_attributes!(attributes)
|
|
177
|
+
check_if_saved!
|
|
178
|
+
attributes.each_pair do |key, value|
|
|
179
|
+
self[key] = value
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
self.save!
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def persisted?
|
|
186
|
+
@status == :persisted
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def deleted?
|
|
190
|
+
@status == :deleted
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def new_record?
|
|
194
|
+
@status.nil?
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require "ashikawa-core"
|
|
2
|
+
require "ashikawa-ar/base"
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Ashikawa
|
|
6
|
+
module AR
|
|
7
|
+
# Provides Search functionality for your model
|
|
8
|
+
module Search
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
# Find a document of the collection by ID
|
|
11
|
+
#
|
|
12
|
+
# @param [Fixnum] id ID of the document
|
|
13
|
+
# @return [Instance of Class]
|
|
14
|
+
# @api public
|
|
15
|
+
# @example Find a document by its ID
|
|
16
|
+
# person = Person.find my_id
|
|
17
|
+
# person.name #=> Johnny
|
|
18
|
+
def self.find(id);end
|
|
19
|
+
|
|
20
|
+
# Find a document using an AQL query
|
|
21
|
+
#
|
|
22
|
+
# @param [String] query The Query
|
|
23
|
+
# @return [Array<Instance of Class>]
|
|
24
|
+
# @api public
|
|
25
|
+
# @example Find documents with an AQL query
|
|
26
|
+
# people = Person.find_by_aql "FOR u IN people RETURN u"
|
|
27
|
+
# people.first.name #=> Johnny
|
|
28
|
+
def self.find_by_aql(query);end
|
|
29
|
+
|
|
30
|
+
# Find all documents with the provided attributes
|
|
31
|
+
#
|
|
32
|
+
# @param [Hash] example The attributes
|
|
33
|
+
# @return [Array<Instance of Class>]
|
|
34
|
+
# @api public
|
|
35
|
+
# @example Find a document by example
|
|
36
|
+
# people = Person.by_example name: "Johnny"
|
|
37
|
+
# people.first.name #=> Johnny
|
|
38
|
+
def self.by_example(example);end
|
|
39
|
+
|
|
40
|
+
# Find the first document with the provided attributes
|
|
41
|
+
#
|
|
42
|
+
# @param [Hash] example The attributes
|
|
43
|
+
# @return [Instance of Class]
|
|
44
|
+
# @api public
|
|
45
|
+
# @example Find a document by example
|
|
46
|
+
# people = Person.first_example name: "Johnny"
|
|
47
|
+
# people.name #=> Johnny
|
|
48
|
+
def self.first_example(example);end
|
|
49
|
+
|
|
50
|
+
# Find all documents
|
|
51
|
+
#
|
|
52
|
+
# @return [Array<Instance of Class>]
|
|
53
|
+
# @api public
|
|
54
|
+
# @example Find all documents
|
|
55
|
+
# people = Person.people
|
|
56
|
+
# people.first.name #=> Johnny
|
|
57
|
+
def self.all;end
|
|
58
|
+
|
|
59
|
+
included do
|
|
60
|
+
class_eval do
|
|
61
|
+
def self.find(id)
|
|
62
|
+
result = collection[id]
|
|
63
|
+
from_raw_document result
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.find_by_aql(query)
|
|
67
|
+
results = database.query query
|
|
68
|
+
from_raw_documents results
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.by_example(example)
|
|
72
|
+
results = collection.by_example example: example
|
|
73
|
+
from_raw_documents results
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.first_example(example)
|
|
77
|
+
result = collection.first_example example
|
|
78
|
+
self.new result.to_hash["document"]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.all
|
|
82
|
+
results = collection.all
|
|
83
|
+
from_raw_documents results
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "ashikawa-core"
|
|
2
|
+
|
|
3
|
+
module Ashikawa
|
|
4
|
+
module AR
|
|
5
|
+
def self.raw_setup(name, database)
|
|
6
|
+
Setup.databases[name] = database
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.setup(name, location)
|
|
10
|
+
Setup.databases[name] = Ashikawa::Core::Database.new location
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class Setup
|
|
14
|
+
class << self; attr_accessor :databases end
|
|
15
|
+
@databases = {}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Ashikawa
|
|
2
|
+
module Generators
|
|
3
|
+
# Generates a Model using Ashikawa::AR for Rails
|
|
4
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
6
|
+
|
|
7
|
+
desc "Creates an Ashikawa::AR model"
|
|
8
|
+
argument :attributes,
|
|
9
|
+
type: :array,
|
|
10
|
+
default: [],
|
|
11
|
+
banner: "attribute[:type] attribute[:type]"
|
|
12
|
+
|
|
13
|
+
check_class_collision
|
|
14
|
+
|
|
15
|
+
def create_model_file
|
|
16
|
+
template "model.rb.tt",
|
|
17
|
+
File.join("app/models", class_path, "#{file_name}.rb")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
hook_for :test_framework
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
RSpec.configure do |config|
|
|
2
|
+
raise "Could not find arangod. Please install it or check if it is in your path." if `which arangod` == ""
|
|
3
|
+
|
|
4
|
+
database_directory = "/tmp/ashikawa-integration"
|
|
5
|
+
arango_process = false
|
|
6
|
+
|
|
7
|
+
config.before(:suite) do
|
|
8
|
+
puts "Starting ArangoDB"
|
|
9
|
+
process_id = $$
|
|
10
|
+
|
|
11
|
+
Dir.mkdir database_directory unless Dir.exists? database_directory
|
|
12
|
+
arango_process = IO.popen("arangod #{database_directory} --watch-process #{process_id}")
|
|
13
|
+
|
|
14
|
+
sleep 2 # Wait for Arango to start up
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
config.after(:suite) do
|
|
18
|
+
puts
|
|
19
|
+
puts "Shutting down ArangoDB"
|
|
20
|
+
|
|
21
|
+
Process.kill "INT", arango_process.pid
|
|
22
|
+
sleep 2 # Wait for Arango to shut down
|
|
23
|
+
arango_process.close
|
|
24
|
+
|
|
25
|
+
`rm -r #{database_directory}/*`
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'integration/spec_helper'
|
|
2
|
+
require 'examples/person.rb'
|
|
3
|
+
|
|
4
|
+
describe "Basics" do
|
|
5
|
+
it "should recognize the truth" do
|
|
6
|
+
true.should be_true
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe "basic functionality" do
|
|
10
|
+
subject { Person }
|
|
11
|
+
|
|
12
|
+
it "should provide virtus and aequitas" do
|
|
13
|
+
person = subject.new name: "George", age: "33"
|
|
14
|
+
person.age.should == 33
|
|
15
|
+
person.valid?.should be_true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should provide the collection name" do
|
|
19
|
+
subject.model_name.collection.should == "people"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|