Dont reindex already indexed files. Yet another bug uncovered by the DateTime fixes.
[beagle.git] / Util / SemWeb / Store.cs
blob57652b1349a42a2b9744ffc8951e0df4d7ba9dd8
1 using System;
2 using System.Collections;
3 using System.Data;
5 namespace SemWeb {
7 public interface StatementSource {
8 void Select(StatementSink sink);
11 public interface StatementSink {
12 bool Add(Statement statement);
15 internal class StatementCounterSink : StatementSink {
16 int counter = 0;
18 public int StatementCount { get { return counter; } }
20 public bool Add(Statement statement) {
21 counter++;
22 return true;
26 internal class StatementExistsSink : StatementSink {
27 bool exists = false;
29 public bool Exists { get { return exists; } }
31 public bool Add(Statement statement) {
32 exists = true;
33 return false;
37 public abstract class Store : StatementSource, StatementSink {
39 Entity rdfType;
41 public static StatementSource CreateForInput(string spec) {
42 return (StatementSource)Create(spec, false);
45 public static StatementSink CreateForOutput(string spec) {
46 return (StatementSink)Create(spec, true);
49 private static object Create(string spec, bool output) {
50 string type = spec;
52 int c = spec.IndexOf(':');
53 if (c != -1) {
54 type = spec.Substring(0, c);
55 spec = spec.Substring(c+1);
56 } else {
57 spec = "";
60 switch (type) {
61 case "mem":
62 return new MemoryStore();
63 case "xml":
64 if (spec == "") throw new ArgumentException("Use: xml:filename");
65 if (output) {
66 return new RdfXmlWriter(spec);
67 } else {
68 return new RdfXmlReader(spec);
70 case "n3":
71 case "ntriples":
72 case "nt":
73 case "turtle":
74 if (spec == "") throw new ArgumentException("Use: format:filename");
75 if (output) {
76 N3Writer ret = new N3Writer(spec);
77 switch (type) {
78 case "nt": case "ntriples":
79 ret.Format = N3Writer.Formats.NTriples;
80 break;
81 case "turtle":
82 ret.Format = N3Writer.Formats.Turtle;
83 break;
85 return ret;
86 } else {
87 return new N3Reader(spec);
89 case "sqlite":
90 case "mysql":
91 if (spec == "") throw new ArgumentException("Use: sqlite|mysql:table:connection-string");
93 c = spec.IndexOf(':');
94 if (c == -1) throw new ArgumentException("Invalid format for sqlite/mysql spec parameter (table:constring).");
95 string table = spec.Substring(0, c);
96 spec = spec.Substring(c+1);
98 string classtype = null;
99 if (type == "sqlite") {
100 classtype = "SemWeb.Stores.SqliteStore, SemWeb.SqliteStore";
101 spec = spec.Replace(";", ",");
102 } else if (type == "mysql") {
103 classtype = "SemWeb.Stores.MySQLStore, SemWeb.MySQLStore";
105 Type ttype = Type.GetType(classtype);
106 if (ttype == null)
107 throw new NotSupportedException("The storage type in <" + classtype + "> could not be found.");
108 return Activator.CreateInstance(ttype, new object[] { spec, table });
109 default:
110 throw new ArgumentException("Unknown parser type: " + type);
114 protected Store() {
115 rdfType = new Entity("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
118 public abstract int StatementCount { get; }
120 public abstract void Clear();
122 public Entity[] GetEntitiesOfType(Entity type) {
123 ArrayList entities = new ArrayList();
125 MemoryStore result = Select(new Statement(null, rdfType, type));
126 foreach (Statement s in result.Statements) {
127 entities.Add(s.Subject);
130 return (Entity[])entities.ToArray(typeof(Entity));
133 bool StatementSink.Add(Statement statement) {
134 Add(statement);
135 return true;
138 public abstract void Add(Statement statement);
140 public abstract void Remove(Statement statement);
142 public virtual void Import(StatementSource source) {
143 source.Select(this);
146 public abstract Entity[] GetAllEntities();
148 public abstract Entity[] GetAllPredicates();
150 public virtual bool Contains(Statement statement) {
151 StatementExistsSink sink = new StatementExistsSink();
152 SelectPartialFilter filter = SelectPartialFilter.All;
153 filter.SelectFirst = true;
154 Select(statement, filter, sink);
155 return sink.Exists;
158 public void Select(StatementSink result) {
159 Select(new Statement(null,null,null), result);
162 public void Select(Statement template, StatementSink result) {
163 Select(template, SelectPartialFilter.All, result);
166 public void Select(Statement[] templates, StatementSink result) {
167 Select(templates, SelectPartialFilter.All, result);
170 public abstract void Select(Statement template, SelectPartialFilter partialFilter, StatementSink result);
172 public abstract void Select(Statement[] templates, SelectPartialFilter partialFilter, StatementSink result);
174 public MemoryStore Select(Statement template) {
175 return Select(template, SelectPartialFilter.All);
178 public MemoryStore Select(Statement template, SelectPartialFilter partialFilter) {
179 MemoryStore ms = new MemoryStore();
180 ms.allowIndexing = false;
181 Select(template, partialFilter, ms);
182 return ms;
185 public MemoryStore Select(Statement[] templates) {
186 return Select(templates, SelectPartialFilter.All);
189 public MemoryStore Select(Statement[] templates, SelectPartialFilter partialFilter) {
190 MemoryStore ms = new MemoryStore();
191 ms.allowIndexing = false;
192 Select(templates, partialFilter, ms);
193 return ms;
196 public Resource[] SelectObjects(Entity subject, Entity predicate) {
197 Hashtable resources = new Hashtable();
198 foreach (Statement s in Select(new Statement(subject, predicate, null), new SelectPartialFilter(false, false, true, false)))
199 if (!resources.ContainsKey(s.Object))
200 resources[s.Object] = s.Object;
201 return (Resource[])new ArrayList(resources.Keys).ToArray(typeof(Resource));
203 public Entity[] SelectSubjects(Entity predicate, Resource @object) {
204 Hashtable resources = new Hashtable();
205 foreach (Statement s in Select(new Statement(null, predicate, @object), new SelectPartialFilter(true, false, false, false)))
206 if (!resources.ContainsKey(s.Subject))
207 resources[s.Subject] = s.Subject;
208 return (Entity[])new ArrayList(resources.Keys).ToArray(typeof(Entity));
211 public abstract void Replace(Entity find, Entity replacement);
213 public abstract void Replace(Statement find, Statement replacement);
215 public virtual Entity[] FindEntities(Statement[] filters) {
216 Hashtable ents = new Hashtable();
217 Select(filters[0], new FindEntitiesSink(ents, spom(filters[0])));
218 for (int i = 1; i < filters.Length; i++) {
219 Hashtable ents2 = new Hashtable();
220 Select(filters[i], new FindEntitiesSink(ents2, spom(filters[i])));
222 Hashtable ents3 = new Hashtable();
223 if (ents.Count < ents2.Count) {
224 foreach (Entity r in ents.Keys)
225 if (ents2.ContainsKey(r))
226 ents3[r] = r;
227 } else {
228 foreach (Entity r in ents2.Keys)
229 if (ents.ContainsKey(r))
230 ents3[r] = r;
232 ents = ents3;
235 ArrayList ret = new ArrayList();
236 ret.AddRange(ents.Keys);
237 return (Entity[])ret.ToArray(typeof(Entity));
240 private int spom(Statement s) {
241 if (s.Subject == null) return 0;
242 if (s.Predicate == null) return 1;
243 if (s.Object == null) return 2;
244 if (s.Meta == null) return 3;
245 throw new InvalidOperationException("A statement did not have a null field.");
248 private class FindEntitiesSink : StatementSink {
249 Hashtable ents;
250 int spom;
251 public FindEntitiesSink(Hashtable ents, int spom) { this.ents = ents; this.spom = spom; }
252 public bool Add(Statement s) {
253 Entity e = null;
254 if (spom == 0) e = s.Subject;
255 if (spom == 1) e = s.Predicate;
256 if (spom == 2) e = s.Object as Entity;
257 if (spom == 3) e = s.Meta;
258 if (e != null) ents[e] = ents;
259 return true;
263 public void Write(RdfWriter writer) {
264 Select(new Statement(null,null,null), writer);
267 public void Write(System.IO.TextWriter writer) {
268 using (RdfWriter w = new N3Writer(writer)) {
269 Write(w);
273 protected object GetResourceKey(Resource resource) {
274 return resource.GetResourceKey(this);
277 protected void SetResourceKey(Resource resource, object value) {
278 resource.SetResourceKey(this, value);
284 namespace SemWeb.Stores {
286 public class MultiStore : Store {
287 ArrayList stores = new ArrayList();
289 public MultiStore() { }
291 public void Add(Store store) {
292 stores.Add(store);
295 public void Add(Store store, RdfReader source) {
296 Add(store);
297 store.Import(source);
300 public void Remove(Store store) {
301 stores.Remove(store);
304 public override int StatementCount {
305 get {
306 int ret = 0;
307 foreach (Store s in stores)
308 ret += s.StatementCount;
309 return ret;
313 public override void Clear() {
314 throw new InvalidOperationException("Clear is not a valid operation on a MultiStore.");
317 public override Entity[] GetAllEntities() {
318 Hashtable h = new Hashtable();
319 foreach (Store s in stores)
320 foreach (Resource r in s.GetAllEntities())
321 h[r] = h;
322 return (Entity[])new ArrayList(h.Keys).ToArray(typeof(Entity));
325 public override Entity[] GetAllPredicates() {
326 Hashtable h = new Hashtable();
327 foreach (Store s in stores)
328 foreach (Resource r in s.GetAllPredicates())
329 h[r] = h;
330 return (Entity[])new ArrayList(h.Keys).ToArray(typeof(Entity));
333 public override void Add(Statement statement) { throw new InvalidOperationException("Add is not a valid operation on a MultiStore."); }
335 public override bool Contains(Statement statement) {
336 foreach (Store s in stores)
337 if (s.Contains(statement))
338 return true;
339 return false;
342 public override void Remove(Statement statement) { throw new InvalidOperationException("Add is not a valid operation on a MultiStore."); }
344 public override void Select(Statement template, SelectPartialFilter partialFilter, StatementSink result) {
345 foreach (Store s in stores)
346 s.Select(template, partialFilter, result);
349 public override void Select(Statement[] templates, SelectPartialFilter partialFilter, StatementSink result) {
350 foreach (Store s in stores)
351 s.Select(templates, partialFilter, result);
354 public override void Replace(Entity a, Entity b) {
355 foreach (Store s in stores)
356 s.Replace(a, b);
359 public override void Replace(Statement find, Statement replacement) {
360 foreach (Store s in stores)
361 s.Replace(find, replacement);
364 public override Entity[] FindEntities(Statement[] filters) {
365 Hashtable h = new Hashtable();
366 foreach (Store s in stores)
367 foreach (Entity e in s.FindEntities(filters))
368 h[e] = h;
369 return (Entity[])new ArrayList(h.Keys).ToArray(typeof(Entity));