Skip to content

Commit

Permalink
Translate the messages better, add in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelafox committed Sep 21, 2018
1 parent b3d0c6b commit 9d9260b
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 90 deletions.
71 changes: 50 additions & 21 deletions build/js/live-editor.output_sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -805,57 +805,86 @@ window.SQLOutput = Backbone.View.extend({
* error message. SQLlite error messages aren't always very descriptive,
* this should make common syntax errors easier to understand.
*/
getErrorMessage: function getErrorMessage(errorMessage, statement) {
errorMessage = errorMessage || "";
getErrorMessage: function getErrorMessage(sqliteError, statement) {
sqliteError = sqliteError || "";
statement = statement || "";
statement = statement.toUpperCase();

// Error messages take form: 'near \"%T\": syntax error'
var isSyntaxError = errorMessage.indexOf(": syntax error") > -1;
var errorMessage = sqliteError;

// First, we translate SQLite errors into friendly i18n-able messages

var colTypesError = sqliteError.indexOf("valid column types") > -1;
if (colTypesError) {
errorMessage = i18n._("Please use one of the valid column types " + "when creating a table: ") + "\"TEXT\", \"NUMERIC\", \"INTEGER\", \"REAL\", \"NONE\".";
}
var uniqError = sqliteError.indexOf("UNIQUE constraint failed:") > -1;
if (uniqError) {
var colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("\"UNIQUE\" constraint failed on column \"%(colName)s\".", { colName: colName });
}
var notNullError = sqliteError.indexOf("NOT NULL constraint") > -1;
if (notNullError) {
var colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("\"NOT NULL\" constraint failed on column \"%(colName)s\".", { colName: colName });
}
var dupColError = sqliteError.indexOf("duplicate column name:") > -1;
if (dupColError) {
var colName = errorMessage.split(":")[1].trim();
errorMessage = i18n._("You have multiple columns named \"%(colName)s\" - " + "column names must be unique.", { colName: colName });
}
var unknownColError = sqliteError.indexOf("no such column:") > -1;
if (unknownColError) {
var colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("We can't find the column named \"%(colName)s\".", { colName: colName });
}
var noTablesError = sqliteError.indexOf("no tables specified") > -1;
if (noTablesError) {
errorMessage = i18n._("You didn't specify any tables for your \"SELECT\".");
}
// Generic syntax error messages take form: 'near \"%T\": syntax error'
var isSyntaxError = sqliteError.indexOf(": syntax error") > -1;
if (isSyntaxError) {
var nearPhrase = errorMessage.split(":")[0];
errorMessage = i18n._("There's a syntax error near %(nearThing)s.", { nearThing: nearPhrase.substr(5) });
}

// Possible SELECT with missing FROM
if (errorMessage.indexOf("no such column:") !== -1 && statement.indexOf("SELECT") !== -1 && statement.indexOf("FROM") === -1) {
errorMessage += " " + i18n._("Are you missing a FROM clause?");
// Possible INSERT with missing INTO
// Now that we've translated the base error messages,
// we add on additional helper messages for common mistakes
if (unknownColError && statement.indexOf("SELECT") !== -1 && statement.indexOf("FROM") === -1) {
errorMessage += " " + i18n._("Are you perhaps missing a \"FROM\" clause?");
} else if (isSyntaxError && statement.indexOf("INSERT") !== -1 && statement.indexOf("VALUES") !== -1 && statement.indexOf("INTO") === -1) {
errorMessage += " " + i18n._("Are you missing the INTO keyword?");
// Possible INSERT INTO with missing VALUES
errorMessage += " " + i18n._("Are you missing the \"INTO\" keyword?");
} else if (isSyntaxError && statement.indexOf("INSERT") !== -1 && statement.indexOf("INTO") !== -1 && statement.indexOf("VALUES") === -1) {
errorMessage += " " + i18n._("Are you missing the VALUES keyword?");
errorMessage += " " + i18n._("Are you missing the \"VALUES\" keyword?");
} else if (statement.indexOf("INTERGER") !== -1) {
errorMessage += " " + i18n._("Is INTEGER spelled correctly?");
errorMessage += " " + i18n._("Is \"INTEGER\" spelled correctly?");
} else if (isSyntaxError && statement.indexOf("CREATE") !== -1 && statement.search(/CREATE TABLE \w+\s\w+/) > -1) {
errorMessage += " " + i18n._("You can't have a space in your table name.");
} else if (isSyntaxError && statement.indexOf("CREATE TABLE (") > -1) {
errorMessage += " " + i18n._("Are you missing the table name?");
} else if (isSyntaxError && statement.indexOf("PRIMARY KEY INTEGER") !== -1) {
errorMessage += " " + i18n._("Did you mean to put PRIMARY KEY after INTEGER?");
errorMessage += " " + i18n._("Perhaps you meant to put \"PRIMARY KEY\" after \"INTEGER\"?");
} else if (isSyntaxError && statement.indexOf("(") !== -1 && statement.indexOf(")") === -1) {
errorMessage += " " + i18n._("Are you missing a parenthesis?");
} else if (isSyntaxError && statement.indexOf("CREATE") !== -1 && statement.indexOf("TABLE") === -1 && (statement.indexOf("INDEX") === -1 || statement.indexOf("TRIGGER") === -1 || statement.indexOf("VIEW") === -1)) {
errorMessage += " " + i18n._("You may be missing what to create. For " + "example, CREATE TABLE...");
errorMessage += " " + i18n._("You may be missing what to create. For " + "example, \"CREATE TABLE...\"");
} else if (isSyntaxError && statement.indexOf("UPDATE") !== -1 && statement.indexOf("SET") === -1) {
errorMessage += " " + i18n._("Are you missing the SET keyword?");
errorMessage += " " + i18n._("Are you missing the \"SET\" keyword?");
} else if (isSyntaxError && statement.search(/[^SUM]\s*\(.*\)\n*\s*\w+/) > -1 || statement.search(/\n+\s*SELECT/) > -1 || statement.search(/\)\n+\s*INSERT/) > -1) {
errorMessage += " " + i18n._("Do you have a semi-colon after each statement?");
} else if (isSyntaxError && statement.indexOf("INSERT") !== -1 && statement.search(/[^INSERT],\d*\s*[a-zA-Z]+/) > -1) {
errorMessage += " " + i18n._("Are you missing quotes around text values?");
} else if (isSyntaxError && statement.search(/,\s*\)/) > -1) {
errorMessage += " " + i18n._("Do you have an extra comma?");
} else if (isSyntaxError && statement.indexOf("INSERT,") > -1) {
errorMessage += " " + i18n._("There shouldn't be a comma after INSERT.");
} else if (errorMessage.indexOf("column types") > -1 && statement.search(/(\w+\s*,\s*((TEXT)|(INTEGER))+)/) > -1) {
errorMessage += " " + i18n._("There shouldn't be a comma after \"INSERT\".");
} else if (colTypesError && statement.search(/(\w+\s*,\s*((TEXT)|(INTEGER))+)/) > -1) {
errorMessage += " " + i18n._("Do you have an extra comma between the name and type?");
} else if (errorMessage.indexOf("column types") > -1 && statement.search(/(\w+\s+\w+\s*((TEXT)|(INTEGER)|(REAL))+)/) > -1) {
} else if (colTypesError && statement.search(/(\w+\s+\w+\s*((TEXT)|(INTEGER)|(REAL))+)/) > -1) {
errorMessage = i18n._("You can't have a space in your column name.");
} else if (errorMessage.indexOf("UNIQUE constraint failed") !== -1) {
} else if (uniqError) {
errorMessage += " " + i18n._("Are you specifying a different value for each row?");
} else if (errorMessage.indexOf("duplicate column name:") !== -1) {
errorMessage = i18n._("You have multiple columns named `%(name)s` - " + "column names must be unique.", { name: errorMessage.split(":")[1].trim() });
}
return errorMessage;
},
Expand Down
79 changes: 56 additions & 23 deletions js/output/sql/sql-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,77 @@ window.SQLOutput = Backbone.View.extend({
* error message. SQLlite error messages aren't always very descriptive,
* this should make common syntax errors easier to understand.
*/
getErrorMessage: function(errorMessage, statement) {
errorMessage = errorMessage || "";
getErrorMessage: function(sqliteError, statement) {
sqliteError = sqliteError || "";
statement = statement || "";
statement = statement.toUpperCase();

// Error messages take form: 'near \"%T\": syntax error'
var isSyntaxError = errorMessage.indexOf(": syntax error") > -1;
let errorMessage = sqliteError;

// First, we translate SQLite errors into friendly i18n-able messages

const colTypesError = sqliteError.indexOf("valid column types") > -1;
if (colTypesError) {
errorMessage = i18n._("Please use one of the valid column types " +
"when creating a table: ")
+ "\"TEXT\", \"NUMERIC\", \"INTEGER\", \"REAL\", \"NONE\".";
}
const uniqError = sqliteError.indexOf("UNIQUE constraint failed:") > -1;
if (uniqError) {
const colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("\"UNIQUE\" constraint failed on column \"%(colName)s\".",
{colName});
}
const notNullError = sqliteError.indexOf("NOT NULL constraint") > -1;
if (notNullError) {
const colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("\"NOT NULL\" constraint failed on column \"%(colName)s\".",
{colName});
}
const dupColError = sqliteError.indexOf("duplicate column name:") > -1;
if (dupColError) {
const colName = errorMessage.split(":")[1].trim();
errorMessage = i18n._("You have multiple columns named \"%(colName)s\" - " +
"column names must be unique.", {colName});
}
const unknownColError = sqliteError.indexOf("no such column:") > -1;
if (unknownColError) {
const colName = sqliteError.split(":")[1].trim();
errorMessage = i18n._("We can't find the column named \"%(colName)s\".",
{colName});
}
const noTablesError = sqliteError.indexOf("no tables specified") > -1;
if (noTablesError) {
errorMessage = i18n._("You didn't specify any tables for your \"SELECT\".");
}
// Generic syntax error messages take form: 'near \"%T\": syntax error'
const isSyntaxError = sqliteError.indexOf(": syntax error") > -1;
if (isSyntaxError) {
const nearPhrase = errorMessage.split(":")[0];
errorMessage = i18n._("There's a syntax error near %(nearThing)s.",
{nearThing: nearPhrase.substr(5)});
}

// Possible SELECT with missing FROM
if (errorMessage.indexOf("no such column:") !== -1 &&
// Now that we've translated the base error messages,
// we add on additional helper messages for common mistakes
if (unknownColError &&
statement.indexOf("SELECT") !== -1 &&
statement.indexOf("FROM") === -1) {
errorMessage += " " + i18n._("Are you missing a FROM clause?");
// Possible INSERT with missing INTO
errorMessage += " " + i18n._("Are you perhaps missing a \"FROM\" clause?");
} else if (isSyntaxError &&
statement.indexOf("INSERT") !== -1 &&
statement.indexOf("VALUES") !== -1 &&
statement.indexOf("INTO") === -1) {
errorMessage += " " + i18n._("Are you missing the INTO keyword?");
// Possible INSERT INTO with missing VALUES
errorMessage += " " + i18n._("Are you missing the \"INTO\" keyword?");
} else if (isSyntaxError &&
statement.indexOf("INSERT") !== -1 &&
statement.indexOf("INTO") !== -1 &&
statement.indexOf("VALUES") === -1) {
errorMessage += " " +
i18n._("Are you missing the VALUES keyword?");
i18n._("Are you missing the \"VALUES\" keyword?");
} else if (statement.indexOf("INTERGER") !== -1) {
errorMessage += " " +
i18n._("Is INTEGER spelled correctly?");
i18n._("Is \"INTEGER\" spelled correctly?");
} else if (isSyntaxError &&
statement.indexOf("CREATE") !== -1 &&
statement.search(/CREATE TABLE \w+\s\w+/) > -1) {
Expand All @@ -106,7 +143,7 @@ window.SQLOutput = Backbone.View.extend({
} else if (isSyntaxError &&
statement.indexOf("PRIMARY KEY INTEGER") !== -1) {
errorMessage += " " +
i18n._("Did you mean to put PRIMARY KEY after INTEGER?");
i18n._("Perhaps you meant to put \"PRIMARY KEY\" after \"INTEGER\"?");
} else if (isSyntaxError &&
statement.indexOf("(") !== -1 &&
statement.indexOf(")") === -1) {
Expand All @@ -120,12 +157,12 @@ window.SQLOutput = Backbone.View.extend({
statement.indexOf("VIEW") === -1)) {
errorMessage += " " +
i18n._("You may be missing what to create. For " +
"example, CREATE TABLE...");
"example, \"CREATE TABLE...\"");
} else if (isSyntaxError &&
statement.indexOf("UPDATE") !== -1 &&
statement.indexOf("SET") === -1) {
errorMessage += " " +
i18n._("Are you missing the SET keyword?");
i18n._("Are you missing the \"SET\" keyword?");
} else if (isSyntaxError &&
statement.search(/[^SUM]\s*\(.*\)\n*\s*\w+/) > -1 ||
statement.search(/\n+\s*SELECT/) > -1 ||
Expand All @@ -146,21 +183,17 @@ window.SQLOutput = Backbone.View.extend({
} else if (isSyntaxError &&
statement.indexOf("INSERT,") > -1 ) {
errorMessage += " " +
i18n._("There shouldn't be a comma after INSERT.");
} else if (errorMessage.indexOf("column types") > -1 &&
i18n._("There shouldn't be a comma after \"INSERT\".");
} else if (colTypesError &&
statement.search(/(\w+\s*,\s*((TEXT)|(INTEGER))+)/) > -1) {
errorMessage += " " +
i18n._("Do you have an extra comma between the name and type?");
} else if (errorMessage.indexOf("column types") > -1 &&
} else if (colTypesError &&
statement.search(/(\w+\s+\w+\s*((TEXT)|(INTEGER)|(REAL))+)/) > -1) {
errorMessage = i18n._("You can't have a space in your column name.");
} else if (errorMessage.indexOf("UNIQUE constraint failed") !== -1) {
} else if (uniqError) {
errorMessage += " " +
i18n._("Are you specifying a different value for each row?");
} else if (errorMessage.indexOf("duplicate column name:") !== -1) {
errorMessage = i18n._("You have multiple columns named `%(name)s` - " +
"column names must be unique.",
{name: errorMessage.split(":")[1].trim()});
}
return errorMessage;
},
Expand Down
Loading

0 comments on commit 9d9260b

Please sign in to comment.