ActiveModel-style Ruby ORM for RDF Linked Data. Works with SPARQL 1.1 HTTP endpoints.
- ActiveModel-compliant interface.
- Inspired by Durran Jordan's Mongoid ORM for MongoDB, and Ben Lavender's RDF ORM, Spira.
- Uses Ruby-RDF to manage the data internally.
-
Add it to your Gemfile and bundle
gem tripod $ bundle
-
Configure it (in application.rb, or development.rb/production.rb/test.rb)
# (values shown are the defaults) Tripod.configure do |config| config.update_endpoint = 'http://127.0.0.1:3030/tripod/update' config.query_endpoint = 'http://127.0.0.1:3030/tripod/sparql' config.timeout_seconds = 30 end
-
Include it in your model classes.
class Person include Tripod::Resource # these are the default rdf-type and graph for resources of this class rdf_type 'http://example.com/person' graph_uri 'http://example.com/people' field :name, 'http://example.com/name' field :knows, 'http://example.com/knows', :multivalued => true, :is_uri => true field :aliases, 'http://example.com/alias', :multivalued => true field :age, 'http://example.com/age', :datatype => RDF::XSD.integer field :important_dates, 'http://example.com/importantdates', :datatype => RDF::XSD.date, :multivalued => true end # Note: Active Model validations are supported
-
Use it
uri = 'http://example.com/ric' p = Person.new(uri) p.name = 'Ric' p.age = 31 p.aliases = ['Rich', 'Richard'] p.important_dates = [Date.new(2011,1,1)] p.save! people = Person.all.resources #=> returns all people as an array ric = Person.find('http://example.com/ric') #=> returns a single Person object.
Tripod doesn't supply a database. You need to install one. I recommend Fuseki, which runs on port 3030 by default.
## Eager Loading
asa = Person.find('http://example.com/asa')
ric = Person.find('http://example.com/ric')
ric.knows = asa.uri
ric.eager_load_predicate_triples! #does a big DESCRIBE statement behind the scenes
knows = ric.get_related_resource('http://example.com/knows', Resource)
knows.label # this won't cause another database lookup
ric.eager_load_object_triples! #does a big DESCRIBE statement behind the scenes
asa = ric.get_related_resource('http://example.com/asa', Person) # returns a fully hydrated Person object for asa, without an extra lookup
## Defining a graph at instantiation-time
class Resource
include Tripod::Resource
field :label, RDF::RDFS.label
# notice also that you don't need to supply an rdf type or graph here!
end
r = Resource.new('http://example.com/foo', 'http://example.com/mygraph')
r.label = "example"
r.save
# Note: Tripod assumes you want to store all resources in named graphs.
# So if you don't supply a graph at any point (i.e. class or instance level),
# you will get an error when you try to persist the resource.
r.write_predicate(RDF.type, 'http://example.com/myresource/type')
r.read_predicate(RDF.type) #=> [RDF::URI.new("http://example.com/myresource/type")]
# A Tripod::Criteria object defines a set of constraints for a SPARQL query.
# It doesn't actually do anything against the DB until you run resources, first, or count on it.
# (from Tripod::CriteriaExecution)
Person.all #=> returns a Tripod::Criteria object which selects all resources of rdf_type http://example.com/person, in the http://example.com/people graph
Resource.all #=> returns a criteria object to return resources in the database (as no rdf_type or graph_uri specified at class level)
Person.all.resources #=> returns all the actual resources for the criteria object, as an array-like object
Person.all.resources(:return_graph => false) #=> returns the actual resources, but without returning the graph_uri in the select (helps avoid pagination issues). Note: doesn't set the graph uri on the instantiated resources.
Person.first #=> returns the first person (by crafting a sparql query under the covers that only returns 1 result)
Person.first(:return_graph => false) # as with resources, doesn't return / set the graph_uri.
Person.count #=> returns the count of all people (by crafting a count query under the covers that only returns a count)
# note that you need to use ?uri as the variable for the subject.
Person.where("?uri <http://example.com/name> 'Joe'") #=> returns a Tripod::Criteria object
Resource.graph("http://example.com/mygraph") #=> Retruns a criteria object with a graph restriction (note: if graph_uri set on the class, it will default to using this)
Resource.find_by_sparql('SELECT ?uri ?graph WHERE { GRAPH ?graph { ?uri ?p ?o } }') #=> allows arbitrary sparql. Again, use ?uri for the variable of the subjects (and ?graph for the graph).
Person.all.where("?uri <http://example.com/name> 'Ric'").where("?uri <http://example.com/knows> <http://example.com/asa>).first
Person.where("?uri <http://example.com/name> ?name").limit(1).offset(0).order("DESC(?name)")
Copyright (c) 2012 Swirrl IT Limited. Released under MIT License