rdf-mapper 0.0.1
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/README.rdoc +188 -0
- data/UNLICENSE +25 -0
- data/VERSION +1 -0
- data/lib/lib/adapters/base.rb +83 -0
- data/lib/lib/adapters/rails.rb +307 -0
- data/lib/lib/adapters/rest.rb +45 -0
- data/lib/lib/adapters/sparql.rb +105 -0
- data/lib/lib/associations/base.rb +95 -0
- data/lib/lib/associations/belongs_to.rb +64 -0
- data/lib/lib/associations/has_and_belongs.rb +17 -0
- data/lib/lib/associations/has_many.rb +147 -0
- data/lib/lib/associations/has_one.rb +17 -0
- data/lib/lib/model/association.rb +59 -0
- data/lib/lib/model/attribute.rb +186 -0
- data/lib/lib/model/base.rb +623 -0
- data/lib/lib/model/output.rb +70 -0
- data/lib/lib/model/property.rb +78 -0
- data/lib/lib/scope/collection.rb +165 -0
- data/lib/lib/scope/condition.rb +132 -0
- data/lib/lib/scope/loader.rb +111 -0
- data/lib/lib/scope/model.rb +129 -0
- data/lib/lib/scope/query.rb +281 -0
- data/lib/lib/util/http.rb +66 -0
- data/lib/lib/util/logger.rb +68 -0
- data/lib/rdf-mapper.rb +15 -0
- metadata +141 -0
data/README.rdoc
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
= RDFMapper -- Object-relation mapping for RDF data
|
2
|
+
|
3
|
+
RDFMapper is an ORM[http://en.wikipedia.org/wiki/Object-relational_mapping]
|
4
|
+
written in Ruby that is designed to play nicely with RDF data.
|
5
|
+
|
6
|
+
== Features
|
7
|
+
|
8
|
+
- 100% Ruby code based on a slim & smart {RDF.rb}[http://rdf.rubyforge.org/] library
|
9
|
+
- All the usual Rails methods: find, create, belongs_to, has_many -- you name it
|
10
|
+
- Built with performance in mind: all objects are lazy-loaded by default
|
11
|
+
- Supports REST, SPARQL and ActiveRecord as RDF data sources
|
12
|
+
- Supports XML, N-Triples and JSON out of the box
|
13
|
+
|
14
|
+
== Installation
|
15
|
+
|
16
|
+
The prefered method of installing RDFMapper is through its gem file (requires
|
17
|
+
RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl]):
|
18
|
+
|
19
|
+
% [sudo] gem install rdf-mapper
|
20
|
+
|
21
|
+
The latest version of RDFMapper can be found at
|
22
|
+
|
23
|
+
* http://github.com/42cities/rdf-mapper
|
24
|
+
|
25
|
+
|
26
|
+
== Contribute
|
27
|
+
|
28
|
+
Please note that RDFMapper in under heavy development right now, it's not yet
|
29
|
+
production safe. Any contribution (bug tickets, code patches) is more than
|
30
|
+
welcome. Email us at team@42cities.com or submit a ticket on
|
31
|
+
GitHub[http://github.com/42cities/rdf-mapper/issues]
|
32
|
+
|
33
|
+
|
34
|
+
= 5-minute crash course
|
35
|
+
|
36
|
+
=== Idea behind RDF models
|
37
|
+
|
38
|
+
Models in RDFMapper are essentially RDF nodes that have an ID and at least one triple
|
39
|
+
with an rdf:type predicate. Consider the following example:
|
40
|
+
|
41
|
+
<http://example.org/people/237643> rdf:type <http://www.example.org/schema#Person>
|
42
|
+
<http://example.org/people/237643> example:name "John Smith"
|
43
|
+
<http://example.org/people/237643> example:age "27"^^xsd:integer
|
44
|
+
|
45
|
+
This set of triples defines a node (with an ID of <http://example.org/people/237643>)
|
46
|
+
that has three 'attributes': `example:name`, `example:age`, and `rdf:type`. Now `rdf:type`
|
47
|
+
predicate tells us that there's a class (<http://www.example.org/schema#Person>)
|
48
|
+
with more or less predefined behavior. And our node (<http://example.org/people/237643>)
|
49
|
+
is an instance of that class. We could replicate the same logic in Ruby:
|
50
|
+
|
51
|
+
class Person
|
52
|
+
attr_accessor :id
|
53
|
+
attr_accessor :name
|
54
|
+
attr_accessor :age
|
55
|
+
end
|
56
|
+
|
57
|
+
person = Person.new
|
58
|
+
person.id = "http://example.org/people/237643"
|
59
|
+
person.name = "John Smith"
|
60
|
+
person.age = 27
|
61
|
+
|
62
|
+
That's essentially what RDFMapper does. It accepts RDF triples (XML or N-triples),
|
63
|
+
creates instances, assigns attributes and binds models together (via Rails-like
|
64
|
+
belongs_to and has_many associations).
|
65
|
+
|
66
|
+
|
67
|
+
=== Defining a model
|
68
|
+
|
69
|
+
Before you start working with RDFMapper, you need to define at least one model. The only
|
70
|
+
required setting is its namespace (think XML namespace) or type (think rdf:type). If you
|
71
|
+
specify the namespace, it will be used by the model itself (to figure out its rdf:type)
|
72
|
+
and by its attributes (to figure out RDF predicates).
|
73
|
+
|
74
|
+
class Person < RDFMapper::Model
|
75
|
+
namespace "http://example.org/#"
|
76
|
+
attribute :name, :type => :text
|
77
|
+
attribute :homepage, :type => :uri, :predicate => 'http://xmlns.com/foaf/0.1/homepage'
|
78
|
+
end
|
79
|
+
|
80
|
+
Person.namespace #=> #<RDF::Vocabulary(http://example.org/#)>
|
81
|
+
Person.type #=> #<RDF::URI(http://example.org/#Person)>
|
82
|
+
|
83
|
+
Person.name.type #=> #<RDF::URI(http://example.org/#name")>
|
84
|
+
Person.homepage.type #=> #<RDF::URI(http://xmlns.com/foaf/0.1/homepage)>
|
85
|
+
|
86
|
+
For more information on {RDF::URI}[http://rdf.rubyforge.org/RDF/URI.html],
|
87
|
+
{RDF::Vocabulary}[http://rdf.rubyforge.org/RDF/Vocabulary.html] and other
|
88
|
+
classes within RDF namespace, refer to {RDF.rb documentation}[http://rdf.rubyforge.org/].
|
89
|
+
|
90
|
+
|
91
|
+
=== Defining the data source
|
92
|
+
|
93
|
+
By this moment you can work with RDFMapper models with no additional settings.
|
94
|
+
However, if you want to load, save and search for your objects, you need to
|
95
|
+
specify their data source. RDFMapper comes with 3 different flavors of data
|
96
|
+
sources: REST, SPARQL and Rails.
|
97
|
+
|
98
|
+
* SPARQL [read-only] -- the standard for RDF data.
|
99
|
+
RDFMapper will query specified SPARQL server over HTTP using standard SPARQL
|
100
|
+
syntax. Currently it supports only a few functions (no subqueries, updates,
|
101
|
+
aggregates, etc.)
|
102
|
+
|
103
|
+
* REST [read-only] -- good old HTTP-based data
|
104
|
+
storage. It assumes that an object's ID (which is an URI) is the place to
|
105
|
+
look when you want to get object's properties. For example, if an object has
|
106
|
+
an ID `http://example.org/people/237643`, RDFMapper will download data from
|
107
|
+
this address and parse any RDF triples it finds along the way.
|
108
|
+
|
109
|
+
* Rails [read/write] -- gets the data from an
|
110
|
+
ActiveRecord model (that is Rails model). This adapter assumes an RDFMapper
|
111
|
+
model has a 'mirror' ActiveRecord model with the same attributes and
|
112
|
+
associations.
|
113
|
+
|
114
|
+
Assigning data source to a model is easy:
|
115
|
+
|
116
|
+
class Person < RDFMapper::Model
|
117
|
+
adapter :rails # There should be a `Person` class that subclasses ActiveRecord::Base
|
118
|
+
end
|
119
|
+
|
120
|
+
class Person < RDFMapper
|
121
|
+
adapter :rails, :class_name => 'Employee' # ActiveRecord::Base model is called `Employee`
|
122
|
+
end
|
123
|
+
|
124
|
+
class Person < RDFMapper
|
125
|
+
adapter :sparql, {
|
126
|
+
:server => 'http://some-sparql-server.com'
|
127
|
+
:headers => { 'API-Key' => '89d7sfd9sfs' }
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
=== Searching
|
133
|
+
|
134
|
+
If you search objects by an ID, it's up to the adapter (REST, SPARQL, or Rails) to
|
135
|
+
decide what type of ID it requires (an URI, a database column or something else).
|
136
|
+
Check out the documentation for each adapter to see how works.
|
137
|
+
|
138
|
+
Person.all #=> #<PersonCollection:23784623>
|
139
|
+
Person.find('132987') #=> #<Person:217132856>
|
140
|
+
Person.find(:all, :conditions => { :name => 'John' }) #=> #<PersonCollection:32462387>
|
141
|
+
|
142
|
+
Note, the objects above are not loaded. RDFMapper will load them once you
|
143
|
+
access an attribute of a collection or an object. The following 3 objects are
|
144
|
+
loaded instantly, since RDFMapper needs to figure out what their attributes are
|
145
|
+
(in this case `nil?`, `name` and `length`).
|
146
|
+
|
147
|
+
Person.find('132987').nil? #=> false
|
148
|
+
Person.find('132987').name #=> "John"
|
149
|
+
Person.find(:all, :conditions => { :name => 'John' }).length #=> 3
|
150
|
+
|
151
|
+
You should take extra care when dealing with lazy-loaded models, since
|
152
|
+
exceptions may occur when a model is not found:
|
153
|
+
|
154
|
+
Person.find('132987') #=> #<Person:217132856>
|
155
|
+
Person.find('132987').name #=> NoMethodError: undefined method `name' for nil:NilClass
|
156
|
+
|
157
|
+
Instead, you should first check if a model exists:
|
158
|
+
|
159
|
+
@person = Person.find('132987')
|
160
|
+
@person.name unless @person.nil?
|
161
|
+
|
162
|
+
|
163
|
+
=== Working with attributes
|
164
|
+
|
165
|
+
Attributes in RDFMapper work just as you would expect them to work with just one
|
166
|
+
small exception. Since any attribute of a model is essentially an RDF triple, you
|
167
|
+
can access attributes by their predicates as well:
|
168
|
+
|
169
|
+
class Person < RDFMapper::Model
|
170
|
+
namespace "http://example.org/#"
|
171
|
+
attribute :name, :type => :text
|
172
|
+
attribute :homepage, :type => :uri, :predicate => 'http://xmlns.com/foaf/0.1/homepage'
|
173
|
+
end
|
174
|
+
|
175
|
+
instance = Person.new
|
176
|
+
instance.name #=> "John Smith"
|
177
|
+
instance[:name] #=> "John Smith"
|
178
|
+
instance['http://example.org/#name'] #=> "John Smith"
|
179
|
+
instance.homepage #=> #<RDF::URI(http://johnsmith.com/")>
|
180
|
+
instance['http://xmlns.com/foaf/0.1/homepage'] #=> #<RDF::URI(http://johnsmith.com/")>
|
181
|
+
|
182
|
+
|
183
|
+
That's pretty much all you need to know. Go try and let us know what you think!
|
184
|
+
|
185
|
+
== License
|
186
|
+
|
187
|
+
RDFMapper is free and unencumbered public domain software. For more information,
|
188
|
+
see http://unlicense.org or the accompanying UNLICENSE file.
|
data/UNLICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, contact Alex Serebryakov [serebryakov@gmail.com]
|
25
|
+
or visit <http://unlicense.org/>
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RDFMapper
|
2
|
+
module Adapters
|
3
|
+
|
4
|
+
autoload :Rails, 'lib/adapters/rails'
|
5
|
+
autoload :REST, 'lib/adapters/rest'
|
6
|
+
autoload :SPARQL, 'lib/adapters/sparql'
|
7
|
+
|
8
|
+
##
|
9
|
+
# Instantiates and returns an instance of an adapter.
|
10
|
+
#
|
11
|
+
# @param [Symbol] name (:rails, :sparql, :rest)
|
12
|
+
# @param [Object] cls subclass of RDFMapper::Model
|
13
|
+
# @param [Hash] options options to pass on to the adapter constructor
|
14
|
+
#
|
15
|
+
# @return [Object] instance of an adapter
|
16
|
+
##
|
17
|
+
def self.register(name, cls, options = {})
|
18
|
+
self[name].new(cls, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Returns adapter's class based on specified `name` (:rails, :sparql, :rest)
|
23
|
+
#
|
24
|
+
# @return [Object]
|
25
|
+
##
|
26
|
+
def self.[](name)
|
27
|
+
case name
|
28
|
+
when :rails then Rails
|
29
|
+
when :sparql then SPARQL
|
30
|
+
when :rest then REST
|
31
|
+
else raise NameError, 'Adapter `%s` not recognized' % value.inspect
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Parent class for all adapters. Contains default constructor method
|
37
|
+
# and interface methods that each adapter should override.
|
38
|
+
##
|
39
|
+
class Base
|
40
|
+
|
41
|
+
##
|
42
|
+
# All adapters implement Logger
|
43
|
+
##
|
44
|
+
include RDFMapper::Logger
|
45
|
+
|
46
|
+
##
|
47
|
+
# Adapter implementation should override this method
|
48
|
+
##
|
49
|
+
def load(query)
|
50
|
+
raise NotImplementedError, 'Expected adapter to override `load`'
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Adapter implementation should override this method
|
55
|
+
##
|
56
|
+
def save(instance)
|
57
|
+
raise NotImplementedError, 'Expected adapter to override `save`'
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Adapter implementation should override this method
|
62
|
+
##
|
63
|
+
def reload(instance)
|
64
|
+
raise NotImplementedError, 'Expected adapter to override `save`'
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Adapter implementation should override this method
|
69
|
+
##
|
70
|
+
def update(instance)
|
71
|
+
raise NotImplementedError, 'Expected adapter to override `save`'
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Adapter implementation should override this method
|
76
|
+
##
|
77
|
+
def create(instance)
|
78
|
+
raise NotImplementedError, 'Expected adapter to override `save`'
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
module RDFMapper
|
2
|
+
module Adapters
|
3
|
+
##
|
4
|
+
# [-]
|
5
|
+
##
|
6
|
+
class Rails < Base
|
7
|
+
|
8
|
+
##
|
9
|
+
# [-]
|
10
|
+
##
|
11
|
+
def initialize(cls, options = {})
|
12
|
+
@rdf, @options = cls, options
|
13
|
+
@options[:skip] ||= []
|
14
|
+
@options[:substitute] ||= { }
|
15
|
+
@options[:substitute][:id] ||= :uid
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
# [-]
|
21
|
+
##
|
22
|
+
def load(query)
|
23
|
+
@rdf.associations.values.select do |assoc|
|
24
|
+
assoc.belongs_to?
|
25
|
+
end.map do |assoc|
|
26
|
+
assoc.name
|
27
|
+
end.reject do |name|
|
28
|
+
@options[:skip].include?(name)
|
29
|
+
end.each do |name|
|
30
|
+
query.include!(name)
|
31
|
+
end
|
32
|
+
Query.new(query, @options).find
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# [-]
|
37
|
+
##
|
38
|
+
def save(instance)
|
39
|
+
if instance[:rails_id].nil?
|
40
|
+
obj = instance.class.find(instance.id.to_s).from(:rails)
|
41
|
+
instance[:rails_id] = obj.rails_id unless obj.nil?
|
42
|
+
end
|
43
|
+
if instance[:rails_id].nil?
|
44
|
+
create(instance)
|
45
|
+
else
|
46
|
+
update(instance)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# [-]
|
52
|
+
##
|
53
|
+
def reload(instance)
|
54
|
+
query = RDFMapper::Scope::Query.new(instance.class, :conditions => { :id => instance.id })
|
55
|
+
Query.new(query, @options).find.first
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# [-]
|
60
|
+
##
|
61
|
+
def update(instance)
|
62
|
+
query = RDFMapper::Scope::Query.new(instance.class, :conditions => instance.attributes)
|
63
|
+
Query.new(query, @options).update
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# [-]
|
68
|
+
##
|
69
|
+
def create(instance)
|
70
|
+
query = RDFMapper::Scope::Query.new(instance.class, :conditions => instance.attributes)
|
71
|
+
Query.new(query, @options).create
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def check_for_rails_id(instance)
|
78
|
+
end
|
79
|
+
|
80
|
+
class Query
|
81
|
+
|
82
|
+
include RDFMapper::Logger
|
83
|
+
|
84
|
+
def initialize(query, options = {})
|
85
|
+
@query, @options = query, options
|
86
|
+
@rails = (@options[:class_name] || @query.cls.to_s.demodulize).constantize
|
87
|
+
setup_replacements
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# [-]
|
92
|
+
##
|
93
|
+
def update
|
94
|
+
record = @rails.update(@query[:rails_id], save_options)
|
95
|
+
record_attributes(record)
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# [-]
|
100
|
+
##
|
101
|
+
def create
|
102
|
+
record = @rails.create(save_options)
|
103
|
+
record_attributes(record)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# [-]
|
108
|
+
##
|
109
|
+
def find
|
110
|
+
@query.check(:rails_id)
|
111
|
+
#
|
112
|
+
debug 'Searching for %s with %s' % [@rails, @query.inspect]
|
113
|
+
debug 'Query: %s' % find_options.inspect
|
114
|
+
#
|
115
|
+
@rails.find(:all, find_options).map do |record|
|
116
|
+
record_attributes(record)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
##
|
124
|
+
# [-]
|
125
|
+
##
|
126
|
+
def record_attributes(record)
|
127
|
+
record_id = [:id, :rails_id].map do |name|
|
128
|
+
[name, record_value(record, name)]
|
129
|
+
end
|
130
|
+
record_props = record_properties(record)
|
131
|
+
record_assoc = record_associations(record)
|
132
|
+
Hash[record_id + record_props + record_assoc]
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# [-]
|
137
|
+
##
|
138
|
+
def save_options
|
139
|
+
Hash[@query.to_a.map do |condition|
|
140
|
+
name = @replace[condition.name]
|
141
|
+
[name, validate(condition.value)]
|
142
|
+
end.reject do |name, value|
|
143
|
+
name.nil? or value.nil?
|
144
|
+
end]
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Substitutes names of those attributes specified in `options[:substitute]`
|
149
|
+
# and raises a runtime error for attributes that could not be found in the
|
150
|
+
# database. Returns an object which can then be used with ActiveRecord::Base.find
|
151
|
+
##
|
152
|
+
def find_options #nodoc
|
153
|
+
{ :conditions => SQL.new(@query, @replace).to_a,
|
154
|
+
:order => @query.order,
|
155
|
+
:limit => @query.limit,
|
156
|
+
:offset => @query.offset,
|
157
|
+
:include => @query.include
|
158
|
+
}.delete_if { |name, value| value.nil? }
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# [-]
|
163
|
+
##
|
164
|
+
def setup_replacements #nodoc
|
165
|
+
@replace = default_replacements
|
166
|
+
@query.flatten.map do |condition|
|
167
|
+
# Original RDF name
|
168
|
+
rdf_name = condition.name
|
169
|
+
# Expected name in the DB
|
170
|
+
expected_name = @replace[rdf_name] || rdf_name
|
171
|
+
# Silently ignore attributes that are not in the DB
|
172
|
+
rails_name = activerecord_attribute?(expected_name)
|
173
|
+
@replace[rdf_name] = rails_name unless rails_name.nil?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# [-]
|
179
|
+
##
|
180
|
+
def default_replacements
|
181
|
+
@options[:substitute].merge({ :rails_id => :id })
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# [-]
|
186
|
+
##
|
187
|
+
def record_properties(record) #nodoc
|
188
|
+
@query.cls.properties.keys.map do |name|
|
189
|
+
value = record_value(record, name)
|
190
|
+
[name, value]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# [-]
|
196
|
+
##
|
197
|
+
def record_associations(record) #nodoc
|
198
|
+
@query.include.map do |name|
|
199
|
+
value = record_value(record, name)
|
200
|
+
value = value.nil? ? nil : value[@replace[:id]]
|
201
|
+
[name, value]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# [-]
|
207
|
+
##
|
208
|
+
def record_value(record, rdf_name) #nodoc
|
209
|
+
name = default_replacements[rdf_name] || rdf_name
|
210
|
+
unless record.respond_to?(name)
|
211
|
+
nil
|
212
|
+
else
|
213
|
+
record.send(name)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# [-]
|
219
|
+
##
|
220
|
+
def activerecord_attribute?(name) #nodoc
|
221
|
+
activerecord_property?(name) || activerecord_association?(name)
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# [-]
|
226
|
+
##
|
227
|
+
def activerecord_association?(name) #nodoc
|
228
|
+
reflection = @rails.reflections[name.to_sym]
|
229
|
+
if reflection.nil? or not reflection.belongs_to?
|
230
|
+
return nil
|
231
|
+
end
|
232
|
+
reflection.primary_key_name.to_sym
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# [-]
|
237
|
+
##
|
238
|
+
def activerecord_property?(name) #nodoc
|
239
|
+
@rails.column_names.include?(name.to_s) ? name.to_sym : nil
|
240
|
+
end
|
241
|
+
|
242
|
+
class SQL
|
243
|
+
|
244
|
+
def initialize(query, replace)
|
245
|
+
@query, @replace = query, replace
|
246
|
+
@text, @values = [], []
|
247
|
+
|
248
|
+
@query.to_a.map do |condition|
|
249
|
+
if condition.kind_of?(query.class)
|
250
|
+
add_query(condition)
|
251
|
+
else
|
252
|
+
add_condition(condition)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def add_query(query)
|
258
|
+
child = SQL.new(query, @replace)
|
259
|
+
unless child.text.empty?
|
260
|
+
@text.push("(%s)" % child.text)
|
261
|
+
@values.push(*child.values)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def add_condition(condition)
|
266
|
+
name = @replace[condition.name]
|
267
|
+
if name.nil?
|
268
|
+
return nil
|
269
|
+
end
|
270
|
+
if condition.value.kind_of?(Array)
|
271
|
+
@text << "%s IN (?)" % name
|
272
|
+
else
|
273
|
+
@text << "%s %s ?" % [name, condition.eq]
|
274
|
+
end
|
275
|
+
@values << validate(condition.value)
|
276
|
+
end
|
277
|
+
|
278
|
+
def validate(value) #nodoc
|
279
|
+
if value.kind_of? Array
|
280
|
+
return value.map do |item|
|
281
|
+
validate(item)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
if value.kind_of? RDFMapper::Model
|
285
|
+
value[:rails_id]
|
286
|
+
else
|
287
|
+
value
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def text
|
292
|
+
@text.join(' %s ' % @query.modifier)
|
293
|
+
end
|
294
|
+
|
295
|
+
def values
|
296
|
+
@values
|
297
|
+
end
|
298
|
+
|
299
|
+
def to_a
|
300
|
+
[text] + values
|
301
|
+
end
|
302
|
+
|
303
|
+
end # SQL
|
304
|
+
end # Query
|
305
|
+
end # Rails
|
306
|
+
end # Adapters
|
307
|
+
end # RDFMapper
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RDFMapper
|
2
|
+
module Adapters
|
3
|
+
##
|
4
|
+
# Not yet implemented
|
5
|
+
##
|
6
|
+
class REST < Base
|
7
|
+
|
8
|
+
##
|
9
|
+
# @todo. Not implemented
|
10
|
+
##
|
11
|
+
def load(query)
|
12
|
+
raise NotImplementedError, 'REST adapter is not yet implemented'
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# @todo. Not implemented
|
17
|
+
##
|
18
|
+
def save(instance)
|
19
|
+
raise NotImplementedError, 'REST adapter is not yet implemented'
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# @todo. Not implemented
|
24
|
+
##
|
25
|
+
def reload(instance)
|
26
|
+
raise NotImplementedError, 'REST adapter is not yet implemented'
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# @todo. Not implemented
|
31
|
+
##
|
32
|
+
def update(instance)
|
33
|
+
raise NotImplementedError, 'REST adapter is not yet implemented'
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# @todo. Not implemented
|
38
|
+
##
|
39
|
+
def create(instance)
|
40
|
+
raise NotImplementedError, 'REST adapter is not yet implemented'
|
41
|
+
end
|
42
|
+
|
43
|
+
end # REST
|
44
|
+
end # Adapters
|
45
|
+
end # RDFMapper
|