const { transformQuery } = require('../dist/src/generated-parser.js') describe('Query Transformation', () => { test('missing:body', () => { const input = 'missing:body' const expectedOutput = "COALESCE(lower(event->>'body'), '') IS NULL" expect(transformQuery(input)).toBe(expectedOutput) }) test('has:body', () => { const input = 'has:body' const expectedOutput = "COALESCE(lower(event->>'body'), '') IS NOT NULL" expect(transformQuery(input)).toBe(expectedOutput) }) test("has:resource['service.name']", () => { const input = "has:resource['service.name']" const expectedOutput = "COALESCE(lower(event->'resource'->>'service.name'), '') IS NOT NULL" expect(transformQuery(input)).toBe(expectedOutput) }) test("has:resource['service.name'].foo", () => { const input = "has:resource['service.name'].foo" const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->>'foo'), '') IS NOT NULL" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo:bar', () => { const input = 'foo:bar' const expectedOutput = "COALESCE(lower(event->>'foo'), '') ILIKE lower('%bar%')" expect(transformQuery(input)).toBe(expectedOutput) }) test("foo:'bar'", () => { const input = "foo:'bar'" const expectedOutput = "COALESCE(lower(event->>'foo'), '') = lower('bar')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo:"bar"', () => { const input = 'foo:"bar"' const expectedOutput = "COALESCE(lower(event->>'foo'), '') = lower('bar')" expect(transformQuery(input)).toBe(expectedOutput) }) describe('complex keys', () => { test('attributes.username:greg', () => { const input = `attributes.username:greg` const expectedOutput = "COALESCE(lower(event->'attributes'->>'username'), '') ILIKE lower('%greg%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo_bar:zoo', () => { const input = `foo_bar:zoo` const expectedOutput = "COALESCE(lower(event->>'foo_bar'), '') ILIKE lower('%zoo%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo.bar.zoo:car', () => { const input = `foo.bar.zoo:car` const expectedOutput = "COALESCE(lower(event->'foo'->'bar'->>'zoo'), '') ILIKE lower('%car%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo.bar.zoo.car:far', () => { const input = `foo.bar.zoo.car:far` const expectedOutput = "COALESCE(lower(event->'foo'->'bar'->'zoo'->>'car'), '') ILIKE lower('%far%')" expect(transformQuery(input)).toBe(expectedOutput) }) }) describe('bracket notation', () => { test('resource[servicename]:cartservice', () => { const input = `resource[servicename]:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->>'servicename'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[service.name]:cartservice', () => { const input = `resource[service.name]:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->>'service.name'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test("resource['service.name']:cartservice", () => { const input = `resource['service.name']:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->>'service.name'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test("resource['service.name'].foo:cartservice", () => { const input = `resource['service.name'].foo:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->>'foo'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[service.name].foo:cartservice', () => { const input = `resource[service.name].foo:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->>'foo'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) // test('resource[service.name.foo]:cartservice', () => { // const input = `resource[service.name.foo]:cartservice` // const expectedOutput = "COALESCE(lower(event->'resource'->>'service.name.foo'), '') ILIKE lower('%cartservice%')" // expect(transformQuery(input)).toBe(expectedOutput) // }) test('resource[service.name][foo.bar]:zoo', () => { const input = `resource[service.name][foo.bar]:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->>'foo.bar'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[service.name][foo.bar][car]:zoo', () => { const input = `resource[service.name][foo.bar][car]:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->'foo.bar'->>'car'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[service.name][foo.bar][car].war:zoo', () => { const input = `resource[service.name][foo.bar][car].war:cartservice` const expectedOutput = "COALESCE(lower(event->'resource'->'service.name'->'foo.bar'->'car'->>'war'), '') ILIKE lower('%cartservice%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[aws.ecs.task.arn] with exact match', () => { const input = `resource[aws.ecs.task.arn]:"arn:aws:ecs:us-east-2:075279486443:task/RulaOrange-cluster/358581120efd413f8f40a9f33b8066f0"` const expectedOutput = "COALESCE(lower(event->'resource'->>'aws.ecs.task.arn'), '') = lower('arn:aws:ecs:us-east-2:075279486443:task/RulaOrange-cluster/358581120efd413f8f40a9f33b8066f0')" expect(transformQuery(input)).toBe(expectedOutput) }) test('resource[aws.ecs.task.arn] with partial match', () => { const input = `resource[aws.ecs.task.arn]:RulaOrange-cluster` const expectedOutput = "COALESCE(lower(event->'resource'->>'aws.ecs.task.arn'), '') ILIKE lower('%RulaOrange-cluster%')" expect(transformQuery(input)).toBe(expectedOutput) }) }) test('a:1', () => { const input = 'a:1' const expectedOutput = "(COALESCE(lower(event->>'a'), ''))::int = 1" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:b c:d', () => { const input = 'a:b c:d' const expectedOutput = "COALESCE(lower(event->>'a'), '') ILIKE lower('%b%') AND COALESCE(lower(event->>'c'), '') ILIKE lower('%d%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:b OR c:d', () => { const input = 'a:b OR c:d' const expectedOutput = "COALESCE(lower(event->>'a'), '') ILIKE lower('%b%') OR COALESCE(lower(event->>'c'), '') ILIKE lower('%d%')" expect(transformQuery(input)).toBe(expectedOutput) }) describe('wildcard', () => { test('a:*b', () => { const input = 'a:*b' const expectedOutput = "COALESCE(lower(event->>'a'), '') ILIKE lower('%b')" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:b*', () => { const input = 'a:b*' const expectedOutput = "COALESCE(lower(event->>'a'), '') ILIKE lower('b%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:*b*', () => { const input = 'a:*b*' const expectedOutput = "COALESCE(lower(event->>'a'), '') ILIKE lower('%b%')" expect(transformQuery(input)).toBe(expectedOutput) }) }) describe('exclusion', () => { test('-a:b', () => { const input = '-a:b' const expectedOutput = "COALESCE(lower(event->>'a'), '') NOT ILIKE lower('%b%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('-a:1', () => { const input = '-a:1' const expectedOutput = "(COALESCE(lower(event->>'a'), ''))::int != 1" expect(transformQuery(input)).toBe(expectedOutput) }) }) describe('groups', () => { test('-resource[service.name]:"CrystalBlue-firehose" AND -resource[service.name]:"CrystalBlue-processor"', () => { const input = '-resource[service.name]:"CrystalBlue-firehose" AND -resource[service.name]:"CrystalBlue-processor"' const expectedOutput = "COALESCE(lower(event->'resource'->>'service.name'), '') != lower('CrystalBlue-firehose') AND COALESCE(lower(event->'resource'->>'service.name'), '') != lower('CrystalBlue-processor')" expect(transformQuery(input)).toBe(expectedOutput) }) test('(-resource[service.name]:"CrystalBlue-firehose" AND -resource[service.name]:"CrystalBlue-processor")', () => { const input = '(-resource[service.name]:"CrystalBlue-firehose" AND -resource[service.name]:"CrystalBlue-processor")' const expectedOutput = "(COALESCE(lower(event->'resource'->>'service.name'), '') != lower('CrystalBlue-firehose') AND COALESCE(lower(event->'resource'->>'service.name'), '') != lower('CrystalBlue-processor'))" expect(transformQuery(input)).toBe(expectedOutput) }) }) test('a:(b OR c)', () => { const input = 'a:(b OR c)' const expectedOutput = "(COALESCE(lower(event->>'a'), '') ILIKE lower('%b%') OR COALESCE(lower(event->>'a'), '') ILIKE lower('%c%'))" expect(transformQuery(input)).toBe(expectedOutput) }) test("a:('b' OR 'c')", () => { const input = `a:('b' OR 'c')` const expectedOutput = "(COALESCE(lower(event->>'a'), '') = lower('b') OR COALESCE(lower(event->>'a'), '') = lower('c'))" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:(1 OR c)', () => { const input = 'a:(1 OR c)' const expectedOutput = "((COALESCE(lower(event->>'a'), ''))::int = 1 OR COALESCE(lower(event->>'a'), '') ILIKE lower('%c%'))" expect(transformQuery(input)).toBe(expectedOutput) }) test('a:(bc* OR d)', () => { const input = 'a:(bc* OR d)' const expectedOutput = "(COALESCE(lower(event->>'a'), '') ILIKE lower('bc%') OR COALESCE(lower(event->>'a'), '') ILIKE lower('%d%'))" expect(transformQuery(input)).toBe(expectedOutput) }) // test('Combination of OR and date range', () => { // const input = `a:(b OR c) AND date:["2019-02-20" TO "2019-02-25"]`; // const expectedOutput = "(event->>'a' = 'b' OR event->>'a' = 'c') AND event->>'date' BETWEEN '2019-02-20' AND '2019-02-25'"; // expect(transformQuery(input)).toBe(expectedOutput); // }); test('a:(b OR NOT c)', () => { const input = 'a:(b OR NOT c)' const expectedOutput = "(COALESCE(lower(event->>'a'), '') ILIKE lower('%b%') OR COALESCE(lower(event->>'a'), '') NOT ILIKE lower('%c%'))" expect(transformQuery(input)).toBe(expectedOutput) }) test("a:'foo bar'", () => { const input = "a:'foo bar'" const expectedOutput = "COALESCE(lower(event->>'a'), '') = lower('foo bar')" expect(transformQuery(input)).toBe(expectedOutput) }) describe('support weird characters', () => { const characters = ['+', '-', '&', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':'] characters.forEach((c) => { test(c, () => { const input = `a:'\\${c}'` const expectedOutput = `COALESCE(lower(event->>'a'), '') = lower('${c}')` expect(transformQuery(input)).toBe(expectedOutput) }) }) }) describe('fuzzy search', () => { test('foo', () => { const input = 'foo' const expectedOutput = "event::text ILIKE '%foo%'" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo bar', () => { const input = 'foo bar' const expectedOutput = "event::text ILIKE '%foo%' AND event::text ILIKE '%bar%'" expect(transformQuery(input)).toBe(expectedOutput) }) test('"foo bar"', () => { const input = '"foo bar"' const expectedOutput = "event::text ILIKE '%foo bar%'" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo a:b', () => { const input = 'foo a:b' const expectedOutput = "event::text ILIKE '%foo%' AND COALESCE(lower(event->>'a'), '') ILIKE lower('%b%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo OR a:b', () => { const input = 'foo OR a:b' const expectedOutput = "event::text ILIKE '%foo%' OR COALESCE(lower(event->>'a'), '') ILIKE lower('%b%')" expect(transformQuery(input)).toBe(expectedOutput) }) test('foo AND a:b', () => { const input = 'foo AND a:b' const expectedOutput = "event::text ILIKE '%foo%' AND COALESCE(lower(event->>'a'), '') ILIKE lower('%b%')" expect(transformQuery(input)).toBe(expectedOutput) }) }) // test.only('Date range ending at a specific date', () => { // const input = `date:[* TO "2019-02-25"]`; // const expectedOutput = "event->>'date' <= '2019-02-25'"; // expect(transformQuery(input)).toBe(expectedOutput); // }); // test('Date range starting at a specific date', () => { // const input = `date:["2019-02-25" TO *]`; // const expectedOutput = "event->>'date' >= '2019-02-25'"; // expect(transformQuery(input)).toBe(expectedOutput); // }); // test('Exclusive date range', () => { // const input = `date:{"2019-02-20" TO "2019-02-25"}`; // const expectedOutput = "event->>'date' > '2019-02-20' AND event->>'date' < '2019-02-25'"; // expect(transformQuery(input)).toBe(expectedOutput); // }); })