import {SQLishParser} from 'sentry/views/starfish/utils/sqlish/SQLishParser';

describe('SQLishParser', function () {
  describe('SQLishParser()', () => {
    const parser = new SQLishParser();

    it.each([
      'SELECT;',
      'SELECT hello;',
      'SELECT *;', // Wildcards
      'WHERE age = 10;', // Equality
      'WHERE age != 10;', // Inequality
      'total / time', // Division
      'sum(age)::numeric(0, 5)', // Type casting
      'WHERE age > 10 AND age < 20;', // Comparison
      "WHERE$1 ILIKE ' % ' || 'text'", // Conditionals
      'SELECT id, name;', // Column lists
      'columns AS `tags[column]`', // ClickHouse backtics
      'SELECT * FROM #temp', // Temporary tables
      '# Fetches', // Comments
      '\r\n', // Windows newlines
      '✌🏻', // Emoji
      'ă', // Unicode
      'SELECT id, nam*', // Truncation
      'AND created >= :c1', // PHP-Style I
      'LIMIT $2', // PHP-style II
      'created >= %s', // Python-style
      'created >= $1', // Rails-style
      '@@ to_tsquery', // Postgres full-text search
      'flags & %s)', // Bitwise AND
      'flags | %s)', // Bitwise OR
      'flags ^ %s)', // Bitwise XOR
      'flags ~ %s)', // Bitwise NOT
      'FROM temp{%s}', // Relay integer stripping
      '+ %s as count', // Arithmetic I
      '- %s as count', // Arithmetic II
      "ILIKE '\\_')", // Backslash
    ])('Parses %s', sql => {
      expect(() => {
        parser.parse(sql);
      }).not.toThrow();
    });
  });

  describe('SQLishParser.parse', () => {
    const parser = new SQLishParser();

    it('Distinguishes between real keywords and interpolated words', () => {
      expect(parser.parse('SELECT country')).toEqual([
        {
          type: 'Keyword',
          content: 'SELECT',
        },
        {
          type: 'Whitespace',
          content: ' ',
        },
        {
          type: 'GenericToken',
          content: 'country',
        },
      ]);

      expect(parser.parse('SELECT discount')).toEqual([
        {
          type: 'Keyword',
          content: 'SELECT',
        },
        {
          type: 'Whitespace',
          content: ' ',
        },
        {
          type: 'GenericToken',
          content: 'discount',
        },
      ]);
    });

    it('Detects collapsed columns', () => {
      expect(parser.parse('select ..')).toEqual([
        {
          type: 'Keyword',
          content: 'SELECT',
        },
        {
          type: 'Whitespace',
          content: ' ',
        },
        {
          type: 'CollapsedColumns',
          content: '..',
        },
      ]);
    });

    it('Detects whitespace between generic tokens and JOIN commands', () => {
      expect(parser.parse('sentry_users INNER JOIN sentry_messages')).toEqual([
        {
          type: 'GenericToken',
          content: 'sentry_users',
        },
        {type: 'Whitespace', content: ' '},
        {type: 'Keyword', content: 'INNER'},
        {type: 'Whitespace', content: ' '},
        {type: 'Keyword', content: 'JOIN'},
        {type: 'Whitespace', content: ' '},
        {
          type: 'GenericToken',
          content: 'sentry_messages',
        },
      ]);
    });
  });
});