activerdf_net7 1.6.11

Sign up to get free protection for your applications and to get access to all the features.
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