# Graph Oriented Objects for Ruby (Goo)

*Goo* is a Ruby library that provides ORM-alike capabilities to interact with [RDF](http://en.wikipedia.org/wiki/Resource_Description_Framework)/[SPARQL](http://en.wikipedia.org/wiki/SPARQL) backends. *Goo* provides a DSL for defining schemas for objects and controls how they get validated, serialized, saved, and retrieved from the triplestore. Using RDF and SPARQL for large-scale applications creates challenges in terms of scalability and technology adoption. We designed Goo with two main objectives:

* *Goo* abstracts SPARQL so developers do not need to be SPARQL experts to handle large RDF graphs efficiently.
* *Goo* is designed to serve [BioPortal](http://bioportal.bioontology.org/) growing REST traffic. BioPortal's REST API provides access to hundreds of millions of Biomedical artifacts. Scalability and efficiency is at the core of *Goo's* design.



:::info
Source code see: <https://github.com/ncbo/goo>

:::

# How to use


:::info
Github documentation see: <http://ncbo.github.io/goo/>

:::


## Examples

### Example: getting a user and editing it

Using bin/ncbo_cron --console

```ruby
user = LinkedData::Models::User.find("admin").first
user.bring_remaining

user.password=("my_password")

user.valid?
user.save
```


### Example: get all mappings

```ruby
LinkedData::Models::Mappings.all.include(:id, :source, :classes)

#Get all mappings with all attributes

LinkedData::Models::RestBackupMapping.all
            .include(LinkedData::Models::RestBackupMapping.attributes(:all)).each do |m|
                   
   puts m.id.to_s
end

#Get and delete all mappings

LinkedData::Models::RestBackupMapping.all.each do |m|
            puts m.id.to_s
            mapping_id = RDF::URI.new(m.id.to_s)
            puts LinkedData::Mappings.delete_rest_mapping(mapping_id)
end
```


### Example: get a slice and edit it


```ruby
# Retrieve an ontology
ont = LinkedData::Models::Ontology.find("STY").first
sub = 

ont = LinkedData::Models::Ontology.find("STY").include(LinkedData::Models::Ontology.attributes(:all)).first

# Retrieve all submissions of ont
sub = LinkedData::Models::OntologySubmission.where(ontology: ont).include(:submissionId).include(:submissionStatus).all

# Retrieve a submission of ont1 including all its attributes
sub = LinkedData::Models::OntologySubmission.where(ontology: ont).include(LinkedData::Models::OntologySubmission.attributes(:all)).first

# Retrive latest submission and bring all properties
sub = ont.latest_submission
sub.bring_remaining
sub.ontology.bring_remaining

# Retrieve a slice
slice = LinkedData::Models::Slice.find("umls").include(:acronym, :name, :ontologies).first

# To include all attributes:
slice = LinkedData::Models::Slice.find("umls")
	.include(LinkedData::Models::Slice.attributes(:all))
	.first

# Change the name
slice.name = "test"
# Change the ontologies of this slice
slice.ontologies = [ont]

# Save the changes
if slice.valid?
  slice.save
end

# Display errors
slice.errors
```

# How it works

## Model set up

### Model settings

TODO see <https://github.com/ncbo/goo/blob/master/lib/goo/base/resource.rb>

### Model attributes

```ruby
# Get all attributes of a model
LinkedData::Models::OntologySubmission.attributes(:all)

# Get the settings of an attribute
LinkedData::Models::OntologySubmission.attribute_settings(:naturalLanguage)
# Returns the following JSON object
{:namespace=>:omv, :enforce=>[:list]}

# Get the value of an attribute?
# In OntologySubmission.rb
self.naturalLanguage = "en"
```


## Generating SPARQL queries

There are 7 types of generated queries

### Include/unmapped/general query

```sql
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph_i> # for each graph from 1..n
WHERE { 
	?id a <type_uri> . 
	OPTIONAL {

		  { ?id <attribute_1_uri> ?attributeObject . BIND("var_1" as ?attributeProperty) } 
			UNION
				....
			UNION
		  { ?attributeObject <attribute_j_uri> ?id . BIND( "var_j" as ?attributeProperty)} # if attribute_j_uri is an inverse attribute 
		  UNION 
			  ....
			{ ?id <attribute_n_uri> ?attributeObject . BIND("var_n" as ?attributeProperty) } 
	}

FILTER(?id = <id_uri>) 
}
```

### Aggregate query

TODO

### BNODE query

```sql
SELECT DISTINCT ?id ?line1 ?line2 
FROM <http://goo.org/default/PersonPersistent>
 WHERE { 
   ?id a <http://goo.org/default/PersonPersistent> . 
   ?id <http://goo.org/default/contact_data> _:g64460 . 
   _:g64460 <http://goo.org/default/line1> ?line1. 
   _:g64460 <http://goo.org/default/line2> ?line2 . 
   FILTER(?id = <http://goo.org/default/person_persistent/Lewis> || ?id = <http://goo.org/default/person_persistent/John>) }
```

### FILTER query (`test/test_where#test_filter`)

```sql
SELECT DISTINCT ?id ?attributeProperty ?attributeObject 
FROM <graph> 
WHERE { 
	  ?id a <type_uri> . 
    ?id <attribute_uri> ?internal_join_var_0 . #can alos be optional
    FILTER(?internal_join_var_0 > "var")
}
```

### ORDER BY query

```sql
SELECT DISTINCT ?id ?attributeProperty ?attributeObject 
FROM <graph> 
WHERE { 
	  ?id a <type_uri> . 
    ?id <attribute_uri> ?internal_join_var_0 . #can also be optional
}
ORDER BY ?internal_join_var_0
```

### Equivalent predicates case

see `def self*.expand_equivalent_predicates(query, eq_p)`


```sql
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph_i>
WHERE { 
    ?id a <type_uri> .
    OPTIONAL { 
         {?id <equivalent_uri_1> ?attributeObject . BIND( "var_1" as ?attributeProperty)) }
				 UNION
         ...
         UNION
           {?id <equivalent_uri_2> ?attributeObject . BIND( "var_1" as ?attributeProperty)) }
     ...
		
}
```

---

**Documents**

- [💁‍♂️ Acknowledgments](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/acknowledgments-15GdRXLQdm)
- [📚Publications and references](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/publications-and-references-87tEoeoGKy)
- [🗽Terms & Conditions](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/terms-conditions-naDsDo2Zxq)
- [🧞‍♂️Metadata guidelines and recommendations](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/metadata-guidelines-and-recommendations-pOFbK9sIfp)
- [📜 AgroPortal Release Notes](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/agroportal-release-notes-btKjZk5tU2)
- [ 👩‍🚀 User Guide](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/user-guide-ZszoBwfjGF)
- [📎 API Documentation](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/api-documentation-kMCurGKD97)
- [🤖 Developer Documentation](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/developer-documentation-LhsrucqGTa)
- [🗃External Documentation](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/external-documentation-vNPQCdArrr)
- [AgroPortal infrastructure](https://wiki.agroportal.eu/s/e6158eda-c109-4385-852c-51a42de9a412/doc/agroportal-infrastructure-ietsAU4kPs)