Skip to content

Instantly share code, notes, and snippets.

@banjun
Created December 23, 2018 06:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save banjun/aa86a04ae2f6b210c483ac4ceb247d73 to your computer and use it in GitHub Desktop.
Save banjun/aa86a04ae2f6b210c483ac4ceb247d73 to your computer and use it in GitHub Desktop.
im@sparql playground
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