forked from linkeddata/gold
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sparqlupdate.go
116 lines (103 loc) · 2.39 KB
/
sparqlupdate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package gold
import (
"bytes"
"errors"
"io"
"io/ioutil"
"strings"
"text/scanner"
)
// SPARQLUpdateQuery contains a verb, the body of the query and the graph
type SPARQLUpdateQuery struct {
verb string
body string
graph AnyGraph
}
// SPARQLUpdate contains the base URI and a list of queries
type SPARQLUpdate struct {
baseURI string
queries []SPARQLUpdateQuery
}
// NewSPARQLUpdate creates a new SPARQL object
func NewSPARQLUpdate(baseURI string) *SPARQLUpdate {
return &SPARQLUpdate{
baseURI: baseURI,
queries: []SPARQLUpdateQuery{},
}
}
// Parse parses a SPARQL query from the reader
func (sparql *SPARQLUpdate) Parse(src io.Reader) error {
b, _ := ioutil.ReadAll(src)
s := new(scanner.Scanner).Init(bytes.NewReader(b))
s.Mode = scanner.ScanIdents | scanner.ScanStrings
start := 0
level := 0
verb := ""
tok := s.Scan()
for tok != scanner.EOF {
switch tok {
case -2:
if level == 0 {
if len(verb) > 0 {
verb += " "
}
verb += s.TokenText()
}
case 123: // {
if level == 0 {
start = s.Position.Offset
}
level++
case 125: // }
level--
if level == 0 {
query := SPARQLUpdateQuery{
body: string(b[start+1 : s.Position.Offset]),
graph: NewGraph(sparql.baseURI),
verb: verb,
}
query.graph.Parse(strings.NewReader(query.body), "text/turtle")
sparql.queries = append(sparql.queries, query)
}
case 59: // ;
if level == 0 {
verb = ""
}
}
tok = s.Scan()
}
return nil
}
// SPARQLUpdate is used to update a graph from a SPARQL query
// Ugly, needs to be improved
func (g *Graph) SPARQLUpdate(sparql *SPARQLUpdate) (int, error) {
for _, query := range sparql.queries {
if query.verb == "DELETE" || query.verb == "DELETE DATA" {
for pattern := range query.graph.IterTriples() {
found := false
for _, triple := range g.All(pattern.Subject, pattern.Predicate, nil) {
switch triple.Object.(type) {
case *BlankNode:
return 500, errors.New("bnodes are not supported!")
default:
if pattern.Object.Equal(triple.Object) {
g.Remove(triple)
found = true
}
}
}
if !found {
return 409, errors.New("no matching triple found in graph!")
}
}
}
}
for _, query := range sparql.queries {
if query.verb == "INSERT" || query.verb == "INSERT DATA" {
for triple := range query.graph.IterTriples() {
g.Add(triple)
}
}
}
return 200, nil
}