Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wild behavior when SELECT is missing + other improvements in this vein #77

Merged
merged 4 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions backend/static/js/codemirror/modes/sparql/sparql.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,22 @@ const CONTEXTS = [
const COMPLEXTYPES = [
{
name: 'PREFIX',
definition: /PREFIX (.*)/g,
definition: /PREFIX (.*)/gi,
suggestions: [['PREFIX ', function (c) { return getPrefixSuggestions(c); }, '\n']],
availableInContext: ['PrefixDecl', 'undefined'],

},
{
name: 'SELECT',
definition: /SELECT (.*)/g,
definition: /SELECT (.*)/gi,
suggestions: [['SELECT * WHERE {\n \n}\n']],
availableInContext: ['PrefixDecl', 'undefined', 'SubQuery'],
onlyOnce: true,

},
{
name: 'DISTINCT',
definition: /DISTINCT|[?\w]+ [?\w]*/g,
definition: /DISTINCT|[?\w]+ [?\w]*/gi,
suggestions: [['DISTINCT ']],
availableInContext: ['SelectClause'],
onlyOnce: true,
Expand All @@ -113,116 +113,116 @@ const COMPLEXTYPES = [
},
{
name: 'TEXT',
definition: /TEXT\((.*)\)/g,
definition: /TEXT\((.*)\)/gi,
suggestions: [['TEXT(', function (c) { var a = []; $(getVariables(c, true, "text")).each(function (k, v) { a.push(v) }); return a; }, ') ']],
availableInContext: ['SelectClause'],

},
{
name: 'SCORE',
definition: /SCORE\((.*)\)/g,
definition: /SCORE\((.*)\)/gi,
suggestions: [['SCORE(', function (c) { var a = []; $(getVariables(c, true, "text")).each(function (k, v) { a.push(v) }); return a; }, ') ']],
availableInContext: ['SelectClause', 'OrderCondition'],

},
{
name: 'MIN',
definition: /\(MIN\((.*)\) as (.*)\)/g,
definition: /\(MIN\((.*)\) as (.*)\)/gi,
suggestions: [['(MIN(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?min_{[0]}) ']],
availableInContext: ['SelectClause', 'OrderCondition'],

},
{
name: 'MAX',
definition: /\(MAX\((.*)\) as (.*)\)/g,
definition: /\(MAX\((.*)\) as (.*)\)/gi,
suggestions: [['(MAX(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?max_{[0]}) ']],
availableInContext: ['SelectClause', 'OrderCondition'],

},
{
name: 'SUM',
definition: /\(SUM\((.*)\) as (.*)\)/g,
definition: /\(SUM\((.*)\) as (.*)\)/gi,
suggestions: [['(SUM(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?sum_{[1]}) ']],
availableInContext: ['SelectClause', 'OrderCondition'],

},
{
name: 'AVG',
definition: /\(AVG\((.*)\) as (.*)\)/g,
definition: /\(AVG\((.*)\) as (.*)\)/gi,
suggestions: [['(AVG(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?avg_{[1]}) ']],
availableInContext: ['SelectClause', 'OrderCondition'],

},
{
name: 'SAMPLE',
definition: /\(SAMPLE\((.*)\) as (.*)\)/g,
definition: /\(SAMPLE\((.*)\) as (.*)\)/gi,
suggestions: [['(SAMPLE(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?sample_{[0]}) ']],
availableInContext: ['SelectClause'],

},
{
name: 'COUNT',
definition: /\(COUNT\((.*)\) as (.*)\)/g,
definition: /\(COUNT\((.*)\) as (.*)\)/gi,
suggestions: [['(COUNT(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?count_{[1]}) ']],
availableInContext: ['SelectClause'],

},
{
name: 'GROUP_CONCAT',
definition: /\(GROUP_CONCAT\((.*)\) as (.*)\)/g,
definition: /\(GROUP_CONCAT\((.*)\) as (.*)\)/gi,
suggestions: [['(GROUP_CONCAT(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?concat_{[1]}) ']],
availableInContext: ['SelectClause'],

},
{
name: 'LIMIT',
definition: /\bLIMIT ([0-9+])/g,
definition: /\bLIMIT ([0-9+])/gi,
suggestions: [['LIMIT ', [1, 10, 100, 1000], '\n']],
availableInContext: ['SolutionModifier'],
onlyOnce: true,

},
{
name: 'TEXTLIMIT',
definition: /TEXTLIMIT ([0-9+])/g,
definition: /TEXTLIMIT ([0-9+])/gi,
suggestions: [['TEXTLIMIT ', [2, 5, 10], '\n']],
availableInContext: ['SolutionModifier'],
onlyOnce: true,

},
{
name: 'ASC',
definition: /ASC(\?.*)/g,
definition: /ASC(\?.*)/gi,
suggestions: [['ASC(', function (c) { var a = getVariables(c); for (var v of getVariables(c, undefined, "text")) { a.push("SCORE(" + v + ")"); }; return a; }, ') ']],
availableInContext: ['OrderCondition'],

},
{
name: 'DESC',
definition: /DESC(\?.*)/g,
definition: /DESC(\?.*)/gi,
suggestions: [['DESC(', function (c) { var a = getVariables(c); for (var v of getVariables(c, undefined, "text")) { a.push("SCORE(" + v + ")"); }; return a; }, ') ']],
availableInContext: ['OrderCondition'],

},
{
name: 'ORDER BY',
definition: /ORDER BY .*/g,
definition: /ORDER BY .*/gi,
suggestions: [['ORDER BY ']],
availableInContext: ['SolutionModifier'],
onlyOnce: true,

},
{
name: 'GROUP BY',
definition: /GROUP BY \?(.+)/g,
definition: /GROUP BY \?(.+)/gi,
suggestions: [['GROUP BY ']],
availableInContext: ['SolutionModifier'],
onlyOnce: true,

},
{
name: 'HAVING',
definition: /HAVING\?(.+)/g,
definition: /HAVING\?(.+)/gi,
suggestions: [['HAVING(', function (c) { return getVariables(c); }, ' ']],
availableInContext: ['SolutionModifier'],
onlyOnce: true,
Expand All @@ -236,15 +236,15 @@ const COMPLEXTYPES = [
},
{
name: 'REGEX',
definition: /REGEX(\?.*)/g,
definition: /REGEX(\?.*)/gi,
suggestions: [['REGEX(', function (c) { return getVariables(c, true); }]],
onlyOncePerVariation: true,
availableInContext: ['Filter'],

},
{
name: 'FILTER',
definition: /FILTER\((.*)/g,
definition: /FILTER\((.*)/gi,
suggestions: [['FILTER ']],
availableInContext: ['WhereClause', 'OptionalClause', 'UnionClause'],
requiresEmptyLine: true,
Expand All @@ -253,7 +253,7 @@ const COMPLEXTYPES = [
},
{
name: 'FILTER LANGUAGE',
definition: /LANG(.*)/g,
definition: /LANG(.*)/gi,
suggestions: [['(LANG(', function (c) { var a = []; for (var v of getVariables(c, undefined, undefined, LANGUAGELITERAL)) { if (editor.getValue().indexOf("FILTER(LANG(" + v) == -1) { a.push(v); } }; return a; }, ') = ', LANGUAGES, ') .\n']],
availableInContext: ['Filter'],
},
Expand Down
20 changes: 14 additions & 6 deletions backend/static/js/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ function splitSparqlQueryIntoParts(query) {
.replace(/\(\s+/g, "(").replace(/\s+\)/g, ")")
.replace(/\{\s*/g, "{ ").replace(/\s*\.?\s*\}$/g, " }");
// console.log("SPLIT_SPARQL_QUERY_INTO_PARTS:", query_with_spaces_normalized)
const pattern = /^\s*(.*?)\s*SELECT\s+([^{]*\S)\s*WHERE\s*{\s*(\S.*\S)\s*}\s*(.*?)\s*$/m;
const pattern = /^\s*(.*?)\s*SELECT\s+([^{]*\S)\s*WHERE\s*{\s*(\S.*\S)\s*}\s*(.*?)\s*$/mi;
var match = query_normalized.match(pattern);
if (!match) {
throw "ERROR: Query did not match regex for SELECT queries";
Expand Down Expand Up @@ -625,17 +625,17 @@ function cleanLines(cm) {
cm.setSelection(selection.anchor, selection.head);
}

// Triggered when using TAB
// Triggered when the `TAB` key is pressed; see `qleverUI`, search for
// `extraKeys` in `CodeMirror` initialization.
function switchStates(cm) {

var cur = editor.getCursor(); // current cursor position
var absolutePosition = editor.indexFromPos({ 'line': cur.line, 'ch': cur.ch + 1 }); // absolute cursor position in text

var content = cm.getValue();

var gaps = [];

var gap1 = /WHERE/g
var gap1 = /WHERE/gi
while ((match = gap1.exec(content)) != null) {
gaps.push(match.index + match[0].length - 5);
}
Expand Down Expand Up @@ -669,12 +669,13 @@ function switchStates(cm) {

var newCursor = editor.posFromIndex(found);
editor.setCursor(newCursor);

var line = cm.getLine(newCursor.line);

indentWhitespaces = (" ".repeat((line.length - line.trimStart().length)))

if (line.slice(newCursor.ch, newCursor.ch + 5) == "WHERE") {
// add empty whitespace in select if not present
if (line.slice(newCursor.ch, newCursor.ch + 5).toUpperCase() == "WHERE") {
// Add empty whitespace in select if not present
log("Found SELECT-Placeholder on postion " + found, 'other');
cm.setSelection({ 'line': newCursor.line, 'ch': line.length - 8 }, { 'line': newCursor.line, 'ch': line.length - 7 });
cm.replaceSelection(" ");
Expand Down Expand Up @@ -702,6 +703,12 @@ function switchStates(cm) {

cm.setSelection(cm.getCursor(), cm.getCursor());

// Now that the cursor is set at a new position, clean up the query.
//
// NOTE: Previously, this was done after every cursor movement in
// `qleverUI.js`, where it says `editor.on("cursorActivity", ...)`.
cleanLines(cm);

window.setTimeout(function () {
CodeMirror.commands.autocomplete(editor);
}, 100);
Expand Down Expand Up @@ -918,6 +925,7 @@ function getFormattedResultEntry(str, maxLength, column = undefined) {
// the column header.
// console.log("Check if \"" + str + "\" in column \"" + var_name + "\" is a float ...");
if (var_name.endsWith("?note") || var_name.endsWith("_note")) str = parseFloat(str).toFixed(2).toString();
if (var_name.endsWith("?grade") || var_name.endsWith("_grade")) str = parseFloat(str).toFixed(2).toString();
if (var_name.endsWith("_per_paper")) str = parseFloat(str).toFixed(2).toString();
if (var_name.endsWith("_perc") || var_name.endsWith("percent")) str = parseFloat(str).toFixed(2).toString();
if (var_name.endsWith("?lp_proz")) str = parseFloat(str).toFixed(0).toString();
Expand Down
18 changes: 10 additions & 8 deletions backend/static/js/qleverUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ $(document).ready(function () {
// Initialization done.
log('Editor initialized', 'other');

// Do some custom activities on cursor activity
// When cursor moves, make sure that tooltips are closed.
editor.on("cursorActivity", function (instance) {
$('[data-tooltip=tooltip]').tooltip('hide');
cleanLines(instance);
// cleanLines(instance);
});

editor.on("update", function (instance, event) {
Expand All @@ -107,18 +107,20 @@ $(document).ready(function () {
// Do some custom activities (overwrite codemirror behaviour)
editor.on("keyup", function (instance, event) {

// For each prefix in COLLECTEDPREFIXES, check whether it occurs somewhere
// in the query and if so, add it before the first SELECT (and move
// the cursor accordingly).
if (FILLPREFIXES) {
// For each prefix in `COLLECTEDPREFIXES`, check whether it occurs
// somewhere in the query and if so, add it before the first `SELECT` or
// `CONSTRUCT` (and move the cursor accordingly). If there is no `SELECT`
// or `CONSTRUCT`, do nothing.
let select_or_construct_regex = /(^| )(SELECT|CONSTRUCT)/mi;
if (FILLPREFIXES && select_or_construct_regex.test(editor.getValue())) {
let queryString = editor.getValue();
let newCursor = editor.getCursor();
let linesAdded = 0;
for (var prefix in COLLECTEDPREFIXES) {
const fullPrefix = "PREFIX " + prefix + ": <" + COLLECTEDPREFIXES[prefix] + ">";
if (doesQueryFragmentContainPrefix(queryString, prefix) &&
queryString.indexOf(fullPrefix) == -1) {
queryString = queryString.replace(/(^| )(SELECT)/m, fullPrefix + "\n$1$2");
queryString = queryString.replace(select_or_construct_regex, fullPrefix + "\n$1$2");
linesAdded += 1;
}
}
Expand Down Expand Up @@ -180,7 +182,7 @@ $(document).ready(function () {

for (var line of lines) {
if (line.trim().startsWith("PREFIX")) {
var match = /PREFIX (.*): ?<(.*)>/g.exec(line.trim());
var match = /PREFIX (.*): ?<(.*)>/gi.exec(line.trim());
if (match) {
prefixes += line.trim() + '\n';
}
Expand Down