-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
539 changed files
with
7,295 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
on: [ push ] | ||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v4 | ||
with: | ||
go-version: '1.21.0' | ||
- run: go test -v ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package rdf | ||
|
||
import "fmt" | ||
|
||
type DataType string | ||
|
||
// INFO on datatypes: https://www.w3.org/TR/xmlschema11-2/type-hierarchy-201104.longdesc.html | ||
const ( | ||
XSD = "http://www.w3.org/2001/XMLSchema#" | ||
XSDAnyType DataType = XSD + "anyType" | ||
XSDAnyURI DataType = XSD + "anyURI" | ||
XSDBase64Binary DataType = XSD + "base64Binary" | ||
XSDBoolean DataType = XSD + "boolean" | ||
XSDDate DataType = XSD + "date" | ||
XDSDecimal DataType = XSD + "decimal" | ||
XSDDouble DataType = XSD + "double" | ||
XSDDuration DataType = XSD + "duration" | ||
XSDFloat DataType = XSD + "float" | ||
XSDString DataType = XSD + "string" | ||
// TODO: add "other" build-in atomic types, e.g. dateTimeStamp etc. | ||
|
||
XSDNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||
XSDNSString = XSDNS + "langString" | ||
) | ||
|
||
// NativeType returns the native type of the given value. | ||
// Returns true if the value was converted, otherwise false. | ||
func (d DataType) NativeType(value string) (any, bool, error) { | ||
switch d { | ||
case XSDAnyType, XSDString: | ||
return value, true, nil | ||
case XSDBoolean: | ||
switch value { | ||
case "true", "false": | ||
return value[0] == 't', true, nil | ||
} | ||
return nil, false, fmt.Errorf("invalid boolean value: %q", value) | ||
default: | ||
return value, false, nil | ||
} | ||
} | ||
|
||
// Validate returns true if the given value is valid for the datatype. | ||
func (d DataType) Validate(v any, acceptString bool) bool { | ||
if _, ok := v.(string); acceptString && ok { | ||
// TODO: validate string against the datatype. | ||
return true | ||
} | ||
|
||
switch d { | ||
case XSDAnyType: | ||
return true | ||
case XSDString: | ||
_, ok := v.(string) | ||
return ok | ||
case XSDBoolean: | ||
_, ok := v.(bool) | ||
return ok | ||
default: | ||
return false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
module github.com/0x51-dev/rdf | ||
|
||
go 1.20 | ||
go 1.21.0 | ||
|
||
require github.com/0x51-dev/upeg v0.0.0-20230714211724-9f58040921d7 | ||
require github.com/0x51-dev/upeg v0.0.0-20230829161504-bdf1e5e3b220 | ||
|
||
require github.com/0x51-dev/ri v0.0.0-20230708135038-029eea38546f |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
github.com/0x51-dev/upeg v0.0.0-20230714211724-9f58040921d7 h1:WuGofvGedJe7v53MPNiympoKKydmVkeijzQYtNy0WZc= | ||
github.com/0x51-dev/upeg v0.0.0-20230714211724-9f58040921d7/go.mod h1:ts9/Zafxb9W9drZFTmQNMR7kLOyHyBw37NuowyiDork= | ||
github.com/0x51-dev/ri v0.0.0-20230708135038-029eea38546f h1:6bWTNS1c7TqLdQEruMwLvDQ7Jn+vJniE/dqeTmOenVA= | ||
github.com/0x51-dev/ri v0.0.0-20230708135038-029eea38546f/go.mod h1:jw6tYgXeAqwcKnvjTOI6rfGEhLj3R5PSMUbRlKL2DvM= | ||
github.com/0x51-dev/upeg v0.0.0-20230829161504-bdf1e5e3b220 h1:Agg2TMCsToB6SOGEHNa9EAJEG32Ej9pV+g6lRTlaQxg= | ||
github.com/0x51-dev/upeg v0.0.0-20230829161504-bdf1e5e3b220/go.mod h1:ts9/Zafxb9W9drZFTmQNMR7kLOyHyBw37NuowyiDork= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package testsuite | ||
|
||
import ( | ||
"fmt" | ||
ttl "github.com/0x51-dev/rdf/turtle" | ||
"github.com/0x51-dev/rdf/turtle/grammar/ir" | ||
) | ||
|
||
type ApprovalType string | ||
|
||
const ( | ||
Approved ApprovalType = "rdft:Approved" | ||
Proposed ApprovalType = "rdft:Proposed" | ||
Rejected ApprovalType = "rdft:Rejected" | ||
) | ||
|
||
type Manifest struct { | ||
Keys []string | ||
Entries map[string]*Test | ||
} | ||
|
||
func LoadManifest(raw string) (*Manifest, error) { | ||
doc, err := ttl.ParseDocument(raw) | ||
if err != nil { | ||
return nil, err | ||
} | ||
sm, err := doc.SubjectMap() | ||
if err != nil { | ||
return nil, err | ||
} | ||
manifest, ok := sm[""] | ||
if !ok { | ||
return nil, fmt.Errorf("manifest: no root") | ||
} | ||
pom, err := manifest.PredicateObjectMap() | ||
if err != nil { | ||
return nil, err | ||
} | ||
mfEntries, ok := pom["mf:entries"] | ||
if !ok { | ||
return nil, fmt.Errorf("manifest: no entries") | ||
} | ||
var keys []string | ||
entries := make(map[string]*Test) | ||
switch t := mfEntries[0].(type) { | ||
case ir.Collection: | ||
for _, entry := range t { | ||
var name string | ||
switch t := entry.(type) { | ||
case *ir.IRI: | ||
name = t.Value | ||
default: | ||
return nil, fmt.Errorf("manifest: entry name not an IRI") | ||
} | ||
keys = append(keys, name) | ||
entries[name], err = NewTest(sm[name]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
default: | ||
return nil, fmt.Errorf("manifest: entries not a collection") | ||
} | ||
return &Manifest{Keys: keys, Entries: entries}, nil | ||
} | ||
|
||
type Test struct { | ||
Type string | ||
Name string | ||
Comment string | ||
Approval ApprovalType | ||
Action string | ||
} | ||
|
||
func NewTest(triple ir.Triple) (*Test, error) { | ||
pom, err := triple.PredicateObjectMap() | ||
if err != nil { | ||
return nil, err | ||
} | ||
typ, ok := pom["rdf:type"] | ||
if !ok { | ||
// Alternate syntax used in NQuads tests. | ||
a, ok := pom["a"] | ||
if !ok { | ||
return nil, fmt.Errorf("test: no type") | ||
} | ||
typ = a | ||
} | ||
name, ok := pom["mf:name"] | ||
if !ok { | ||
return nil, fmt.Errorf("test: no name") | ||
} | ||
comment := pom["rdfs:comment"] | ||
approval := pom["rdft:approval"] | ||
action, ok := pom["mf:action"] | ||
if !ok { | ||
return nil, fmt.Errorf("test: no action") | ||
} | ||
return &Test{ | ||
Type: typ.String(), | ||
Name: (name[0].(*ir.StringLiteral)).Value, | ||
Comment: comment.String(), | ||
Approval: ApprovalType(approval.String()), | ||
Action: (action[0].(*ir.IRI)).Value, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package rdf_test | ||
|
||
import ( | ||
_ "embed" | ||
"github.com/0x51-dev/rdf/internal/testsuite" | ||
"testing" | ||
) | ||
|
||
var ( | ||
//go:embed ntriples/testdata/suite/manifest.ttl | ||
ntriples string | ||
) | ||
|
||
func TestLoadManifest(t *testing.T) { | ||
if _, err := testsuite.LoadManifest(ntriples); err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package rdf | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// BlankNode identifiers are local identifiers. | ||
type BlankNode struct { | ||
Attribute string | ||
} | ||
|
||
func (b *BlankNode) toObject(_ bool) (map[string]any, error) { | ||
return map[string]any{ | ||
"@id": b.Attribute, | ||
}, nil | ||
} | ||
|
||
type IRIReference struct { | ||
Value string | ||
} | ||
|
||
func (r *IRIReference) toObject(_ bool) (map[string]any, error) { | ||
return map[string]any{ | ||
"@id": r.Value, | ||
}, nil | ||
} | ||
|
||
// Literal is used to represent values such as strings, numbers, and dates. | ||
type Literal struct { | ||
// Value is a Unicode string. | ||
Value string | ||
// Datatype is an IRI identifying a datatype that determines how the lexical form maps to a literal value. | ||
Datatype DataType | ||
// Language can only be present if Datatype is XSDNSString. | ||
Language string | ||
} | ||
|
||
func (l *Literal) toObject(nativeTypes bool) (map[string]any, error) { | ||
if l.Language != "" { | ||
if l.Datatype != "" && l.Datatype != XSDNSString { | ||
return nil, fmt.Errorf("invalid datatype for language literal: %s", l.Datatype) | ||
} | ||
return map[string]any{ | ||
"@value": l.Value, | ||
"@language": l.Language, | ||
}, nil | ||
} | ||
if l.Datatype != XSDString { | ||
if nativeTypes { | ||
v, _, err := l.Datatype.NativeType(l.Value) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return map[string]any{ | ||
"@value": v, | ||
"@datatype": l.Datatype, | ||
}, nil | ||
} | ||
return map[string]any{ | ||
"@value": l.Value, | ||
"@datatype": l.Datatype, | ||
}, nil | ||
} | ||
return map[string]any{ | ||
"@value": l.Value, | ||
}, nil | ||
} | ||
|
||
type Node interface { | ||
toObject(nativeTypes bool) (map[string]any, error) | ||
} | ||
|
||
func FromObject(obj any, acceptString bool) (Node, error) { | ||
var id string | ||
switch obj := obj.(type) { | ||
case map[string]any: | ||
if v, ok := obj["@value"]; ok { | ||
var literal = &Literal{ | ||
Value: fmt.Sprintf("%v", v), | ||
Datatype: XSDString, | ||
} | ||
if datatype, ok := obj["@datatype"]; ok { | ||
s, ok := datatype.(string) | ||
if !ok { | ||
return nil, fmt.Errorf("invalid @datatype attribute: %T", datatype) | ||
} | ||
literal.Datatype = DataType(s) | ||
} | ||
if !literal.Datatype.Validate(v, acceptString) { | ||
return nil, fmt.Errorf("invalid @value for datatype %s: %v", literal.Datatype, v) | ||
} | ||
return literal, nil | ||
} | ||
|
||
if v, ok := obj["@id"]; ok { | ||
id, ok = v.(string) | ||
if !ok { | ||
return nil, fmt.Errorf("invalid @id attribute: %T", v) | ||
} | ||
} else { | ||
return nil, fmt.Errorf("missing @id attribute") | ||
} | ||
case string: | ||
id = obj | ||
default: | ||
return nil, fmt.Errorf("unknown object type: %T", obj) | ||
} | ||
if strings.HasPrefix(id, "_:") { | ||
return &BlankNode{Attribute: id}, nil | ||
} | ||
return &IRIReference{Value: id}, nil | ||
} |
Oops, something went wrong.