activerdf_net7 1.6.11

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 (190) hide show
  1. data/CHANGELOG +79 -0
  2. data/LICENSE +504 -0
  3. data/README.rdoc +34 -0
  4. data/activerdf-jena/CHANGELOG +14 -0
  5. data/activerdf-jena/LICENSE +504 -0
  6. data/activerdf-jena/README +57 -0
  7. data/activerdf-jena/Rakefile +87 -0
  8. data/activerdf-jena/TODO +18 -0
  9. data/activerdf-jena/VERSION +1 -0
  10. data/activerdf-jena/ext/antlr-2.7.5.jar +0 -0
  11. data/activerdf-jena/ext/arq-extra.jar +0 -0
  12. data/activerdf-jena/ext/arq.jar +0 -0
  13. data/activerdf-jena/ext/aterm-java-1.6.jar +0 -0
  14. data/activerdf-jena/ext/commons-logging-1.1.jar +0 -0
  15. data/activerdf-jena/ext/concurrent.jar +0 -0
  16. data/activerdf-jena/ext/icu4j_3_4.jar +0 -0
  17. data/activerdf-jena/ext/iri.jar +0 -0
  18. data/activerdf-jena/ext/jena.jar +0 -0
  19. data/activerdf-jena/ext/jenatest.jar +0 -0
  20. data/activerdf-jena/ext/json.jar +0 -0
  21. data/activerdf-jena/ext/junit.jar +0 -0
  22. data/activerdf-jena/ext/log4j-1.2.12.jar +0 -0
  23. data/activerdf-jena/ext/lucene-core-2.0.0.jar +0 -0
  24. data/activerdf-jena/ext/ng4j.jar +0 -0
  25. data/activerdf-jena/ext/pellet.jar +0 -0
  26. data/activerdf-jena/ext/relaxngDatatype.jar +0 -0
  27. data/activerdf-jena/ext/stax-api-1.0.jar +0 -0
  28. data/activerdf-jena/ext/wstx-asl-3.0.0.jar +0 -0
  29. data/activerdf-jena/ext/xercesImpl.jar +0 -0
  30. data/activerdf-jena/ext/xml-apis.jar +0 -0
  31. data/activerdf-jena/ext/xsdlib.jar +0 -0
  32. data/activerdf-jena/lib/activerdf_jena/init.rb +26 -0
  33. data/activerdf-jena/lib/activerdf_jena/jena.rb +59 -0
  34. data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +515 -0
  35. data/activerdf-jena/lib/activerdf_jena/lucene.rb +22 -0
  36. data/activerdf-jena/lib/activerdf_jena/ng4j.rb +50 -0
  37. data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +379 -0
  38. data/activerdf-jena/lib/activerdf_jena/pellet.rb +25 -0
  39. data/activerdf-jena/test/bnode_org_rss.rdf +793 -0
  40. data/activerdf-jena/test/eyal-foaf.nt +39 -0
  41. data/activerdf-jena/test/fun_with_bnodes.nt +2 -0
  42. data/activerdf-jena/test/s1.n3 +18 -0
  43. data/activerdf-jena/test/test_data.nt +32 -0
  44. data/activerdf-jena/test/test_jena_adapter.rb +451 -0
  45. data/activerdf-jena/test/test_ng4j_adapter.rb +354 -0
  46. data/activerdf-rdflite/CHANGELOG +31 -0
  47. data/activerdf-rdflite/LICENSE +504 -0
  48. data/activerdf-rdflite/README +16 -0
  49. data/activerdf-rdflite/Rakefile +73 -0
  50. data/activerdf-rdflite/VERSION +1 -0
  51. data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +34 -0
  52. data/activerdf-rdflite/lib/activerdf_rdflite/init.rb +13 -0
  53. data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +582 -0
  54. data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +87 -0
  55. data/activerdf-rdflite/test/test_bnode_data.nt +5 -0
  56. data/activerdf-rdflite/test/test_data.nt +32 -0
  57. data/activerdf-rdflite/test/test_escaped_data.nt +2 -0
  58. data/activerdf-rdflite/test/test_fetching.rb +33 -0
  59. data/activerdf-rdflite/test/test_rdflite.rb +277 -0
  60. data/activerdf-redland/CHANGELOG +12 -0
  61. data/activerdf-redland/LICENSE +504 -0
  62. data/activerdf-redland/README +9 -0
  63. data/activerdf-redland/Rakefile +72 -0
  64. data/activerdf-redland/VERSION +1 -0
  65. data/activerdf-redland/lib/activerdf_redland/init.rb +10 -0
  66. data/activerdf-redland/lib/activerdf_redland/redland.rb +362 -0
  67. data/activerdf-redland/test/test_person_data.nt +42 -0
  68. data/activerdf-redland/test/test_redland_adapter.rb +242 -0
  69. data/activerdf-sesame/CHANGELOG +6 -0
  70. data/activerdf-sesame/LICENSE +10 -0
  71. data/activerdf-sesame/LICENSE-aduna +10 -0
  72. data/activerdf-sesame/LICENSE-lgpl +504 -0
  73. data/activerdf-sesame/README +33 -0
  74. data/activerdf-sesame/Rakefile +77 -0
  75. data/activerdf-sesame/VERSION +1 -0
  76. data/activerdf-sesame/ext/commons-codec-1.3.jar +0 -0
  77. data/activerdf-sesame/ext/commons-dbcp-1.2.2.jar +0 -0
  78. data/activerdf-sesame/ext/commons-httpclient-3.1.jar +0 -0
  79. data/activerdf-sesame/ext/commons-logging-1.1.1.jar +0 -0
  80. data/activerdf-sesame/ext/commons-pool-1.3.jar +0 -0
  81. data/activerdf-sesame/ext/commons-pool-1.5.2.jar +0 -0
  82. data/activerdf-sesame/ext/junit-3.8.2.jar +0 -0
  83. data/activerdf-sesame/ext/openrdf-sesame-2.0-onejar.jar +0 -0
  84. data/activerdf-sesame/ext/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
  85. data/activerdf-sesame/ext/slf4j-api-1.4.3.jar +0 -0
  86. data/activerdf-sesame/ext/slf4j-nop-1.4.3.jar +0 -0
  87. data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
  88. data/activerdf-sesame/java/build.number +3 -0
  89. data/activerdf-sesame/java/build.xml +313 -0
  90. data/activerdf-sesame/java/javadoc/allclasses-frame.html +31 -0
  91. data/activerdf-sesame/java/javadoc/allclasses-noframe.html +31 -0
  92. data/activerdf-sesame/java/javadoc/constant-values.html +146 -0
  93. data/activerdf-sesame/java/javadoc/deprecated-list.html +146 -0
  94. data/activerdf-sesame/java/javadoc/help-doc.html +223 -0
  95. data/activerdf-sesame/java/javadoc/index-files/index-1.html +150 -0
  96. data/activerdf-sesame/java/javadoc/index-files/index-10.html +145 -0
  97. data/activerdf-sesame/java/javadoc/index-files/index-2.html +157 -0
  98. data/activerdf-sesame/java/javadoc/index-files/index-3.html +146 -0
  99. data/activerdf-sesame/java/javadoc/index-files/index-4.html +145 -0
  100. data/activerdf-sesame/java/javadoc/index-files/index-5.html +145 -0
  101. data/activerdf-sesame/java/javadoc/index-files/index-6.html +142 -0
  102. data/activerdf-sesame/java/javadoc/index-files/index-7.html +145 -0
  103. data/activerdf-sesame/java/javadoc/index-files/index-8.html +152 -0
  104. data/activerdf-sesame/java/javadoc/index-files/index-9.html +146 -0
  105. data/activerdf-sesame/java/javadoc/index.html +36 -0
  106. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/WrapperForSesame2.html +665 -0
  107. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/class-use/WrapperForSesame2.html +144 -0
  108. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-frame.html +32 -0
  109. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-summary.html +157 -0
  110. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-tree.html +150 -0
  111. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-use.html +144 -0
  112. data/activerdf-sesame/java/javadoc/overview-summary.html +156 -0
  113. data/activerdf-sesame/java/javadoc/overview-tree.html +152 -0
  114. data/activerdf-sesame/java/javadoc/package-list +1 -0
  115. data/activerdf-sesame/java/javadoc/resources/inherit.gif +0 -0
  116. data/activerdf-sesame/java/javadoc/stylesheet.css +29 -0
  117. data/activerdf-sesame/java/lib/commons-codec-1.3.jar +0 -0
  118. data/activerdf-sesame/java/lib/commons-dbcp-1.2.2.jar +0 -0
  119. data/activerdf-sesame/java/lib/commons-httpclient-3.1.jar +0 -0
  120. data/activerdf-sesame/java/lib/commons-logging-1.1.1.jar +0 -0
  121. data/activerdf-sesame/java/lib/commons-pool-1.3.jar +0 -0
  122. data/activerdf-sesame/java/lib/commons-pool-1.5.2.jar +0 -0
  123. data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
  124. data/activerdf-sesame/java/lib/openrdf-sesame-2.0-onejar.jar +0 -0
  125. data/activerdf-sesame/java/lib/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
  126. data/activerdf-sesame/java/lib/slf4j-api-1.4.3.jar +0 -0
  127. data/activerdf-sesame/java/lib/slf4j-nop-1.4.3.jar +0 -0
  128. data/activerdf-sesame/java/manifest.mf +3 -0
  129. data/activerdf-sesame/java/settings.xml +135 -0
  130. data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +145 -0
  131. data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +41 -0
  132. data/activerdf-sesame/lib/activerdf_sesame/init.rb +11 -0
  133. data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +400 -0
  134. data/activerdf-sesame/test/eyal-foaf.nt +39 -0
  135. data/activerdf-sesame/test/eyal-foaf.rdf +65 -0
  136. data/activerdf-sesame/test/test_sesame_adapter.rb +341 -0
  137. data/activerdf-sparql/CHANGELOG +35 -0
  138. data/activerdf-sparql/LICENSE +504 -0
  139. data/activerdf-sparql/README +10 -0
  140. data/activerdf-sparql/Rakefile +78 -0
  141. data/activerdf-sparql/VERSION +1 -0
  142. data/activerdf-sparql/lib/activerdf_sparql/init.rb +10 -0
  143. data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +212 -0
  144. data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +55 -0
  145. data/activerdf-sparql/test/test_sparql_adapter.rb +108 -0
  146. data/activerdf-yars/LICENSE +504 -0
  147. data/activerdf-yars/README +10 -0
  148. data/activerdf-yars/Rakefile +38 -0
  149. data/activerdf-yars/lib/activerdf_yars/init.rb +10 -0
  150. data/activerdf-yars/lib/activerdf_yars/jars2.rb +119 -0
  151. data/lib/active_rdf.rb +85 -0
  152. data/lib/active_rdf/directaccess/direct_access.rb +49 -0
  153. data/lib/active_rdf/federation/active_rdf_adapter.rb +47 -0
  154. data/lib/active_rdf/federation/connection_pool.rb +156 -0
  155. data/lib/active_rdf/federation/federation_manager.rb +112 -0
  156. data/lib/active_rdf/instance_exec.rb +13 -0
  157. data/lib/active_rdf/objectmanager/bnode.rb +7 -0
  158. data/lib/active_rdf/objectmanager/literal.rb +71 -0
  159. data/lib/active_rdf/objectmanager/namespace.rb +106 -0
  160. data/lib/active_rdf/objectmanager/object_manager.rb +119 -0
  161. data/lib/active_rdf/objectmanager/ordered_set.rb +116 -0
  162. data/lib/active_rdf/objectmanager/property_list.rb +76 -0
  163. data/lib/active_rdf/objectmanager/resource.rb +609 -0
  164. data/lib/active_rdf/objectmanager/resource_like.rb +28 -0
  165. data/lib/active_rdf/queryengine/ntriples_parser.rb +90 -0
  166. data/lib/active_rdf/queryengine/query.rb +245 -0
  167. data/lib/active_rdf/queryengine/query2jars2.rb +22 -0
  168. data/lib/active_rdf/queryengine/query2sparql.rb +139 -0
  169. data/lib/active_rdf_helpers.rb +30 -0
  170. data/lib/active_rdf_log.rb +100 -0
  171. data/test/common.rb +119 -0
  172. data/test/directaccess/test_direct_access.rb +64 -0
  173. data/test/federation/test_connection_pool.rb +86 -0
  174. data/test/federation/test_federation_manager.rb +145 -0
  175. data/test/objectmanager/test_literal.rb +52 -0
  176. data/test/objectmanager/test_namespace.rb +83 -0
  177. data/test/objectmanager/test_object_manager.rb +96 -0
  178. data/test/objectmanager/test_ordered_set.rb +110 -0
  179. data/test/objectmanager/test_resource_reading.rb +150 -0
  180. data/test/objectmanager/test_resource_writing.rb +39 -0
  181. data/test/objectmanager/test_talia_syntax.rb +68 -0
  182. data/test/queryengine/my_external_resource.rb +24 -0
  183. data/test/queryengine/test_external_resource_class.rb +49 -0
  184. data/test/queryengine/test_ntriples_parser.rb +71 -0
  185. data/test/queryengine/test_query.rb +55 -0
  186. data/test/queryengine/test_query2jars2.rb +51 -0
  187. data/test/queryengine/test_query2sparql.rb +76 -0
  188. data/test/queryengine/test_query_engine.rb +52 -0
  189. data/test/test_adapters.rb +58 -0
  190. metadata +266 -0
@@ -0,0 +1,16 @@
1
+ == Welcome to rdflite
2
+
3
+ rdflite is a small RDF datastore, based on sqlite3. It can be used as a
4
+ datastore for ActiveRDF: it acts as a gemplugin for ActiveRDF. rdflite does not
5
+ scale well for large datasets, but is very fast for small ones. It supports the
6
+ full ActiveRDF query grammar (basically, select/distinct/count with arbitrary
7
+ joins in the where clauses) and offers full-text search over the literals if
8
+ ferret is installed.
9
+
10
+ See http://www.activerdf.org/ for more information.
11
+
12
+ == License
13
+ rdflite is distributed under the LGPL license.
14
+
15
+ == Authors
16
+ * Eyal Oren
@@ -0,0 +1,73 @@
1
+ require 'meta_project'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/clean'
5
+ require 'rake/gempackagetask'
6
+ require 'rake/rdoctask'
7
+ require 'rake/contrib/xforge'
8
+ require 'rubygems'
9
+ require 'fileutils'
10
+ require '../tools/rakehelp'
11
+
12
+ $version = IO.read('VERSION').strip
13
+ $name = 'activerdf_rdflite'
14
+ $project = MetaProject::Project::XForge::RubyForge.new('activerdf')
15
+
16
+ # setup tests
17
+ setup_tests
18
+ setup_clean ["pkg", "lib/*.bundle", "*.gem", ".config"]
19
+
20
+ # setup rdoc
21
+ Rake::RDocTask.new do |rdoc|
22
+ rdoc.rdoc_dir = 'doc/rdoc'
23
+ rdoc.options << '--line-numbers'
24
+ rdoc.rdoc_files.add ['README', 'LICENSE', 'lib/**/*.rb', 'doc/**/*.rdoc']
25
+ end
26
+
27
+ desc "Does a full compile, test run"
28
+ task :default => [:test, :package]
29
+
30
+ setup_gem($name, $version) do |spec|
31
+ spec.summary = "an RDF database for usage in ActiveRDF (based on sqlite3)"
32
+ spec.description = spec.summary
33
+ spec.author="Eyal Oren <eyal.oren@deri.org"
34
+ spec.add_dependency('gem_plugin', '>= 0.2.1')
35
+ spec.add_dependency('uuidtools')
36
+ spec.add_dependency('activerdf', '>= 1.6.4')
37
+ spec.add_dependency('mime-types')
38
+ spec.add_dependency('sqlite3-ruby', '>= 1.2.1')
39
+ end
40
+
41
+ task :verify_rubyforge do
42
+ raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
43
+ raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
44
+ end
45
+
46
+ desc "Release files on RubyForge."
47
+ task :release => [:clean, :verify_rubyforge, :package ] do
48
+ release_files = FileList["pkg/#$name-#$version.gem"]
49
+
50
+ Rake::XForge::Release.new($project) do |release|
51
+ release.user_name = ENV['RUBYFORGE_USER']
52
+ release.password = ENV['RUBYFORGE_PASSWORD']
53
+ release.files = release_files.to_a
54
+ release.release_name = "#$name #$version"
55
+ release.package_name = "activerdf-rdflite"
56
+ release.release_notes = ""
57
+
58
+ changes = []
59
+ File.open("CHANGELOG") do |file|
60
+ current = true
61
+
62
+ file.each do |line|
63
+ line.chomp!
64
+ if current and line =~ /^==/
65
+ current = false; next
66
+ end
67
+ break if line.empty? and not current
68
+ changes << line
69
+ end
70
+ end
71
+ release.release_changes = changes.join("\n")
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ 1.4.1
@@ -0,0 +1,34 @@
1
+ # Author:: Eyal Oren
2
+ # Copyright:: (c) 2005-2006 Eyal Oren
3
+ # License:: LGPL
4
+
5
+ # FetchingAdapter is an extension to rdflite for fetching RDF from online sources.
6
+ class FetchingAdapter < RDFLite
7
+ ConnectionPool.register_adapter(:fetching, self)
8
+
9
+ # TODO: check that rapper is installed
10
+
11
+ # fetches RDF/XML data from given url and adds it to the datastore, using the
12
+ # source url as context identifier.
13
+ def fetch url
14
+ # check if url starts with http://
15
+ return unless url.match(/http:\/\/(.*)/)
16
+
17
+ ActiveRdfLogger::log_debug(self) { "Fetching from #{url}" }
18
+
19
+ #model = Redland::Model.new
20
+ #parser = Redland::Parser.new('rdfxml')
21
+ #scan = Redland::Uri.new('http://feature.librdf.org/raptor-scanForRDF')
22
+ #enable = Redland::Literal.new('1')
23
+ #Redland::librdf_parser_set_feature(parser, scan.uri, enable.node)
24
+ #parser.parse_into_model(model, url)
25
+ #triples = Redland::Serializer.ntriples.model_to_string(nil, model)
26
+
27
+ triples = `rapper --scan --quiet "#{url}"`
28
+ lines = triples.split($/)
29
+ ActiveRdfLogger::log_debug(self) { "Found #{lines.size} triples" }
30
+
31
+ context = Query.resource_class.new(url)
32
+ add_ntriples(triples, context)
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+
2
+ # add the directory in which this file is located to the ruby loadpath
3
+ file =
4
+ if File.symlink?(__FILE__)
5
+ File.readlink(__FILE__)
6
+ else
7
+ __FILE__
8
+ end
9
+ $: << File.dirname(File.expand_path(file))
10
+
11
+ require 'rdflite'
12
+ require 'fetching'
13
+ require 'suggesting'
@@ -0,0 +1,582 @@
1
+ # Author:: Eyal Oren
2
+ # Copyright:: (c) 2005-2006 Eyal Oren
3
+ # License:: LGPL
4
+
5
+ require 'sqlite3'
6
+ require 'active_rdf'
7
+ require 'federation/connection_pool'
8
+ require 'uuidtools'
9
+ require 'queryengine/ntriples_parser'
10
+ require 'open-uri'
11
+ require 'mime/types'
12
+
13
+ ActiveRdfLogger::log_info "Loading RDFLite adapter", self
14
+
15
+
16
+
17
+ # RDFLite is a lightweight RDF database on top of sqlite3. It can act as adapter
18
+ # in ActiveRDF. It supports on-disk and in-memory usage, and allows keyword
19
+ # search if ferret is installed.
20
+ class RDFLite < ActiveRdfAdapter
21
+
22
+ class << self
23
+ begin
24
+ require 'ferret'
25
+ @have_ferret = true
26
+ rescue LoadError
27
+ ActiveRdfLogger::log_info "Keyword search is disabled since we could not load Ferret. To
28
+ enable, please do \"gem install ferret\"", self
29
+ @have_ferret = false
30
+ end
31
+
32
+ def has_ferret?
33
+ @have_ferret
34
+ end
35
+ end
36
+
37
+ ConnectionPool.register_adapter(:rdflite,self)
38
+ bool_accessor :keyword_search, :reasoning
39
+
40
+ # instantiates RDFLite database
41
+ # available parameters:
42
+ # * :location => filepath (defaults to memory)
43
+ # * :keyword => true/false (defaults to false)
44
+ # * :pidx, :oidx, etc. => true/false (enable/disable these indices)
45
+ def initialize(params = {})
46
+ super()
47
+ ActiveRdfLogger::log_info(self) { "Initialised rdflite with params #{params.to_s}" }
48
+
49
+ @reads = true
50
+ @writes = true
51
+
52
+ # if no file-location given, we use in-memory store
53
+ file = params[:location] || ':memory:'
54
+ @db = SQLite3::Database.new(file)
55
+
56
+ # disable keyword search by default, enable only if ferret is found
57
+ @keyword_search = params[:keyword].nil? ? false : params[:keyword]
58
+ @keyword_search &= self.class.has_ferret?
59
+
60
+ @reasoning = params[:reasoning] || false
61
+ @subprops = {} if @reasoning
62
+
63
+ if keyword_search?
64
+ # we initialise the ferret index, either as a file or in memory
65
+ infos = Ferret::Index::FieldInfos.new
66
+
67
+ # we setup the fields not to store object's contents
68
+ infos.add_field(:subject, :store => :yes, :index => :no, :term_vector => :no)
69
+ infos.add_field(:object, :store => :no) #, :index => :omit_norms)
70
+
71
+ @ferret = if params[:location]
72
+ Ferret::I.new(:path => params[:location] + '.ferret', :field_infos => infos)
73
+ else
74
+ Ferret::I.new(:field_infos => infos)
75
+ end
76
+ end
77
+
78
+ # turn off filesystem synchronisation for speed
79
+ @db.synchronous = 'off'
80
+
81
+ # create triples table. ignores duplicated triples
82
+ @db.execute('create table if not exists triple(s,p,o,c, unique(s,p,o,c) on conflict ignore)')
83
+
84
+ create_indices(params)
85
+ @db
86
+ end
87
+
88
+ # returns the number of triples in the datastore (incl. possible duplicates)
89
+ def size
90
+ @db.execute('select count(*) from triple')[0][0].to_i
91
+ end
92
+
93
+ # returns all triples in the datastore
94
+ def dump
95
+ @db.execute('select s,p,o,c from triple').collect do |s,p,o,c|
96
+ [s,p,o,c].join(' ')
97
+ end
98
+ end
99
+
100
+ # deletes all triples from datastore
101
+ def clear
102
+ @db.execute('delete from triple')
103
+ end
104
+
105
+ # close adapter and remove it from the ConnectionPool
106
+ def close
107
+ ConnectionPool.remove_data_source(self)
108
+ @db.close
109
+ end
110
+
111
+ # deletes triple(s,p,o,c) from datastore
112
+ # symbol parameters match anything: delete(:s,:p,:o) will delete all triples
113
+ # you can specify a context to limit deletion to that context:
114
+ # delete(:s,:p,:o, 'http://context') will delete all triples with that context
115
+ def delete(s, p, o, c=nil)
116
+ # convert non-nil input to internal format
117
+ quad = [s,p,o,c].collect {|r| r.nil? ? nil : internalise(r) }
118
+
119
+ # construct where clause for deletion (for all non-nil input)
120
+ where_clauses = []
121
+ conditions = []
122
+ quad.each_with_index do |r,i|
123
+ unless r.nil?
124
+ conditions << r
125
+ where_clauses << "#{SPOC[i]} = ?"
126
+ end
127
+ end
128
+
129
+ # construct delete string
130
+ ds = 'delete from triple'
131
+ ds << " where #{where_clauses.join(' and ')}" unless where_clauses.empty?
132
+
133
+ # execute delete string with possible deletion conditions (for each
134
+ # non-empty where clause)
135
+ ActiveRdfLogger::log_debug(self) { "Deleting #{[s,p,o,c].join(' ')}" }
136
+ @db.execute(ds, *conditions)
137
+
138
+ # delete literal from ferret index
139
+ @ferret.search_each("subject:\"#{s}\", object:\"#{o}\"") do |idx, score|
140
+ @ferret.delete(idx)
141
+ end if keyword_search?
142
+
143
+ @db
144
+ end
145
+
146
+ # adds triple(s,p,o) to datastore
147
+ # s,p must be resources, o can be primitive data or resource
148
+ def add(s,p,o,c=nil)
149
+ # check illegal input
150
+ raise(ActiveRdfError, "adding non-resource #{s} while adding (#{s},#{p},#{o},#{c})") unless s.respond_to?(:uri)
151
+ raise(ActiveRdfError, "adding non-resource #{p} while adding (#{s},#{p},#{o},#{c})") unless p.respond_to?(:uri)
152
+
153
+ triple = [s, p, o].collect{|r| serialise(r) }
154
+ add_ntriples(triple.join(' ') + " .\n", serialise(c) )
155
+
156
+ ## get internal representation (array)
157
+ #quad = [s,p,o,c].collect {|r| internalise(r) }
158
+
159
+ ## insert the triple into the datastore
160
+ #@db.execute('insert into triple values (?,?,?,?)', *quad)
161
+
162
+ ## if keyword-search available, insert the object into keyword search
163
+ #@ferret << {:subject => s, :object => o} if keyword_search?
164
+ end
165
+
166
+ # flushes openstanding changes to underlying sqlite3
167
+ def flush
168
+ # since we always write changes into sqlite3 immediately, we don't do
169
+ # anything here
170
+ true
171
+ end
172
+
173
+ # loads triples from file in ntriples format
174
+ def load(location)
175
+ context = if URI.parse(location).host
176
+ location
177
+ else
178
+ internalise(RDFS::Resource.new("file:#{location}"))
179
+ end
180
+
181
+ case MIME::Types.of(location)
182
+ when MIME::Types['application/rdf+xml']
183
+ # check if rapper available
184
+ begin
185
+ # can only parse rdf/xml with redland
186
+ # die otherwise
187
+ require 'rdf/redland'
188
+ model = Redland::Model.new
189
+ Redland::Parser.new.parse_into_model(model, location)
190
+ add_ntriples(model.to_string('ntriples'), location)
191
+ rescue LoadError
192
+ raise ActiveRdfError, "cannot parse remote rdf/xml file without Redland: please install Redland (librdf.org) and its Ruby bindings"
193
+ end
194
+ else
195
+ data = open(location).read
196
+ add_ntriples(data, context)
197
+ end
198
+ end
199
+
200
+ # adds ntriples from given context into datastore
201
+ def add_ntriples(ntriples, context)
202
+ # add each triple to db
203
+ @db.transaction
204
+ insert = @db.prepare('insert into triple values (?,?,?,?);')
205
+
206
+ ntriples = NTriplesParser.parse(ntriples)
207
+ ntriples.each do |s,p,o|
208
+ # convert triples into internal db format
209
+ subject, predicate, object = [s,p,o].collect {|r| internalise(r) }
210
+
211
+ # insert triple into database
212
+ insert.execute(subject, predicate, object, context)
213
+
214
+ # if keyword-search available, insert the object into keyword search
215
+ @ferret << {:subject => subject, :object => object} if keyword_search?
216
+ end
217
+
218
+ @db.commit
219
+ @db
220
+ end
221
+
222
+ # executes ActiveRDF query on datastore
223
+ def query(query)
224
+ # construct query clauses
225
+ sql, conditions = translate(query)
226
+
227
+ # executing query, passing all where-clause values as parameters (so that
228
+ # sqlite will encode quotes correctly)
229
+ results = @db.execute(sql, *conditions)
230
+
231
+ # if ASK query, we check whether we received a positive result count
232
+ if query.ask?
233
+ return [[results[0][0].to_i > 0]]
234
+ elsif query.count?
235
+ return [[results[0][0].to_i]]
236
+ else
237
+ # otherwise we convert results to ActiveRDF nodes and return them
238
+ return wrap(results, query.resource_class)
239
+ end
240
+ end
241
+
242
+ # translates ActiveRDF query into internal sqlite query string
243
+ def translate(query)
244
+ where, conditions = construct_where(query)
245
+ [construct_select(query) + construct_join(query) + where + construct_sort(query) + construct_limit(query), conditions]
246
+ end
247
+
248
+ private
249
+ # constants for extracting resources/literals from sql results
250
+ SPOC = ['s','p','o','c']
251
+
252
+ # construct select clause
253
+ def construct_select(query)
254
+ # ASK queries counts the results, and return true if results > 0
255
+ return "select count(*)" if query.ask?
256
+
257
+ # add select terms for each selectclause in the query
258
+ # the term names depend on the join conditions, e.g. t0.s or t1.p
259
+ select = query.select_clauses.collect do |term|
260
+ variable_name(query, term)
261
+ end
262
+
263
+ # add possible distinct and count functions to select clause
264
+ select_clause = ''
265
+ select_clause << 'distinct ' if query.distinct?
266
+ select_clause << select.join(', ')
267
+ select_clause = "count(#{select_clause})" if query.count?
268
+
269
+ "select " + select_clause
270
+ end
271
+
272
+ # construct (optional) limit and offset clauses
273
+ def construct_limit(query)
274
+ clause = ""
275
+
276
+ # if no limit given, use limit -1 (no limit)
277
+ limit = query.limits.nil? ? -1 : query.limits
278
+
279
+ # if no offset given, use offset 0
280
+ offset = query.offsets.nil? ? 0 : query.offsets
281
+
282
+ clause << " limit #{limit} offset #{offset}"
283
+ clause
284
+ end
285
+
286
+ # sort query results on variable clause (optionally)
287
+ def construct_sort(query)
288
+ if not query.sort_clauses.empty?
289
+ sort = query.sort_clauses.collect { |term| variable_name(query, term) }
290
+ " order by (#{sort.join(',')})"
291
+ elsif not query.reverse_sort_clauses.empty?
292
+ sort = query.reverse_sort_clauses.collect { |term| variable_name(query, term) }
293
+ " order by (#{sort.join(',')}) DESC"
294
+ else
295
+ ""
296
+ end
297
+ end
298
+
299
+ # construct join clause
300
+ # TODO: joins don't work this way, they have to be linear (in one direction
301
+ # only, and we should only alias tables we didnt alias yet)
302
+ # we should only look for one join clause in each where-clause: when we find
303
+ # one, we skip the rest of the variables in this clause.
304
+ def construct_join(query)
305
+ join_stmt = ''
306
+
307
+ # no join necessary if only one where clause given
308
+ return ' from triple as t0 ' if query.where_clauses.size == 1
309
+
310
+ where_clauses = query.where_clauses.flatten
311
+ considering = where_clauses.uniq.select{|w| w.is_a?(Symbol)}
312
+
313
+ # constructing hash with indices for all terms
314
+ # e.g. {?s => [1,3,5], ?p => [2], ... }
315
+ term_occurrences = Hash.new()
316
+ where_clauses.each_with_index do |term, index|
317
+ ary = (term_occurrences[term] ||= [])
318
+ ary << index
319
+ end
320
+
321
+ aliases = {}
322
+
323
+ where_clauses.each_with_index do |term, index|
324
+ # if the term has been joined with his buddy already, we can skip it
325
+ next unless considering.include?(term)
326
+
327
+ # we find all (other) occurrences of this term
328
+ indices = term_occurrences[term]
329
+
330
+ # if the term doesnt have a join-buddy, we can skip it
331
+ next if indices.size == 1
332
+
333
+ # construct t0,t1,... as aliases for term
334
+ # and construct join condition, e.g. t0.s
335
+ termalias = "t#{index / 4}"
336
+ termjoin = "#{termalias}.#{SPOC[index % 4]}"
337
+
338
+ join = if join_stmt.include?(termalias)
339
+ ""
340
+ else
341
+ "triple as #{termalias}"
342
+ end
343
+
344
+ indices.each do |i|
345
+ # skip the current term itself
346
+ next if i==index
347
+
348
+ # construct t0,t1, etc. as aliases for buddy,
349
+ # and construct join condition, e.g. t0.s = t1.p
350
+ buddyalias = "t#{i/4}"
351
+ buddyjoin = "#{buddyalias}.#{SPOC[i%4]}"
352
+
353
+ # TODO: fix reuse of same table names as aliases, e.g.
354
+ # "from triple as t1 join triple as t2 on ... join t1 on ..."
355
+ # is not allowed as such by sqlite
356
+ # but on the other hand, restating the aliases gives ambiguity:
357
+ # "from triple as t1 join triple as t2 on ... join triple as t1 ..."
358
+ # is ambiguous
359
+ if join_stmt.include?(buddyalias)
360
+ join << "and #{termjoin} = #{buddyjoin}"
361
+ else
362
+ join << " join triple as #{buddyalias} on #{termjoin} = #{buddyjoin} "
363
+ end
364
+ end
365
+ join_stmt << join
366
+
367
+ # remove term from 'todo' list of still-considered terms
368
+ considering.delete(term)
369
+ end
370
+
371
+ if join_stmt == ''
372
+ return " from triple as t0 "
373
+ else
374
+ return " from #{join_stmt} "
375
+ end
376
+ end
377
+
378
+ # construct where clause
379
+ def construct_where(query)
380
+ # collecting where clauses, these will be added to the sql string later
381
+ where = []
382
+
383
+ # collecting all the right-hand sides of where clauses (e.g. where name =
384
+ # 'abc'), to add to query string later using ?-notation, because then
385
+ # sqlite will automatically encode quoted literals correctly
386
+ right_hand_sides = []
387
+
388
+ # convert each where clause to SQL:
389
+ # add where clause for each subclause, except if it's a variable
390
+ query.where_clauses.each_with_index do |clause,level|
391
+ raise ActiveRdfError, "where clause #{clause} is not a triple" unless clause.is_a?(Array)
392
+ clause.each_with_index do |subclause, i|
393
+ # dont add where clause for variables
394
+ unless subclause.is_a?(Symbol) || subclause.nil?
395
+ conditions = compute_where_condition(i, subclause, query.reasoning? && reasoning?)
396
+ if conditions.size == 1
397
+ where << "t#{level}.#{SPOC[i]} = ?"
398
+ right_hand_sides << conditions.first
399
+ else
400
+ conditions = conditions.collect {|c| "'#{c}'"}
401
+ where << "t#{level}.#{SPOC[i]} in (#{conditions.join(',')})"
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ # if keyword clause given, convert it using keyword index
408
+ if query.keyword? && keyword_search?
409
+ subjects = []
410
+ select_subject = query.keywords.collect {|subj,key| subj}.uniq
411
+ raise ActiveRdfError, "cannot do keyword search over multiple subjects" if select_subject.size > 1
412
+
413
+ keywords = query.keywords.collect {|subj,key| key}
414
+ @ferret.search_each("object:#{keywords}") do |idx,score|
415
+ subjects << @ferret[idx][:subject]
416
+ end
417
+ subjects.uniq! if query.distinct?
418
+ where << "#{variable_name(query,select_subject.first)} in (#{subjects.collect {'?'}.join(',')})"
419
+ right_hand_sides += subjects
420
+ end
421
+
422
+ if where.empty?
423
+ ['',[]]
424
+ else
425
+ ["where " + where.join(' and '), right_hand_sides]
426
+ end
427
+ end
428
+
429
+ def compute_where_condition(index, subclause, reasoning)
430
+ conditions = [subclause]
431
+
432
+ # expand conditions with rdfs rules if reasoning enabled
433
+ if reasoning
434
+ case index
435
+ when 0: ;
436
+ # no rule for subjects
437
+ when 1:
438
+ # expand properties to include all subproperties
439
+ conditions = subproperties(subclause) if subclause.respond_to?(:uri)
440
+ when 2:
441
+ # no rule for objects
442
+ when 3:
443
+ # no rule for contexts
444
+ end
445
+ end
446
+
447
+ # convert conditions into internal format
448
+ #conditions.collect { |c| c.respond_to?(:uri) ? "<#{c.uri}>" : c.to_s }
449
+ conditions.collect { |c| internalise(c) }
450
+ end
451
+
452
+ def subproperties(resource)
453
+ # compute and store subproperties of this resource
454
+ # or use earlier computed value if available
455
+ unless @subprops[resource]
456
+ subproperty = Namespace.lookup(:rdfs,:subPropertyOf)
457
+ children_query = Query.new.distinct(:sub).where(:sub, subproperty, resource)
458
+ children_query.reasoning = false
459
+ children = children_query.execute
460
+
461
+ if children.empty?
462
+ @subprops[resource] = [resource]
463
+ else
464
+ @subprops[resource] = [resource] + children.collect{|c| subproperties(c)}.flatten.compact
465
+ end
466
+ end
467
+ @subprops[resource]
468
+ end
469
+
470
+ # returns sql variable name for a queryterm
471
+ def variable_name(query,term)
472
+ # look up the first occurence of this term in the where clauses, and compute
473
+ # the level and s/p/o position of it
474
+ index = query.where_clauses.flatten.index(term)
475
+
476
+ if index.nil?
477
+ # term does not appear in where clause
478
+ # but maybe it appears in a keyword clause
479
+
480
+ # index would not be nil if we had:
481
+ # select(:o).where(knud, knows, :o).where(:o, :keyword, 'eyal')
482
+ #
483
+ # the only possibility that index is nil is if we have:
484
+ # select(:o).where(:o, :keyword, :eyal) (selecting subject)
485
+ # or if we use a select clause that does not appear in any where clause
486
+
487
+ # so we check if we find the term in the keyword clauses, otherwise we throw
488
+ # an error
489
+ if query.keywords.keys.include?(term)
490
+ return "t0.s"
491
+ else
492
+ raise ActiveRdfError, "unbound variable :#{term.to_s} in select of #{query.to_sp}"
493
+ end
494
+ end
495
+
496
+ termtable = "t#{index / 4}"
497
+ termspo = SPOC[index % 4]
498
+ return "#{termtable}.#{termspo}"
499
+ end
500
+
501
+ # wrap resources into ActiveRDF resources, literals into Strings. result_type
502
+ # is the type that should be used for ActiveRDF resources
503
+ def wrap(results, result_type)
504
+ results.collect do |row|
505
+ row.collect { |result| parse(result, result_type) }
506
+ end
507
+ end
508
+
509
+ # Return the result as a correct type. result_type is the type that should
510
+ # be used for "resouce" elements
511
+ def parse(result, result_type = RDFS::Resource)
512
+ NTriplesParser.parse_node(result, result_type) || result
513
+ # case result
514
+ # when Literal
515
+ # # replace special characters to allow string interpolation for e.g. 'test\nbreak'
516
+ # $1.double_quote
517
+ # when Resource
518
+ # result_type.new($1)
519
+ # else
520
+ # # when we do a count(*) query we get a number, not a resource/literal
521
+ # result
522
+ # end
523
+ end
524
+
525
+ def create_indices(params)
526
+ sidx = params[:sidx] || false
527
+ pidx = params[:pidx] || false
528
+ oidx = params[:oidx] || false
529
+ spidx = params[:spidx] || true
530
+ soidx = params[:soidx] || false
531
+ poidx = params[:poidx] || true
532
+ opidx = params[:opidx] || false
533
+
534
+ # creating lookup indices
535
+ @db.transaction do
536
+ @db.execute('create index if not exists sidx on triple(s)') if sidx
537
+ @db.execute('create index if not exists pidx on triple(p)') if pidx
538
+ @db.execute('create index if not exists oidx on triple(o)') if oidx
539
+ @db.execute('create index if not exists spidx on triple(s,p)') if spidx
540
+ @db.execute('create index if not exists soidx on triple(s,o)') if soidx
541
+ @db.execute('create index if not exists poidx on triple(p,o)') if poidx
542
+ @db.execute('create index if not exists opidx on triple(o,p)') if opidx
543
+ end
544
+ end
545
+
546
+ # transform triple into internal format <uri> and "literal"
547
+ def internalise(r)
548
+ if r.nil? or r.is_a? Symbol
549
+ nil
550
+ else
551
+ r.to_ntriple
552
+ end
553
+ end
554
+
555
+ # transform resource/literal into ntriples format
556
+ def serialise(r)
557
+ # Fixme: r is most likely NOT a resource
558
+ if r.nil?
559
+ nil
560
+ else
561
+ r.to_ntriple
562
+ end
563
+ end
564
+
565
+ Resource = /<([^>]*)>/
566
+ Literal = /"((?:\\"|[^"])*)"/
567
+
568
+ public :subproperties
569
+ end
570
+
571
+ class String
572
+ def double_quote
573
+ Thread.new do
574
+ $SAFE = 12
575
+ begin
576
+ eval('"%s"' % self)
577
+ rescue Exception => e
578
+ self
579
+ end
580
+ end.value
581
+ end
582
+ end