UNPKG

ts-mysql-analyzer

Version:

A MySQL query analyzer.

392 lines 17.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const __1 = require("../"); const ts_mysql_schema_1 = require("ts-mysql-schema"); let schema; beforeAll(async () => { const mySQLSchema = new ts_mysql_schema_1.MySQLSchema({ uri: 'mysql://root@127.0.0.1:3310/test' }); schema = await mySQLSchema.getSchema(); }); describe('MySQLAnalyzer', () => { it('returns diagnostic for empty queries', () => { const analyzer = new __1.MySQLAnalyzer(); const diagnostic = analyzer.analyze(''); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Error, message: 'MySQL query is empty.', start: 0, stop: 0, code: __1.DiagnosticCode.EmptyQuery } ]); }); it('returns diagnostic for lexer errors', () => { const analyzer = new __1.MySQLAnalyzer(); const diagnostic = analyzer.analyze('"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Error, message: 'Unfinished double quoted string literal', start: 0, stop: 1, code: __1.DiagnosticCode.LexerError } ]); }); it('returns diagnostic for parser errors', () => { const analyzer = new __1.MySQLAnalyzer(); const diagnostic = analyzer.analyze('SELE'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Error, message: `Extraneous input "SELE" found, expecting EOF, BEGIN, CACHE, CHECKSUM, COMMIT`, start: 0, stop: 3, code: __1.DiagnosticCode.ParserError } ]); }); it('returns no diagnostics for valid query', () => { const analyzer = new __1.MySQLAnalyzer(); const diagnostics = analyzer.analyze('SELECT * FROM users'); expect(diagnostics).toMatchObject([]); }); it('returns diagnostic for INSERT statements when column count != row count', () => { const analyzer = new __1.MySQLAnalyzer(); const diagnostic = analyzer.analyze('INSERT INTO users (id, status) VALUES ("1")'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Column count does not match row count.', start: 0, stop: 43, code: __1.DiagnosticCode.ColumnRowMismatch } ]); }); it('returns diagnostic for 1 invalid table', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM invalid_table'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: "Table 'invalid_table' does not exist in database 'test'. Did you mean 'posts'?", start: 14, stop: 26, code: __1.DiagnosticCode.MissingTable } ]); }); it('returns multiple diagnostics for multiple invalid tables', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM invalid_table1 INNER JOIN invalid_table2'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: "Table 'invalid_table1' does not exist in database 'test'. Did you mean 'posts'?", start: 14, stop: 27, code: __1.DiagnosticCode.MissingTable }, { severity: __1.DiagnosticSeverity.Warning, message: "Table 'invalid_table2' does not exist in database 'test'. Did you mean 'posts'?", start: 40, stop: 53, code: __1.DiagnosticCode.MissingTable } ]); }); it('returns diagnostic for 1 invalid column', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT invalid_column FROM users'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: "Column 'invalid_column' does not exist in table 'users'. Did you mean 'name'?", start: 7, stop: 20, code: __1.DiagnosticCode.MissingColumn } ]); }); it('returns multiple diagnostics for multiple invalid columns', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT invalid_column1, invalid_column2 FROM users'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: "Column 'invalid_column1' does not exist in table 'users'. Did you mean 'name'?", start: 7, stop: 21, code: __1.DiagnosticCode.MissingColumn }, { severity: __1.DiagnosticSeverity.Warning, message: "Column 'invalid_column2' does not exist in table 'users'. Did you mean 'name'?", start: 24, stop: 38, code: __1.DiagnosticCode.MissingColumn } ]); }); it('returns diagnostic for 1 column in WHERE clause with missing index', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE name = "some-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Suggestion, message: `You can optimize this query by adding a MySQL index for column 'name'.`, start: 26, stop: 29, code: __1.DiagnosticCode.MissingIndex } ]); }); it('returns multiple diagnostics for multiple columns in WHERE clause with missing indices', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE name = "some-string" AND email="some-other-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Suggestion, message: `You can optimize this query by adding a MySQL index for column 'name'.`, start: 26, stop: 29, code: __1.DiagnosticCode.MissingIndex }, { severity: __1.DiagnosticSeverity.Suggestion, message: `You can optimize this query by adding a MySQL index for column 'email'.`, start: 51, stop: 55, code: __1.DiagnosticCode.MissingIndex } ]); }); it('returns multiple diagnostics for multiple invalid assignments', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE id = true AND friends = "some-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type boolean is not assignable to type string.', start: 31, stop: 34, code: __1.DiagnosticCode.TypeMismatch }, { severity: __1.DiagnosticSeverity.Warning, message: 'Type string is not assignable to type number.', start: 50, stop: 62, code: __1.DiagnosticCode.TypeMismatch } ]); }); describe('string assignments', () => { it('string not assignable to number', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE friends = "some-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type string is not assignable to type number.', start: 36, stop: 48, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('string not assignable to boolean', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE enabled = "some-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type string is not assignable to type boolean.', start: 36, stop: 48, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('invalid date string not assignable to date', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE created = "some-string"'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type string is not assignable to type date.', start: 36, stop: 48, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('valid date string assignable to date', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE created = "2020-04-06T14:28:25.774Z"'); expect(diagnostic).toMatchObject([]); }); it('valid string assignment', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE id = "some-string"'); expect(diagnostic).toMatchObject([]); }); }); describe('number assignments', () => { it('number not assignable to string', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE id = 1'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type number is not assignable to type string.', start: 31, stop: 31, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('number not assignable to boolean', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE enabled = 1'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type number is not assignable to type boolean.', start: 36, stop: 36, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('number not assignable to date', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE created = 1'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type number is not assignable to type date.', start: 36, stop: 36, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('valid number assignment', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE friends = 1'); expect(diagnostic).toMatchObject([]); }); }); describe('boolean assignments', () => { it('boolean not assignable to string', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE id = true'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type boolean is not assignable to type string.', start: 31, stop: 34, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('boolean not assignable to number', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE friends = true'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type boolean is not assignable to type number.', start: 36, stop: 39, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('boolean not assignable to date', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE created = true'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type boolean is not assignable to type date.', start: 36, stop: 39, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('valid boolean assignment', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE enabled = true'); expect(diagnostic).toMatchObject([]); }); }); describe('null assignments', () => { it('null not assignable to string', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE id = null'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type null is not assignable to type string.', start: 31, stop: 34, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('null not assignable to number', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE friends = null'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type null is not assignable to type number.', start: 36, stop: 39, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('null not assignable to boolean', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE enabled = null'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type null is not assignable to type boolean.', start: 36, stop: 39, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('null not assignable to date', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE created = null'); expect(diagnostic).toMatchObject([ { severity: __1.DiagnosticSeverity.Warning, message: 'Type null is not assignable to type date.', start: 36, stop: 39, code: __1.DiagnosticCode.TypeMismatch } ]); }); it('valid null assignment', () => { const analyzer = new __1.MySQLAnalyzer({ schema }); const diagnostic = analyzer.analyze('SELECT * FROM users WHERE project = null'); expect(diagnostic).toMatchObject([]); }); }); }); //# sourceMappingURL=index.js.map