active-orient 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e808c07b0d7ea4b6ab44772dcfbed8521f1dbe1b
4
+ data.tar.gz: d1dc78cd6f6b0b5b8da14512e54e39777479b31c
5
+ SHA512:
6
+ metadata.gz: da1131e98ac909ba6e77526f52a6c9ae608eabe9d9a0d5d3dc2bb2a702fb7454493a2de516746e00f2d6f1f60c1bb4191393f49a28da470a3f3e87c763b624cb
7
+ data.tar.gz: 883ea6e68bfe1fc3a88dc4b7d9173a1a454c6141d6dfb234286aab3de1677666a0a115a022acd36049ed9cbf490abfd153287a547c67dddb9115671daf4bf9a8
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+ gem 'activesupport' , "~>4.2"
4
+ gem 'activemodel'
5
+ gem 'rest-client', :git => 'git://github.com/rest-client/rest-client.git'
6
+ group :development, :test do
7
+ gem "rspec"
8
+ gem 'rspec-its'
9
+ gem 'rspec-collection_matchers'
10
+ gem 'rspec-context-private'
11
+ gem 'guard'
12
+ gem 'guard-rspec'
13
+ ## gem 'database_cleaner'
14
+ gem 'rb-inotify'
15
+ gem 'pry'
16
+ end
@@ -0,0 +1,21 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cmd: "bundle exec rspec" do
5
+ require "ostruct"
6
+
7
+ # Generic Ruby apps
8
+ rspec = OpenStruct.new
9
+ rspec.spec = ->(m) { "spec/#{m}_spec.rb" }
10
+ rspec.spec_dir = "spec"
11
+ rspec.spec_helper = "spec/spec_helper.rb"
12
+
13
+
14
+ watch(%r{^spec/.+_spec\.rb$})
15
+ watch(%r{^spec/usecase/(.+).rb$})
16
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
17
+ watch('spec/spec_helper.rb') { "spec" }
18
+
19
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
+ end
21
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 topofocus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,275 @@
1
+ # ActiveOrient
2
+ Use OrientDB to persistently store dynamic Ruby-Objects and use database queries to manage even very large
3
+ datasets.
4
+
5
+ The Package ist tested with Ruby 2.2.1 and Orientdb 2.1.
6
+
7
+
8
+ To start you need a ruby 2.x Installation and a working OrientDB-Instance.
9
+ Clone the project and run bundle install/ bundle update,
10
+ then modify »config/connect.yml«.
11
+ Its adviserable to generate the rdoc-documentation with executing
12
+ ```
13
+ rdoc
14
+ ```
15
+ from the source directory of AcitiveOrient and then to load the doc-directory into any browser.
16
+
17
+ For a quick start, go to the home directory of the package and start an irb-session
18
+
19
+ then
20
+
21
+ ```ruby
22
+ require './config/boot'
23
+ r = ActiveOrient::OrientDB.new database: 'First'
24
+ => #<ActiveOrient::OrientDB:0x000000048d0488 @res=#<RestClient::Resource:0x00000004927288
25
+ @url="http://localhost:2480", @block=nil,
26
+ @options={:user=>"xx", :password=>"***"}>, @database="First", @classes=[]>
27
+ ```
28
+
29
+ »r« is the Database-Instance itself. Obviously the database is empty.
30
+
31
+
32
+ Let's create some classes
33
+
34
+ ```ruby
35
+ M = r.open_class 'classname' #
36
+ M = r.create_class 'classname' # creates or opens a basic document-class
37
+ M = r.create_vertex_class 'classname' # creates or opens a vertex-class
38
+ M = r.create_edge_class 'classname' # creates or opens an edge-class, providing bidirectional links between documents
39
+
40
+ r.delete_class M # universal removal-of-the-class-method
41
+ ```
42
+
43
+
44
+ »M« is the ActiveOrient::Model-Class itself, a constant pointing to the class-definition of the ruby-class.
45
+ Its a shortcut for »ActiveOrient::Model::{Classname} and is reused if defined elsewhere.
46
+
47
+ If a schema is used, properties can be created and retrieved as well
48
+ ```ruby
49
+ r.create_properties( M ) do
50
+ { symbol: { propertyType: 'STRING' },
51
+ con_id: { propertyType: 'INTEGER' },
52
+ details: { propertyType: 'LINK', linkedClass: 'Contracts' }
53
+ }
54
+
55
+ r.get_class_properties M
56
+ ```
57
+ or
58
+ ```ruby
59
+ M.create_property 'symbol'
60
+ M.create_property 'con_id', type: 'integer'
61
+ M.create_property 'details', type: 'link', other_class: 'Contracts'
62
+ ```
63
+
64
+ #### Active Model interface
65
+
66
+ Every OrientDB-Database-Class is mirrord as Ruby-Class. The Class itself is defined by
67
+ ```ruby
68
+ M = r.create_class 'classname'
69
+ M = r.create_class { superclass_name: 'classname' }
70
+ Vertex = r.create_vertex_class 'classname'
71
+ Edge = r.create_edge_class 'classname'
72
+ ```
73
+ and is of TYPE ActiveOrient::Model::{classname}
74
+
75
+ As for ActiveRecord-Tables, the Class itself provides methods to inspect and to filter datasets form the database.
76
+
77
+ ```ruby
78
+ M.all
79
+ M.first
80
+ M.last
81
+ ```
82
+ returns an Array containing all Documents/Edges of the Class; the first and the last Record.
83
+ ```ruby
84
+ M.where town: 'Berlin'
85
+ ```
86
+ performs a query on the class and returns the result as Array
87
+
88
+ ```ruby
89
+ M.count where: { town: 'Berlin' }
90
+ ```
91
+ gets the number of datasets fullfilling the search-criteria. Any parameter defining a valid
92
+ SQL-Query in Orientdb can be provided to the count, where, first and last-method.
93
+
94
+ A »normal« Query is submitted via
95
+ ```ruby
96
+ M.get_documents projection: { projection-parameter }
97
+ distinct: { some parameters }
98
+ where: { where-parameter }
99
+ order: { sorting-parameters }
100
+ group_by: { one grouping-parameter}
101
+ unwind:
102
+ skip:
103
+ limit:
104
+
105
+ # or
106
+ query = OrientSupport::OrientQuery.new {paramter}
107
+ M.get_documents query: query
108
+
109
+ ```
110
+
111
+ Basic graph-support:
112
+
113
+
114
+
115
+ ```ruby
116
+ vertex_1 = Vertex.create color: "blue"
117
+ vertex_2 = Vertex.create flower: "rose"
118
+ Edge.create_edge attributes: { :birthday => Date.today }, from: vertex_1, to: vertex_2
119
+ ```
120
+ connects the vertices and assigns the attributes to the edge
121
+
122
+
123
+ #### Links
124
+
125
+ A record in a database-class is defined by a »rid«. Every Model-Object comes with a handy »link«-method.
126
+
127
+ In OrientDB links are used to realise unidirectional 1:1 and 1:n relationships.
128
+
129
+ ActiveOrient autoloads Model-objects when they are accessed. As a consequence,
130
+ if an Object is stored in Cluster 30 and id 2, then "#30:2" fully qualifies the ActiveOrient::Model object.
131
+
132
+ ```ruby
133
+ TestLinks = r.create_class 'Test_link_class'
134
+ TestBase = r.create_class 'Test_base_class'
135
+
136
+ link_document = TestLinks.create att: 'one attribute'
137
+ base_document = TestBase.create base: 'my_base', single_link: link_document
138
+ ```
139
+ base_document.single_link just contains the rid. When accessed, the ActiveOrient::Model::Testlinkclass-object is autoloaded and
140
+ ``` ruby
141
+ base_document.single_link.att
142
+ ```
143
+ reads the stored content of link_document.
144
+
145
+ To store a list of links to other Database-Objects a simple Array is allocated
146
+ ``` ruby
147
+ # predefined linkmap-properties
148
+ base_document = TestBase.create links: []
149
+ ( 0 .. 20 ).each{ |y| base_document.links << TestLinks.create nr: y }
150
+ end
151
+ #or in schemaless-mode
152
+ base_document = TestBase.create links: (0..20).map{|y| TestLinks.create nr: y }
153
+
154
+
155
+ ```
156
+ base_document.links behaves like a ruby-array.
157
+
158
+ If you got an undirectional graph
159
+
160
+ a --> b ---> c --> d
161
+
162
+ the graphelements can be explored by joining the objects ( a.b.c.d ), or (a.b[5].c[9].d )
163
+
164
+ #### Edges
165
+
166
+ Edges are easily handled
167
+ ```ruby
168
+ Vertex = r.create_vertex_class 'd1'
169
+ Eedge = r.create_edge_class 'e1'
170
+
171
+ start = Vertex.create something: 'nice'
172
+ the_end = Vertex.create something: 'not_nice'
173
+ the_edge = Edge.create_edge attributes: { transform_to: 'very bad' },
174
+ from: start,
175
+ to: the_end
176
+
177
+ (...)
178
+ the_edge.delete
179
+ ```
180
+
181
+ There is a basic support for traversals throught a graph.
182
+ The Edges are accessed by their names (downcase).
183
+
184
+ ```ruby
185
+ start.e1[0]
186
+ --> #<ActiveOrient::Model::E1:0x000000041e4e30
187
+ @metadata={"type"=>"d", "class"=>"E1", "version"=>60, "fieldTypes"=>"out=x,in=x",
188
+ "cluster"=>16, "record"=>43},
189
+ @attributes={"out"=>"#31:23", "in"=>"#31:15", "transform_to"=>"very bad" }>
190
+ ```
191
+ The Attributes "in" and "out" can be used to move across the graph
192
+ ```ruby
193
+ start.e1[0].out.something
194
+ ---> "not_nice
195
+ start.e1[0].in.something
196
+ ---> "nice
197
+ ```
198
+
199
+ #### Execute SQL-Commands
200
+ At least - sql-commands can be executed as batch
201
+
202
+ The ActiveOrient::Query-Class provides a Query-Stack and an Records-Array which keeps the results.
203
+ The ActiveOrient::Query-Class acts as Parent-Class for aggregated Records (without a @rid), which are ActiveOrient::Model::Myquery Objects. If a Query returns a database-record, the correct ActiveOrient::Model-Class is instantiated.
204
+
205
+ ```ruby
206
+ ach = ActiveOrient::Query.new
207
+
208
+ ach.queries << 'create class Contracts ABSTRACT'
209
+ ach.queries << 'create property Contracts.subcategory link'
210
+ ach.queries << 'create property Contracts.details link'
211
+ ach.queries << 'create class Stocks extends Contracts'
212
+ ach.queries << 'create class Futures extends Contracts'
213
+ result = ach.execute_queries transaction: false
214
+
215
+
216
+
217
+ ```
218
+ queries the database as demonstrated above. In addition, the generated query itself is added to the »queries«-Stack and the result can be found in sample_query.records.
219
+
220
+ This feature can be used as a substitute for simple functions
221
+
222
+ ```ruby
223
+ roq = ActiveOrient::Query.new
224
+ roq.queries =["select name, categories.subcategories.contracts from Industries where name containstext …'ial'"]
225
+ roq.execute_queries.each{|x| puts x.name, x.categories.inspect }
226
+ --> Basic Materials [["#21:1"]]
227
+ --> Financial [["#21:2"]]
228
+ --> Industrial [["#23:0", "#23:1"]]
229
+ ```
230
+
231
+ OrientDB supports the execution of SQL-Batch-Commands.
232
+ ( http://orientdb.com/docs/2.0/orientdb.wiki/SQL-batch.html )
233
+ This is supported simply by using a Array as Argument for ActiveOrient::Query.queries
234
+
235
+ Therefor complex queries can be simplified using database-variables
236
+ ```ruby
237
+ ach = ActiveOrient::Query.new
238
+ ach.queries << [ "select expand( contracts ) from Openinterest"
239
+ "let con = select expand( contracts ) from Openinterest; ",
240
+ "...", ... ]
241
+ result = ach.execute_queries
242
+ ```
243
+
244
+ The contract-documents are accessible with
245
+ ```ruby
246
+ r.get_document '21:1'
247
+ --><Stocks: con_id: 77680640 currency: EUR details: #18:1 exchange: SMART local_symbol: BAS
248
+ primary_exchange: IBIS subcategory: #14:1 symbol: BAS>
249
+ ```
250
+ or
251
+ ```ruby
252
+ my_query = ActiveOrient::Query.new
253
+ ['Contracts', 'Industries', 'Categories', 'Subcategories'].each do |table|
254
+ my_query.queries = [ "select count(*) from #{table}"]
255
+
256
+ count = my_query.execute_queries
257
+ # count=> [#<ActiveOrient::Model::Myquery:0x00000003b317c8
258
+ # @metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"count=l"},
259
+ # @attributes={"count"=>4 } ] --> an Array with one Element, therefor count.pop
260
+ puts "Table #{table} \t #{count.pop.count} Datasets "
261
+ end
262
+ -->Table Contracts 56 Datasets
263
+ -->Table Industries 8 Datasets
264
+ -->Table Categories 22 Datasets
265
+ -->Table Subcategories 35 Datasets
266
+
267
+ ```
268
+
269
+ Note that the fetched Object is of type »Stocks« (ActiveOrient::Model::Stocks).
270
+
271
+ The ActiveOrient-API documentation can be found here: https://github.com/orientechnologies/orientdb-docs/wiki/OrientDB-ActiveOrient
272
+ and the ActiveModel-documentation is here: http://www.rubydoc.info/gems/activemodel
273
+
274
+
275
+
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "active-orient"
6
+ s.version = File.open('VERSION').read.strip
7
+ s.authors = [" Hartmut Bischoff"]
8
+ s.email = ["topofocus@gmail.com"]
9
+ s.homepage = 'https://github.com/topofocus/active-orient'
10
+ s.licenses = ['MIT']
11
+ s.summary = 'Pure ruby client for OrientDB based on ActiveModel'
12
+ s.description = 'Persistent ORM for OrientDB, based on ActiveModel'
13
+ s.platform = Gem::Platform::RUBY
14
+ s.required_ruby_version = '>= 2.2.0'
15
+ s.date = Time.now.strftime "%Y-%m-%d"
16
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ s.bindir = "exe"
20
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+
22
+ s.add_development_dependency "bundler", "~> 1.8"
23
+ s.add_development_dependency "rake", "~> 10.0"
24
+ s.add_dependency 'activesupport'
25
+ # s.add_dependency 'rest-client', :git => 'git://github.com/rest-client/rest-client.git'
26
+
27
+ end
@@ -0,0 +1,24 @@
1
+ require 'bundler/setup'
2
+ require 'yaml'
3
+ project_root = File.expand_path('../..', __FILE__)
4
+ require "#{project_root}/lib/support.rb"
5
+ require "#{project_root}/lib/base.rb"
6
+ require "#{project_root}/lib/base_properties.rb"
7
+
8
+ require "#{project_root}/lib/model.rb"
9
+ require "#{project_root}/lib/orient.rb"
10
+ require "#{project_root}/lib/rest.rb"
11
+ #require "#{project_root}/lib/graph.rb"
12
+
13
+ # require all the models and libraries
14
+ libs= Dir.glob(File.join( project_root, "lib",'**', "*rb"))
15
+ result = libs.reverse.collect { |file| [file, require( file )] }
16
+
17
+ logger = Logger.new '/dev/stdout'
18
+ #REST::Graph.logger = logger
19
+ ActiveOrient::Model.logger = logger
20
+ ActiveOrient::OrientDB.logger = logger
21
+
22
+
23
+
24
+
@@ -0,0 +1,13 @@
1
+ ---
2
+ :orientdb:
3
+ :server: localhost
4
+ :port: 2480
5
+ :database: hc_database
6
+ :admin:
7
+ :user: hctw
8
+ :pass: hc
9
+ :auth:
10
+ :user: topo
11
+ :pass: focus
12
+
13
+ # hfx: 101
@@ -0,0 +1,220 @@
1
+ module ActiveOrient
2
+ require 'active_model'
3
+ #
4
+ # Base class for tableless IB data Models, extends ActiveModel API
5
+ class Base
6
+ extend ActiveModel::Naming
7
+ extend ActiveModel::Callbacks
8
+ include ActiveModel::Validations
9
+ include ActiveModel::Serialization
10
+ include ActiveModel::Serializers::Xml
11
+ include ActiveModel::Serializers::JSON
12
+
13
+
14
+ ##Every Rest::Base-Object is stored in the @@rid_store
15
+ ## The Objects are just references to the @@rid_store.
16
+ ## any Change of the Object is thus synchonized to any allocated variable
17
+ #
18
+ @@rid_store = Hash.new
19
+
20
+ def self.display_riid
21
+ @@rid_store
22
+ end
23
+ def self.remove_riid obj
24
+ @@rid_store[obj.riid]=nil
25
+ end
26
+ def self.get_riid link
27
+
28
+ end
29
+ def self.store_riid obj
30
+ if obj.rid.present? && obj.riid.all?{|x| x.present? && x>=0} # only positive values are stored
31
+ ## return the presence of a stored object as true by the block
32
+ ## the block is only executed if the presence is confirmed
33
+ ## Nothing is returned from the class-method
34
+ if @@rid_store[obj.riid].present?
35
+ yield if block_given?
36
+ end
37
+ @@rid_store[obj.riid] = obj
38
+ @@rid_store[obj.riid] # return_value
39
+ else
40
+ obj # no rid-value: just return the obj
41
+ end
42
+ end
43
+
44
+
45
+ define_model_callbacks :initialize
46
+
47
+ mattr_accessor :logger
48
+ # If a opts hash is given, keys are taken as attribute names, values as data.
49
+ # The model instance fields are then set automatically from the opts Hash.
50
+ def initialize attributes={}, opts={}
51
+ logger.progname= "ActiveOrient::Base#initialize"
52
+ #possible_link_array_candidates = link_candidates = Hash.new
53
+ @metadata = HashWithIndifferentAccess.new
54
+ # @edges = HashWithIndifferentAccess.new
55
+
56
+ run_callbacks :initialize do
57
+ # puts "initialize::attributes: #{attributes.inspect}"
58
+
59
+ attributes.keys.each do | att |
60
+ unless att[0] == "@" # @ identifies Metadata-attributes
61
+ att = att.to_sym if att.is_a?(String)
62
+ unless self.class.instance_methods.detect{|x| x == att }
63
+ self.class.define_property att, nil
64
+ # logger.debug { "property #{att.to_s} assigned to #{self.class.to_s}" }
65
+ else
66
+ # logger.info{ "property #{att.to_s} NOT assigned " }
67
+ end
68
+ end
69
+ end
70
+
71
+ if attributes['@type'] == 'd' # document
72
+ @metadata[ :type ] = attributes.delete '@type'
73
+ @metadata[ :class ] = attributes.delete '@class'
74
+ @metadata[ :version ] = attributes.delete '@version'
75
+ @metadata[ :fieldTypes ] = attributes.delete '@fieldTypes'
76
+ if attributes.has_key?( '@rid' )
77
+ rid = attributes.delete '@rid'
78
+ cluster, record = rid[1,rid.size].split(':')
79
+ @metadata[ :cluster ] = cluster.to_i
80
+ @metadata[ :record ] = record.to_i
81
+ end
82
+
83
+ #### edges -- remove in_ and out_ and de-capitalize the remaining edge
84
+ if @metadata[ :fieldTypes ].present? && (@metadata[ :fieldTypes ] =~ /=g/)
85
+ edges = @metadata['fieldTypes'].split(',').find_all{|x| x=~/=g/}.map{|x| x.split('=').first}
86
+ edges.each do |edge|
87
+ operator, *base_edge = edge.split('_')
88
+ base_edge = base_edge.join('_')
89
+ unless self.class.instance_methods.detect{|x| x == base_edge }
90
+ ## define two methods: out_{Edge}/{in_Edge} -> edge.
91
+ self.class.define_property base_edge, nil
92
+ self.class.send :alias_method, base_edge.underscore, edge #
93
+ # logger.debug { "#{link}:: edge #{edge} assigned to #{self.class.to_s} and remaped to #{base_edge.underscore}" }
94
+
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ self.attributes = attributes # set_attribute_defaults is now after_init callback
102
+ end
103
+ ActiveOrient::Base.store_riid self
104
+ end
105
+
106
+ # ActiveModel API (for serialization)
107
+
108
+ def attributes
109
+ @attributes ||= HashWithIndifferentAccess.new
110
+ end
111
+
112
+ def attributes= attrs
113
+ attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
114
+ end
115
+
116
+ # ActiveModel-style read/write_attribute accessors
117
+ # Here we define the autoload mechanism
118
+ def [] key
119
+
120
+ iv= attributes[key.to_sym]
121
+ # iv.from_orient unless iv.nil?
122
+ if iv.is_a?(String) && iv.rid? #&& @metadata[:fieldTypes].present? && @metadata[:fieldTypes].include?( key.to_s+"=x" )
123
+ # puts "autoload: #{iv}"
124
+ ActiveOrient::Model.autoload_object iv
125
+ elsif iv.is_a?(Array) # && @metadata[:fieldTypes].present? && @metadata[:fieldTypes].match( key.to_s+"=[znmgx]" )
126
+ # puts "autoload: #{iv.inspect}"
127
+ OrientSupport::Array.new self, *iv.map{|y| (y.is_a?(String) && y.rid?) ? ActiveOrient::Model.autoload_object( y ) : y }
128
+ else
129
+
130
+ iv
131
+ end
132
+ end
133
+
134
+ def update_attribute key, value
135
+ @attributes[key] = value
136
+ end
137
+ =begin
138
+ Here we define how the attributes are initialized
139
+ Key and val are set by the RestCliend
140
+ =end
141
+ def []= key, val
142
+ val = val.rid if val.is_a? ActiveOrient::Model
143
+ # if val.is_a?(Array) # && @metadata[:fieldTypes].present? && @metadata[:fieldTypes].include?( key.to_s+"=n" )
144
+ # if @metadata[ :fieldTypes ] =~ /out=x,in=x/
145
+ # puts "VAL is a ARRAY"
146
+ # else
147
+ # puts "METADATA: #{ @metadata[ :fieldTypes ]} "
148
+ # end
149
+ # val# = val.map{|x| if val.is_a? ActiveOrient::Model then val.rid else val end }
150
+ # end
151
+ attributes[key.to_sym] = case val
152
+ when Array
153
+ if val.first.is_a?(Hash)
154
+ v=val.map do |x|
155
+ if x.is_a?( Hash )
156
+ HashWithIndifferentAccess.new(x)
157
+ else
158
+ x
159
+ end
160
+ end
161
+ OrientSupport::Array.new( self, *v )
162
+ else
163
+ OrientSupport::Array.new( self, *val )
164
+ end
165
+ when Hash
166
+ HashWithIndifferentAccess.new(val)
167
+ else
168
+ val
169
+ end
170
+
171
+ end
172
+
173
+ def to_model
174
+ self
175
+ end
176
+
177
+
178
+
179
+ ### Noop methods mocking ActiveRecord::Base macros
180
+
181
+ def self.attr_protected *args
182
+ end
183
+
184
+ def self.attr_accessible *args
185
+ end
186
+
187
+ ### ActiveRecord::Base association API mocks
188
+
189
+ def self.belongs_to model, *args
190
+ attr_accessor model
191
+ end
192
+
193
+ def self.has_one model, *args
194
+ attr_accessor model
195
+ end
196
+
197
+ def self.has_many models, *args
198
+ attr_accessor models
199
+
200
+ define_method(models) do
201
+ self.instance_variable_get("@#{models}") ||
202
+ self.instance_variable_set("@#{models}", [])
203
+ end
204
+ end
205
+
206
+ def self.find *args
207
+ []
208
+ end
209
+
210
+ ### ActiveRecord::Base callback API mocks
211
+
212
+ define_model_callbacks :initialize, :only => :after
213
+
214
+ ### ActiveRecord::Base misc
215
+
216
+ def self.serialize *properties
217
+ end
218
+
219
+ end # Model
220
+ end # module