Skip to content

Commit

Permalink
Add CQL language support
Browse files Browse the repository at this point in the history
  • Loading branch information
Querela committed Jul 11, 2024
1 parent 59e5a34 commit f2f44fa
Show file tree
Hide file tree
Showing 24 changed files with 700 additions and 0 deletions.
4 changes: 4 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@
"title": "Content-Security-Policy",
"owner": "ScottHelme"
},
"cql": {
"title": "Contextual Query Language",
"owner": "Querela"
},
"cooklang": {
"title": "Cooklang",
"owner": "ahue"
Expand Down
114 changes: 114 additions & 0 deletions components/prism-cql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
(function (Prism) {

var boolExp = /\b(?:AND|NOT|OR|PROX)\b/i;
var stringExp = /(?:"(?:\\[\s\S]|(?!")[^\\])*")/;
var wordExp = /[^\s()=<>"\/]+/;
var identifierExp = RegExp('(?:' + stringExp.source + '|' + wordExp.source + ')');

var comparitorNamedExp = identifierExp;
var comparitorSymbolExp = /(?:<>|[=><]=?)/;
var comparitorExp = RegExp('(?:' + comparitorSymbolExp.source + '|' + comparitorNamedExp.source + ')');

var modifierExp = RegExp('/\\s*' + identifierExp.source + '(?:\\s*' + comparitorSymbolExp.source + '\\s*' + identifierExp.source + ')?');
var modifierListExp = RegExp('(?:\\s*' + modifierExp.source + ')*');

var relationExp = RegExp(comparitorExp.source + modifierListExp.source);

var modifier = {
pattern: modifierExp,
inside: {
'modifier': {
pattern: RegExp('(/\\s*)' + identifierExp.source),
lookbehind: true,
alias: 'property',
},
'value': {
pattern: RegExp(identifierExp.source + '$'),
alias: 'string',
},
'comparitor': {
pattern: comparitorSymbolExp,
alias: 'operator',
},
'punctuation': /\//,
}
};

var searchClause = {
pattern: RegExp('(?:' + identifierExp.source + '\\s*' + relationExp.source + '\\s*)?' + identifierExp.source),
inside: {
// required last part, search term
'term': {
pattern: RegExp(identifierExp.source + '(?!.)'),
alias: 'string',
},
// optional index with relation
'index': {
pattern: RegExp('^' + identifierExp.source),
alias: 'property',
},
'relation-modifier': modifier,
'relation': {
pattern: comparitorExp,
alias: 'operator',
},
},
};

var boolClause = {
pattern: RegExp(boolExp.source + modifierListExp.source, 'i'),
inside: {
'boolean': {
pattern: boolExp,
alias: 'operator'
},
'boolean-modifier': modifier,
},
};

var prefix = {
pattern: RegExp('(^\\s*)>\\s*(?:' + identifierExp.source + '\\s*=\\s*)?' + identifierExp.source),
lookbehind: true,
inside: {
'uri': {
pattern: RegExp(identifierExp.source + '$'),
alias: 'string',
},
'prefix': {
pattern: identifierExp,
alias: 'property',
},
'punctuation': /[>=]/,
}
};

var sortby = {
// XXX: too complex exponential/polynomial backtracking possible ...
//pattern: RegExp('sortby(?:\\s*' + identifierExp.source + modifierListExp.source + ')+\\s*$', 'i'),
pattern: RegExp('(^|\\s)sortby\\b(?:' + identifierExp.source + '\\b|[\\s=></])+$', 'i'),
lookbehind: true,
inside: {
'keyword': /sortby/i,
'sortby-index-modifier': modifier,
'index': {
pattern: identifierExp,
alias: 'property',
}
}
};

Prism.languages['cql'] = {
// prefix / suffix
'prefix': prefix,
'sortby': sortby,

// conjuctions
'bool-group': boolClause,
// search clause triples
'search-clause': searchClause,

// grouping
'punctuation': /[()]/,
};

}(Prism));
60 changes: 60 additions & 0 deletions examples/prism-cql.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<h2>CQL Query</h2>

<pre><code>dc.title any fish</code></pre>
<pre><code>dc.title any fish or dc.creator any sanderson</code></pre>
<pre><code>dc.title any fish sortBy dc.date/sort.ascending</code></pre>
<pre><code>> dc = "info:srw/context-sets/1/dc-v1.1" dc.title any fish</code></pre>

<h2>Search Clause</h2>

<pre><code>dc.title any fish</code></pre>
<pre><code>fish</code></pre>
<pre><code>cql.serverChoice = fish</code></pre>

<h2>Search Term</h2>

<pre><code>"fish"</code></pre>
<pre><code>fish</code></pre>
<pre><code>"squirrels fish"</code></pre>
<pre><code>""</code></pre>

<h2>Index Name</h2>

<pre><code>title any fish</code></pre>
<pre><code>dc.title any fish</code></pre>

<h2>Relation</h2>

<pre><code>dc.title any fish</code></pre>
<pre><code>dc.title cql.any fish</code></pre>

<h2>Relation Modifiers</h2>

<pre><code>dc.title any/relevant fish</code></pre>
<pre><code>dc.title any/ relevant /cql.string fish</code></pre>
<pre><code>dc.title any/rel.algorithm=cori fish</code></pre>

<h2>Boolean Operators</h2>

<pre><code>dc.title any fish or dc.creator any sanderson</code></pre>
<pre><code>dc.title any fish or (dc.creator any sanderson and dc.identifier = "id:1234567")</code></pre>

<h2>Boolean Modifiers</h2>

<pre><code>dc.title any fish or/rel.combine=sum dc.creator any sanderson</code></pre>
<pre><code>dc.title any fish prox/unit=word/distance&gt;3 dc.title any squirrel</code></pre>

<h2>Sorting</h2>

<pre><code>"cat" sortBy dc.title</code></pre>
<pre><code>"dinosaur" sortBy dc.date/sort.descending dc.title/sort.ascending</code></pre>

<h2>Prefix Assignment</h2>

<pre><code>&gt; dc = "http://deepcustard.org/" dc.custardDepth &gt; 10</code></pre>
<pre><code>&gt; "http://deepcustard.org/" custardDepth &gt; 10</code></pre>

<h2>Case Insensitive</h2>

<pre><code>dC.tiTlE any fish</code></pre>
<pre><code>dc.TitlE Any/rEl.algOriThm=cori fish soRtbY Dc.TitlE </code></pre>
57 changes: 57 additions & 0 deletions tests/languages/cql/boolean_modifiers.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
dc.title any fish or/rel.combine=sum dc.creator any sanderson

dc.title any fish prox/unit=word/distance>3 dc.title any squirrel

----------------------------------------------------

[
["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]],
["bool-group", [
["boolean", "or"],
["boolean-modifier", [
["punctuation", "/"],
["modifier", "rel.combine"],
["comparitor", "="],
["value", "sum"]
]]
]],
["search-clause", [
["index", "dc.creator"],
["relation", "any"],
["term", "sanderson"]
]],

["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]],
["bool-group", [
["boolean", "prox"],
["boolean-modifier", [
["punctuation", "/"],
["modifier", "unit"],
["comparitor", "="],
["value", "word"]
]],
["boolean-modifier", [
["punctuation", "/"],
["modifier", "distance"],
["comparitor", ">"],
["value", "3"]
]]
]],
["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "squirrel"]
]]
]

----------------------------------------------------

Boolean modifiers.
49 changes: 49 additions & 0 deletions tests/languages/cql/boolean_operators.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
dc.title any fish or dc.creator any sanderson

dc.title any fish or (dc.creator any sanderson and dc.identifier = "id:1234567")

----------------------------------------------------

[
["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]],
["bool-group", [
["boolean", "or"]
]],
["search-clause", [
["index", "dc.creator"],
["relation", "any"],
["term", "sanderson"]
]],

["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]],
["bool-group", [
["boolean", "or"]
]],
["punctuation", "("],
["search-clause", [
["index", "dc.creator"],
["relation", "any"],
["term", "sanderson"]
]],
["bool-group", [
["boolean", "and"]
]],
["search-clause", [
["index", "dc.identifier"],
["relation", "="],
["term", "\"id:1234567\""]
]],
["punctuation", ")"]
]

----------------------------------------------------

Boolean operators.
33 changes: 33 additions & 0 deletions tests/languages/cql/case_insensitive.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
dC.tiTlE any fish

dc.TitlE Any/rEl.algOriThm=cori fish soRtbY Dc.TitlE

----------------------------------------------------

[
["search-clause", [
["index", "dC.tiTlE"],
["relation", "any"],
["term", "fish"]
]],

["search-clause", [
["index", "dc.TitlE"],
["relation", "Any"],
["relation-modifier", [
["punctuation", "/"],
["modifier", "rEl.algOriThm"],
["comparitor", "="],
["value", "cori"]
]],
["term", "fish"]
]],
["sortby", [
["keyword", "soRtbY"],
["index", "Dc.TitlE"]
]]
]

----------------------------------------------------

Case Insenstivity.
15 changes: 15 additions & 0 deletions tests/languages/cql/clause_feature_1.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
dc.title any fish

----------------------------------------------------

[
["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]]
]

----------------------------------------------------

Search clauses.
13 changes: 13 additions & 0 deletions tests/languages/cql/clause_feature_2.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fish

----------------------------------------------------

[
["search-clause", [
["term", "fish"]
]]
]

----------------------------------------------------

Search clauses.
15 changes: 15 additions & 0 deletions tests/languages/cql/clause_feature_3.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
cql.serverChoice = fish

----------------------------------------------------

[
["search-clause", [
["index", "cql.serverChoice"],
["relation", "="],
["term", "fish"]
]]
]

----------------------------------------------------

Search clauses.
23 changes: 23 additions & 0 deletions tests/languages/cql/index_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
title any fish

dc.title any fish

----------------------------------------------------

[
["search-clause", [
["index", "title"],
["relation", "any"],
["term", "fish"]
]],

["search-clause", [
["index", "dc.title"],
["relation", "any"],
["term", "fish"]
]]
]

----------------------------------------------------

Index names.
Loading

0 comments on commit f2f44fa

Please sign in to comment.