Skip to content

Conversation

@loubnaB023
Copy link

This PR fixes #1979 by extending the parser to recognize additional datetime functions and aliases.

Changes:

  1. Updated alasqlparser.jison:

    • Added lexer tokens for NOW, GETDATE, and CURRENT_TIMESTAMP
    • Enhanced PrimitiveValue and FuncValue to support:
      • CURRENT_TIMESTAMP with/without parentheses
      • NOW() and GETDATE() as valid functions
  2. Rebuilt the parser

  3. Added test/test-now.js to verify parsing of:

    • SELECT NOW()
    • SELECT GETDATE()
    • SELECT CURRENT_TIMESTAMP()
    • SELECT CURRENT_TIMESTAMP
    • SELECT CURRENT_DATE
    • SELECT CURDATE()
openSourcePassingTest

@mathiasrw
Copy link
Member

Nice. Very nice.

Please rename the test file to test1979.

Please make sure the test file will verify the output of each query that is now supported.

@mathiasrw
Copy link
Member

I accidentally did a git stash pop and test1979.js test file came up. Im leaving it here to make sure I can pick it up when I dive in again.

if (typeof exports === 'object') {
	var assert = require('assert');
	var alasql = require('..');
}

/*
  Test for issue #1979
*/

var testId = '1979'; // insert test file number

describe('Test ' + testId + ' - date function aliases in the parser', function () {
	it('1a. NOW is a reserved keyword', function () {
		assert.throws(function () {
			alasql('SELECT NOW() AS now');
		});
		assert.throws(function () {
			alasql('SELECT NOW() AS NOW');
		});
		assert.throws(function () {
			alasql('SELECT NOW() AS NOW()');
		});
	});

	it('1b. GETDATE is a reserved keyword', function () {
		assert.throws(function () {
			alasql('SELECT GETDATE() AS GETDATE');
		});
		assert.throws(function () {
			alasql('SELECT GETDATE() AS getdate');
		});
		assert.throws(function () {
			alasql('SELECT GETDATE() AS getdate()');
		});
	});

	it.only('1c. Check parser', function () {
		// If the parser works ok, the date functions are parsed with a funcid instead of columnid
		assert.equal("CURRENT_TIMESTAMP", alasql.parse('SELECT CURRENT_TIMESTAMP').statements[0].columns[0].funcid);
		assert.equal("CURRENT_TIMESTAMP", alasql.parse('SELECT CURRENT_TIMESTAMP()').statements[0].columns[0].funcid);
		assert.equal("CURRENT_TIMESTAMP", alasql.parse('SELECT NOW').statements[0].columns[0].funcid);
		assert.equal("NOW", alasql.parse('SELECT NOW()').statements[0].columns[0].funcid);
		assert.equal("CURRENT_TIMESTAMP", alasql.parse('SELECT GETDATE').statements[0].columns[0].funcid);
		assert.equal("GETDATE", alasql.parse('SELECT GETDATE()').statements[0].columns[0].funcid);
		assert.equal("CURRENT_DATE", alasql.parse('SELECT CURRENT_DATE').statements[0].columns[0].funcid);
		assert.equal("CURRENT_DATE", alasql.parse('SELECT CURRENT_DATE()').statements[0].columns[0].funcid);
		assert.equal("CURRENT_DATE", alasql.parse('SELECT CURDATE').statements[0].columns[0].funcid);
		assert.equal("CURDATE", alasql.parse('SELECT CURDATE()').statements[0].columns[0].funcid);

		assert.equal("SECOND", alasql.parse('SELECT SECOND(NOW())').statements[0].columns[0].funcid);
		assert.equal("HOUR", alasql.parse('SELECT HOUR(NOW())').statements[0].columns[0].funcid);
		assert.equal("MINUTE", alasql.parse('SELECT MINUTE(NOW())').statements[0].columns[0].funcid);
		assert.equal("DAY", alasql.parse('SELECT DAY(NOW())').statements[0].columns[0].funcid);
		assert.equal("DAYOFWEEK", alasql.parse('SELECT DAYOFWEEK(NOW())').statements[0].columns[0].funcid);
		assert.equal("MONTH", alasql.parse('SELECT MONTH(NOW())').statements[0].columns[0].funcid);
		assert.equal("YEAR", alasql.parse('SELECT YEAR(NOW())').statements[0].columns[0].funcid);

		assert.equal("DATE_ADD", alasql.parse('SELECT DATE_ADD(DATE("20081012"), INTERVAL 10 DAY)').statements[0].columns[0].funcid);
		assert.equal("DATE_ADD", alasql.parse('SELECT ADDDATE(DATE("20081012"), INTERVAL 10 DAY)').statements[0].columns[0].funcid);
		assert.equal("DATE_SUB", alasql.parse('SELECT DATE_SUB(DATE("20081012"), INTERVAL 10 DAY)').statements[0].columns[0].funcid);
		assert.equal("DATE_SUB", alasql.parse('SELECT SUBDATE(DATE("20081012"), INTERVAL 10 DAY)').statements[0].columns[0].funcid);
		assert.equal("DATE", alasql.parse('SELECT DATE("20081012")').statements[0].columns[0].funcid);
	});

	it.only('1d. SECOND/HOUR/MINUTE/DAY/DAYOFWEEK/MONTH/YEAR are not reserved keywords', function () {
		assert.doesNotThrow(function () {
			alasql('SELECT SECOND(NOW()) AS SECOND');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT HOUR(NOW()) AS HOUR');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT MINUTE(NOW()) AS MINUTE');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT DAY(NOW()) AS DAY');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT DAYOFWEEK(NOW()) AS DAYOFWEEK');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT DAYOFMONTH(NOW()) AS DAYOFMONTH');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT MONTH(NOW()) AS MONTH');
		});
		assert.doesNotThrow(function () {
			alasql('SELECT YEAR(NOW()) AS YEAR');
		});
		// As literal is fine
		alasql("SELECT SECOND(NOW()) AS 'SECOND'");
		alasql("SELECT HOUR(NOW()) AS 'HOUR'");
		alasql("SELECT MINUTE(NOW()) AS 'MINUTE'");
		alasql("SELECT DAY(NOW()) AS 'DAY'");
		alasql("SELECT DAYOFWEEK(NOW()) AS 'DAYOFWEEK'");
		alasql("SELECT DAYOFMONTH(NOW()) AS 'DAYOFMONTH'");
		alasql("SELECT MONTH(NOW()) AS 'MONTH'");
		alasql("SELECT YEAR(NOW()) AS 'YEAR'");
	});

	it.only('1e. DATE is _not_ a reserved keyword', function () {
		// Should not throw, use of Date is ambigious in AlaSQL and thus _not_ validated in the parser
		// `SELECT DATE(NOW()) AS DATE` -> as column alias
		// `CREATE TABLE one (d Date)` -> as column type
		// `INSERT INTO one VALUES (new Date(2014,6,1))` -> as JS Date object
		alasql('SELECT DATE("20081012") AS date');
		alasql("SELECT DATE('20081012') AS 'date'");
		alasql('SELECT DATE("20081012") AS `date`');
		alasql("SELECT DATE('20081012') AS 'DATE'");
		alasql("CREATE TABLE one (d Date)");
		alasql("INSERT INTO one VALUES (new Date(2014,6,1))");
		assert.equal(114, alasql('SELECT d FROM one')[0].d.getYear());
	});

	it.only('1f. DATE_ADD works with IntervalLiteral', function () {
		// Should not throw
		alasql('SELECT DATE_ADD(NOW(), 10) AS a')

		// Verify it added 10 days to 20081012
		assert.equal(22, alasql('SELECT DATE_ADD(DATE("20081012"), INTERVAL 10 DAY) AS a')[0].a.getDate());
		assert.equal(22, alasql('SELECT ADDDATE(DATE("20081012"), INTERVAL 10 DAY) AS a')[0].a.getDate());

		// Verify it subtracted 10 days from 20081012
		assert.equal(2, alasql('SELECT DATE_SUB(DATE("20081012"), INTERVAL 10 DAY) AS a')[0].a.getDate());
		assert.equal(2, alasql('SELECT SUBDATE(DATE("20081012"), INTERVAL 10 DAY) AS a')[0].a.getDate());

		// Assert DAYOFYEAR
		assert.equal(107, alasql('SELECT SUBDATE(DATE("20080101"), INTERVAL 10 DAYOFYEAR) AS a')[0].a.getYear());

		// Assert that nonexistinginterval throws
		assert.throws(function () {
			alasql('SELECT ADDDATE(DATE("20081012"), INTERVAL 10 nonexistinginterval) AS a');
		});
	});
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add GETDATE, NOW as alias to parser + allow CURRENT_TIMESTAMP with parenthesis

2 participants