Created
December 23, 2018 06:41
-
-
Save banjun/aa86a04ae2f6b210c483ac4ceb247d73 to your computer and use it in GitHub Desktop.
im@sparql playground
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
import Foundation | |
var str = "Hello, playground" | |
enum RDFT { | |
case iri(IRI) | |
case rdfl(RDFL) | |
// case rdfb(RDFB) | |
} | |
struct IRI { | |
var value: String | |
} | |
enum RDFL { | |
case plain(String) | |
} | |
struct Query { | |
var prefixes: [PrefixType] | |
var body: Body | |
struct Body { | |
var select: Select | |
enum Select { | |
case all | |
case fields([Field]) | |
enum Field { | |
case variable(Variable) | |
case raw(String) | |
} | |
} | |
var `where`: Where | |
struct Where { | |
var terms: [Term] | |
enum Term { | |
case triple(Triple) | |
case filter(Variable, String) | |
} | |
} | |
var groupBy: GroupBy? | |
enum GroupBy { | |
case variable(Variable) | |
} | |
var orderBy: OrderBy? | |
enum OrderBy { | |
case asc(Variable) | |
case desc(Variable) | |
} | |
} | |
struct Variable { | |
var name: String | |
} | |
/// トリプル・パターンは、次の集合のメンバーです。 | |
/// (RDF-T ∪ V) x (I ∪ V) x (RDF-T ∪ V) | |
struct Triple { | |
var left: RDFTOrV | |
var middle: IRIOrV | |
var right: RDFTOrV | |
} | |
enum RDFTOrV { | |
case rdft(RDFT) | |
case variable(Variable) | |
} | |
enum IRIOrV { | |
case iri(IRI) | |
case variable(Variable) | |
} | |
} | |
protocol QuerySerializable { | |
var query: String { get } | |
} | |
extension IRI: QuerySerializable { | |
var query: String { | |
return value | |
} | |
} | |
extension RDFL: QuerySerializable { | |
var query: String { | |
switch self { | |
case .plain(let s): return s | |
} | |
} | |
} | |
extension RDFT: QuerySerializable { | |
var query: String { | |
switch self { | |
case .iri(let i): return i.query | |
case .rdfl(let l): return l.query | |
} | |
} | |
} | |
extension Query: QuerySerializable { | |
var query: String { | |
return "\(prefixes.map {$0.query}.joined(separator: "\n"))\n\n\(body.query)" | |
} | |
} | |
extension PrefixType { | |
var query: String { | |
return "PREFIX \(prefixMeta.name): <\(prefixMeta.url.absoluteString)>" | |
} | |
} | |
extension Query.Body: QuerySerializable { | |
var query: String { | |
return [ | |
select.query, | |
`where`.query, | |
orderBy?.query, | |
groupBy?.query | |
].compactMap {$0}.joined(separator: "\n") | |
} | |
} | |
extension Query.Variable: QuerySerializable { | |
var query: String { | |
return "?\(name)" | |
} | |
} | |
extension Query.Body.Select: QuerySerializable { | |
var query: String { | |
switch self { | |
case .all: return "SELECT *" | |
case .fields(let fs): return "SELECT \(fs.map {$0.query}.joined(separator: " "))" | |
} | |
} | |
} | |
extension Query.Body.Select.Field: QuerySerializable { | |
var query: String { | |
switch self { | |
case .variable(let v): return v.query | |
case .raw(let s): return s | |
} | |
} | |
} | |
extension Query.Body.Where: QuerySerializable { | |
var query: String { | |
return "WHERE {\n\(terms.map {" " + $0.query}.joined(separator: "\n"))\n}" | |
} | |
} | |
extension Query.Body.Where.Term: QuerySerializable { | |
var query: String { | |
switch self { | |
case .triple(let t): return t.query | |
case .filter(let v, let s): return "filter(regex(str(\(v.query)), \"\(s)\"))" | |
} | |
} | |
} | |
extension Query.Triple: QuerySerializable { | |
var query: String { | |
return "\(left.query) \(middle.query) \(right.query)." | |
} | |
} | |
extension Query.RDFTOrV: QuerySerializable { | |
var query: String { | |
switch self { | |
case .rdft(let t): return t.query | |
case .variable(let v): return v.query | |
} | |
} | |
} | |
extension Query.IRIOrV: QuerySerializable { | |
var query: String { | |
switch self { | |
case .iri(let i): return i.query | |
case .variable(let v): return v.query | |
} | |
} | |
} | |
extension Query.Variable: ExpressibleByStringLiteral { | |
init(stringLiteral value: String) { | |
self.init(name: value) | |
} | |
} | |
extension Query.Body.OrderBy: QuerySerializable { | |
var query: String { | |
switch self { | |
case .asc(let v): return "order by(\(v.query))" | |
case .desc(let v): return "order by desc(\(v.query))" | |
} | |
} | |
} | |
extension Query.Body.GroupBy: QuerySerializable { | |
var query: String { | |
switch self { | |
case .variable(let v): return "group by(\(v.query))" | |
} | |
} | |
} | |
protocol PrefixType: QuerySerializable { | |
var prefixMeta: PrefixMeta { get } | |
} | |
struct PrefixMeta { | |
var name: String | |
var url: URL | |
} | |
/// To Be Generated | |
struct PrefixSchema: PrefixType { | |
var prefixMeta: PrefixMeta {return .init(name: "schema", url: URL(string: "http://schema.org/")!)} | |
var name: IRI {return .init(value: "\(prefixMeta.name):name")} | |
var alternateName: IRI {return .init(value: "\(prefixMeta.name):alternateName")} | |
var height: IRI {return .init(value: "\(prefixMeta.name):height")} | |
var member: IRI {return .init(value: "\(prefixMeta.name):member")} | |
// ... | |
} | |
/// To Be Generated | |
struct PrefixImas: PrefixType { | |
var prefixMeta: PrefixMeta {return .init(name: "imas", url: URL(string: "https://sparql.crssnky.xyz/imasrdf/URIs/imas-schema.ttl#")!)} | |
// ... | |
var unit: IRI {return .init(value: "\(prefixMeta.name):Unit")} | |
} | |
/// To Be Generated | |
struct PrefixRDF: PrefixType { | |
var prefixMeta: PrefixMeta {return .init(name: "rdf", url: URL(string: "http://www.w3.org/1999/02/22-rdf-syntax-ns#")!)} | |
// ... | |
var type: IRI {return .init(value: "\(prefixMeta.name):type")} | |
} | |
func fetch(_ query: Query, completion: @escaping (Data) -> Void) { | |
let endpoint = URL(string: "https://sparql.crssnky.xyz/spql/imas/query")! | |
let p = query.query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" | |
let req = URL(string: "https://sparql.crssnky.xyz/spql/imas/query?query=" + p)! | |
req.absoluteString | |
URLSession.shared.dataTask(with: req) { data, response, error in | |
guard let data = data else { | |
print(String(describing: error)) | |
return | |
} | |
print(String(data: data, encoding: .utf8)!) | |
completion(data) | |
}.resume() | |
} | |
struct Response<Binding: Codable>: Codable { | |
var results: Results | |
struct Results: Codable { | |
var bindings: [Binding] | |
} | |
} | |
///// | |
enum BuiltinPrefix { | |
static let schema = PrefixSchema() | |
static let rdf = PrefixRDF() | |
static let imas = PrefixImas() | |
// static let imasrdf = Query.Prefix(name: "imasrdf", iri: IRI("https://sparql.crssnky.xyz/imasrdf/RDFs/detail/")) | |
// static let foaf = Query.Prefix(name: "foaf", iri: IRI("http://xmlns.com/foaf/0.1/")) | |
// static let math = Query.Prefix(name: "math", iri: IRI("http://www.w3.org/2005/xpath-functions/math#")) | |
// static let xsd = Query.Prefix(name: "xsd", iri: IRI("https://www.w3.org/TR/xmlschema11-2/#")) | |
// static let rdfs = Query.Prefix(name: "rdfs", iri: IRI("http://www.w3.org/2000/01/rdf-schema#")) | |
} | |
let prefixes: [PrefixType] = [ | |
BuiltinPrefix.schema, | |
BuiltinPrefix.rdf, | |
BuiltinPrefix.imas, | |
// BuiltinPrefix.imasrdf, | |
// BuiltinPrefix.foaf, | |
// BuiltinPrefix.math, | |
// BuiltinPrefix.xsd, | |
// BuiltinPrefix.rdfs, | |
] | |
////////////////////////////////////// | |
struct BindingOH: Codable { | |
var o: Value | |
var h: Value | |
struct Value: Codable { | |
var value: String | |
} | |
} | |
let query = Query( | |
prefixes: prefixes, | |
body: Query.Body( | |
select: .fields([.variable("o"), .variable("h")]), | |
where: Query.Body.Where( | |
terms: [ | |
.triple(Query.Triple( | |
left: .variable("s"), | |
middle: .iri(BuiltinPrefix.schema.name), | |
right: .variable("o"))), | |
.triple(Query.Triple( | |
left: .variable("s"), | |
middle: .iri(BuiltinPrefix.schema.height), | |
right: .variable("h"))), | |
]), | |
groupBy: nil, | |
orderBy: .asc("h"))) | |
print(query.query) | |
fetch(query) { data in | |
do { | |
// print(String(data: data, encoding: .utf8)) | |
let r = try JSONDecoder().decode(Response<BindingOH>.self, from: data).results.bindings | |
let short = r.prefix(20) | |
short.forEach { b in | |
print("\(b.h.value)cm: \(b.o.value)") | |
} | |
} catch { | |
print(error) | |
} | |
} | |
/////////////////////////////////////////////// | |
struct BindingUnitMember: Codable { | |
var ユニット名: Value | |
var メンバー: Value | |
struct Value: Codable { | |
var value: String | |
} | |
} | |
struct Unit { | |
var ユニット名: String | |
var メンバー: String | |
init(_ binding: BindingUnitMember) { | |
ユニット名 = binding.ユニット名.value | |
メンバー = binding.メンバー.value | |
} | |
} | |
let query2 = Query(prefixes: prefixes, body: Query.Body( | |
select: .fields([.variable("ユニット名"), | |
Query.Body.Select.Field.raw("(group_concat(?名前;separator=\", \")as ?メンバー)"), | |
Query.Body.Select.Field.raw("(group_concat(?身長;separator=\", \")as ?メンバー身長)")]), | |
where: Query.Body.Where(terms: [ | |
.triple(.init( | |
left: .variable("s"), | |
middle: .iri(BuiltinPrefix.rdf.type), | |
right: .rdft(.iri(BuiltinPrefix.imas.unit)))), | |
.triple(.init( | |
left: .variable("s"), | |
middle: .iri(BuiltinPrefix.schema.name), | |
right: .variable("ユニット名"))), | |
.triple(.init( | |
left: .variable("s"), | |
middle: .iri(BuiltinPrefix.schema.member), | |
right: .variable("m"))), | |
.triple(.init( | |
left: .variable("m"), | |
middle: .iri(BuiltinPrefix.schema.name), | |
right: .variable("名前"))), | |
.triple(.init( | |
left: .variable("m"), | |
middle: .iri(BuiltinPrefix.schema.height), | |
right: .variable("身長"))), | |
.filter("名前", "ありす"), | |
]), | |
groupBy: .variable("ユニット名"), | |
orderBy: nil)) | |
print(query2.query) | |
/////////////////////////////////////////////// | |
fetch(query2) { data in | |
do { | |
let r = try JSONDecoder().decode(Response<BindingUnitMember>.self, from: data).results.bindings | |
let units = r.map {Unit($0)} | |
units | |
} catch { | |
print(error) | |
} | |
} | |
import PlaygroundSupport | |
PlaygroundPage.current.needsIndefiniteExecution = true | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment