kalimba-redlander 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 45a19d6326c2d8dca3240b19980c34f25d4c51cc
4
+ data.tar.gz: 3d8efb8bc5173956a0ecac4a75bf28452cc4fff8
5
+ SHA512:
6
+ metadata.gz: d82e2a8077e043f9d37cc15c2e1b3da5bdff50f707fe484e5869792c521ad9b229a02585d15022e8bc167b62b2257efa9cef6b274ec2e563f72d1533d714ccfd
7
+ data.tar.gz: 74fd9991804fbfa4cb9f30a1fcd65cb8d259e9cf10850be9f184a092b79a0fed4e0d4ba5ad5c65f2fc39e7b1df64568001adf9716ed02aa4b26b8bb88b2a99d1
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012, 2013 Slava Kravchenko
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
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
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,261 @@
1
+ require "redlander"
2
+ require "kalimba/persistence"
3
+
4
+ module Kalimba
5
+ module Persistence
6
+ # Mapping of database options from Rails' database.yml
7
+ # to those that Redland::Model expects
8
+ REPOSITORY_OPTIONS_MAPPING = {
9
+ "adapter" => :storage,
10
+ "database" => :name
11
+ }
12
+
13
+ class << self
14
+ def backend
15
+ Kalimba::Persistence::Redlander
16
+ end
17
+
18
+ def repository(options = {})
19
+ ::Redlander::Model.new(remap_options(options))
20
+ end
21
+
22
+ private
23
+
24
+ def remap_options(options = {})
25
+ options = Hash[options.map {|k, v| [REPOSITORY_OPTIONS_MAPPING[k] || k, v] }].symbolize_keys
26
+ options[:storage] =
27
+ case options[:storage]
28
+ when "sqlite3"
29
+ "sqlite"
30
+ else
31
+ options[:storage]
32
+ end
33
+
34
+ options
35
+ end
36
+ end
37
+
38
+ # Redlander-based persistence module
39
+ module Redlander
40
+ extend ActiveSupport::Concern
41
+ include Kalimba::Persistence
42
+
43
+ module ClassMethods
44
+ def find_each(options = {})
45
+ if block_given?
46
+ attributes = (options[:conditions] || {}).stringify_keys
47
+
48
+ q = "SELECT ?subject WHERE { #{resource_definition} . #{attributes_to_graph_query(attributes)} }"
49
+ q << " LIMIT #{options[:limit]}" if options[:limit]
50
+
51
+ logger.debug(q) if logger
52
+
53
+ Kalimba.repository.query(q) do |binding|
54
+ yield self.for(binding["subject"].uri.fragment)
55
+ end
56
+ else
57
+ enum_for(:find_each, options)
58
+ end
59
+ end
60
+
61
+ def find_by_id(id_value)
62
+ record = self.for(id_value)
63
+ record.new_record? ? nil : record
64
+ end
65
+
66
+ def exist?(attributes = {})
67
+ attributes = attributes.stringify_keys
68
+ q = "ASK { #{resource_definition} . #{attributes_to_graph_query(attributes)} }"
69
+ logger.debug(q) if logger
70
+ Kalimba.repository.query(q)
71
+ end
72
+
73
+ def create(attributes = {})
74
+ record = new(attributes)
75
+ record.save
76
+ record
77
+ end
78
+
79
+ def destroy_all
80
+ logger.debug("destroying all #{self.name.pluralize}") if logger
81
+ Kalimba.repository.transaction do
82
+ Kalimba.repository.statements.each(:predicate => NS::RDF["type"], :object => type) do |statement|
83
+ Kalimba.repository.statements.delete_all(:subject => statement.subject)
84
+ end
85
+ end
86
+ end
87
+
88
+ def count(attributes = {})
89
+ q = "SELECT (COUNT(?subject) AS _count) WHERE { #{resource_definition} . #{attributes_to_graph_query(attributes.stringify_keys)} }"
90
+ logger.debug(q) if logger
91
+
92
+ # using SPARQL 1.1, because SPARQL 1.0 does not support COUNT
93
+ c = Kalimba.repository.query(q, :language => "sparql")[0]
94
+ c ? c["_count"].value : 0
95
+ end
96
+
97
+
98
+ private
99
+
100
+ def resource_definition
101
+ if type
102
+ [ "?subject", ::Redlander::Node.new(NS::RDF['type']), ::Redlander::Node.new(type) ].join(" ")
103
+ else
104
+ raise KalimbaError, "resource is missing type declaration"
105
+ end
106
+ end
107
+
108
+ def attributes_to_graph_query(attributes = {})
109
+ attributes.map { |name, value|
110
+ if value.is_a?(Enumerable)
111
+ value.map { |v| attributes_to_graph_query(name => v) }.join(" . ")
112
+ else
113
+ [ "?subject",
114
+ ::Redlander::Node.new(properties[name][:predicate]),
115
+ ::Redlander::Node.new(value)
116
+ ].join(" ")
117
+ end
118
+ }.join(" . ")
119
+ end
120
+ end
121
+
122
+ def new_record?
123
+ !(destroyed? || persisted?)
124
+ end
125
+
126
+ def persisted?
127
+ !subject.nil? && Kalimba.repository.statements.exist?(:subject => subject)
128
+ end
129
+
130
+ def reload
131
+ logger.debug("reloading #{self.inspect}") if logger
132
+ self.class.properties.each { |name, _| attributes[name] = retrieve_attribute(name) }
133
+ self
134
+ end
135
+
136
+ def destroy
137
+ if !destroyed? && persisted?
138
+ Kalimba.repository.transaction do
139
+ logger.debug("destroying #{self.inspect}") if logger
140
+ Kalimba.repository.statements.delete_all(:subject => subject)
141
+ end
142
+ super
143
+ else
144
+ false
145
+ end
146
+ end
147
+
148
+ def save(options = {})
149
+ @subject ||= generate_subject
150
+ logger.debug("saving #{self.inspect}") if logger
151
+ Kalimba.repository.transaction do
152
+ store_type && store_attributes(options) && super
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def read_attribute(name, *args)
159
+ if changed.include?(name) || !persisted?
160
+ super
161
+ else
162
+ attributes[name] = retrieve_attribute(name)
163
+ end
164
+ end
165
+ alias_method :attribute, :read_attribute
166
+
167
+ def write_attribute(name, value)
168
+ unless changed_attributes.include?(name)
169
+ orig_value = read_attribute(name)
170
+ unless value == orig_value
171
+ orig_value = orig_value.duplicable? ? orig_value.clone : orig_value
172
+ changed_attributes[name] = orig_value
173
+ end
174
+ end
175
+ attributes[name] = value
176
+ end
177
+
178
+ def store_type
179
+ st = ::Redlander::Statement.new(subject: subject, predicate: NS::RDF["type"], object: self.class.type)
180
+ Kalimba.repository.statements.add(st)
181
+ end
182
+
183
+ def store_attributes(options = {})
184
+ if new_record?
185
+ attributes.all? { |name, value| value.blank? || store_attribute(name, options) }
186
+ else
187
+ changes.all? { |name, _| store_attribute(name, options) }
188
+ end
189
+ end
190
+
191
+ def retrieve_attribute(name)
192
+ predicate = self.class.properties[name][:predicate]
193
+ datatype = self.class.properties[name][:datatype]
194
+
195
+ if self.class.properties[name][:collection]
196
+ Kalimba.repository.statements
197
+ .all(:subject => subject, :predicate => predicate)
198
+ .map { |statement| type_cast_from_rdf(statement.object.value, datatype) }
199
+ else
200
+ if self.class.localizable_property?(name)
201
+ retrieve_localizable_property(name, predicate)
202
+ else
203
+ statement = Kalimba.repository.statements.first(:subject => subject, :predicate => predicate)
204
+ statement && type_cast_from_rdf(statement.object.value, datatype)
205
+ end
206
+ end
207
+ end
208
+
209
+ def store_attribute(name, options = {})
210
+ predicate = self.class.properties[name][:predicate]
211
+
212
+ Kalimba.repository.statements.delete_all(:subject => subject, :predicate => predicate)
213
+
214
+ value = read_attribute(name)
215
+ if value
216
+ datatype = self.class.properties[name][:datatype]
217
+ if self.class.localizable_property?(name)
218
+ store_localizable_property(name, value, predicate, datatype)
219
+ elsif self.class.properties[name][:collection]
220
+ value.to_set.all? { |v| store_single_value(v, predicate, datatype, options) }
221
+ else
222
+ store_single_value(value, predicate, datatype, options)
223
+ end
224
+ else
225
+ true
226
+ end
227
+ end
228
+
229
+ def store_single_value(value, predicate, datatype, options = {})
230
+ value =
231
+ # TODO: check for the types that are acceptable by the property,
232
+ # not the types of values themselves!
233
+ if value.is_a?(Kalimba::Resource)
234
+ store_single_resource(value, options)
235
+ else
236
+ type_cast_to_rdf(value, datatype)
237
+ end
238
+ if value
239
+ statement = ::Redlander::Statement.new(:subject => subject, :predicate => predicate, :object => ::Redlander::Node.new(value))
240
+ Kalimba.repository.statements.add(statement)
241
+ else
242
+ # if value turned into nil or false upon conversion/typecasting to RDF,
243
+ # do not count this as an error
244
+ true
245
+ end
246
+ end
247
+
248
+ def store_single_resource(resource, options)
249
+ # avoid cyclic saves
250
+ if options[:parent_subject] != resource.subject &&
251
+ must_be_persisted?(resource)
252
+ resource.save(:parent_subject => subject)
253
+ end
254
+ end
255
+
256
+ def must_be_persisted?(resource)
257
+ resource.changed? || resource.new_record?
258
+ end
259
+ end
260
+ end
261
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kalimba-redlander
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Slava Kravchenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kalimba
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redlander
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.0
41
+ description: Redlander adapter for Kalimba. It provides the RDF storage backend for
42
+ Kalimba.
43
+ email:
44
+ - slava.kravchenko@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - lib/kalimba/persistence/redlander.rb
50
+ - LICENSE
51
+ homepage: https://github.com/cordawyn/kalimba-redlander
52
+ licenses:
53
+ - The MIT License (MIT)
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.0.0.rc.2
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: Redlander adapter for Kalimba
75
+ test_files: []
76
+ has_rdoc: