From 74abfa517bd6d8b199094a98f36269d90f5ef3ee Mon Sep 17 00:00:00 2001 From: Maxim Zhukov Date: Wed, 21 Apr 2021 02:09:52 -0500 Subject: [PATCH 1/2] Replace the like query where clause with the RegExp --- like.ts | 7 ++++ like_test.ts | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mod_test.ts | 2 +- 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 like.ts create mode 100644 like_test.ts diff --git a/like.ts b/like.ts new file mode 100644 index 0000000..119d6d3 --- /dev/null +++ b/like.ts @@ -0,0 +1,7 @@ +export function getLikeRegExp(input: string): RegExp { + const pattern = input + .replaceAll(".", "\\.") + .replaceAll("%", ".*?"); + + return new RegExp("^" + pattern + "$"); +} diff --git a/like_test.ts b/like_test.ts new file mode 100644 index 0000000..4a5d956 --- /dev/null +++ b/like_test.ts @@ -0,0 +1,91 @@ +import { assert, assertEquals } from "./deps.ts"; +import { getLikeRegExp } from "./like.ts"; + +Deno.test("where name like 'abc.txt'", () => { + const regexp = getLikeRegExp("abc.txt"); + + /* Match */ + assert("abc.txt".match(regexp)); + + /* Does not match */ + assertEquals("a.txt".match(regexp), null); + assertEquals("abc_d.txt".match(regexp), null); + assertEquals("abc.tx".match(regexp), null); +}); + +Deno.test("where name like '%.txt'", () => { + const regexp = getLikeRegExp("%.txt"); + + /* Match */ + assert("abc.txt".match(regexp)); + assert("c.txt".match(regexp)); + assert("ab_c.txt".match(regexp)); + assert("ab_-\/*+ddc.txt".match(regexp)); + + /* Does not match */ + assertEquals("abc.bin".match(regexp), null); + assertEquals(".txn".match(regexp), null); + assertEquals("abc_txt".match(regexp), null); + assertEquals("abc.!txt".match(regexp), null); + assertEquals("abc.txt_bin".match(regexp), null); +}); + +Deno.test("where name like '%.txt%'", () => { + const regexp = getLikeRegExp("%.txt%"); + + /* Match */ + assert("abc.txt".match(regexp)); + assert("c.txt".match(regexp)); + assert("ab_c.txt".match(regexp)); + assert("ab_-\/*+ddc.txt".match(regexp)); + + /* Does not match */ + assertEquals("abc.bin".match(regexp), null); + assertEquals(".txn".match(regexp), null); + assertEquals("abc_txt".match(regexp), null); +}); + +Deno.test("where name like 'ab%txt'", () => { + const regexp = getLikeRegExp("ab%txt"); + + /* Match */ + assert("abc.txt".match(regexp)); + assert("abdef_.txt".match(regexp)); + assert("ab_c.txt".match(regexp)); + assert("ab_-\/*+ddc.txt".match(regexp)); + + /* Does not match */ + assertEquals("abc.bin".match(regexp), null); + assertEquals("abc".match(regexp), null); + assertEquals("d_abc.txt".match(regexp), null); + assertEquals("abc.txt.".match(regexp), null); + assertEquals("abc.txt!".match(regexp), null); +}); + +Deno.test("where name like 'abc.%'", () => { + const regexp = getLikeRegExp("abc.%"); + + /* Match */ + assert("abc.txt".match(regexp)); + assert("abc.bin".match(regexp)); + assert("abc.".match(regexp)); + + /* Does not match */ + assertEquals("abc".match(regexp), null); + assertEquals("d".match(regexp), null); + assertEquals("abc?.".match(regexp), null); +}); + +Deno.test("where name like '%.%'", () => { + const regexp = getLikeRegExp("%.%"); + + /* Match */ + assert("abc.txt".match(regexp)); + assert("abc.bin".match(regexp)); + assert("abc.".match(regexp)); + assert(".".match(regexp)); + assert(".txt".match(regexp)); + + /* Does not match */ + assertEquals("abc".match(regexp), null); +}); diff --git a/mod_test.ts b/mod_test.ts index be424c9..9214a3b 100644 --- a/mod_test.ts +++ b/mod_test.ts @@ -4,7 +4,7 @@ import { fsselect } from "./mod.ts"; Deno.test("if 'select * from .' works", async () => { const result = await fsselect("select * from ."); - assert(result.length === 18); + assert(result.length === 20); }); Deno.test("if 'select * from root' works", async () => { From 941f23078793021922ae99baab8a59f0f66a32b1 Mon Sep 17 00:00:00 2001 From: Maxim Zhukov Date: Wed, 21 Apr 2021 22:34:00 -0500 Subject: [PATCH 2/2] Implement like statement --- README.md | 10 ++------ mod_test.ts | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ where.ts | 7 +++++- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4b7dbea..903d411 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ export interface IDirEntry { ### Operators -The list of supported operators: `>`, `<`, `=`, `<>`. +The list of supported operators: `>`, `<`, `=`, `<>`, `like`. ### Supported @@ -85,10 +85,4 @@ The list of supported operators: `>`, `<`, `=`, `<>`. `select * from root where name = 'root.txt'` -### TODO - -`select * from root where name like '%txt'` - -`select * from root where name like '%txt%'` - -`select * from root where name like 'txt%'` \ No newline at end of file +`select * from root where name like '%.txt'` \ No newline at end of file diff --git a/mod_test.ts b/mod_test.ts index 9214a3b..0c473c0 100644 --- a/mod_test.ts +++ b/mod_test.ts @@ -147,4 +147,76 @@ Deno.test("if select * from root where name <> 'root.txt' works", async () => { "test_folder_with_folder", ]; assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like 'test_%' works", async () => { + const result = await fsselect("select * from root where name like 'test_%'"); + assert(result.length === 3); + + const names = result.map((i) => i.name as string); + const expectedNames = [ + "test_folder_with_file", + "test_folder_with_files", + "test_folder_with_folder", + ]; + assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like '%folder%' works", async () => { + const result = await fsselect("select * from root where name like '%folder%'"); + assert(result.length === 3); + + const names = result.map((i) => i.name as string); + const expectedNames = [ + "test_folder_with_file", + "test_folder_with_files", + "test_folder_with_folder", + ]; + assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like '%.txt' works", async () => { + const result = await fsselect("select * from root where name like '%.txt'"); + assert(result.length === 1); + + const names = result.map((i) => i.name as string); + const expectedNames = [ + "root.txt" + ]; + assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like '%with_file%' works", async () => { + const result = await fsselect("select * from root where name like '%with_file%'"); + assert(result.length === 2); + + const names = result.map((i) => i.name as string); + const expectedNames = [ + "test_folder_with_file", + "test_folder_with_files", + ]; + assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like 'some' does not return entries", async () => { + const result = await fsselect("select * from root where name like 'some'"); + assert(result.length === 0); + + const names = result.map((i) => i.name as string); + const expectedNames: string[] = []; + assertArrayIncludes(names, expectedNames); +}); + +Deno.test("if select * from root where name like '%%' works", async () => { + const result = await fsselect("select * from root where name like '%%'"); + assert(result.length === 4); + + const names = result.map((i) => i.name as string); + const expectedNames = [ + "test_folder_with_file", + "test_folder_with_files", + "test_folder_with_folder", + "root.txt" + ]; + assertArrayIncludes(names, expectedNames); }); \ No newline at end of file diff --git a/where.ts b/where.ts index 0223fb0..d0e6c24 100644 --- a/where.ts +++ b/where.ts @@ -1,3 +1,4 @@ +import { getLikeRegExp } from "./like.ts"; import { IDirEntry, IWhereClause, IWhereCondition } from "./types.ts"; export function where(entry: IDirEntry, where: IWhereClause | null): boolean { @@ -75,7 +76,7 @@ function meet(entry: IDirEntry, condition: IWhereCondition): boolean { "LessThan": null, "Equal": equalString, "Different": differentString, - "Like": null, + "Like": likeString, }; const operation = operations[op]; @@ -125,3 +126,7 @@ function equalString(left: string | undefined, right: string): boolean { function differentString(left: string | undefined, right: string): boolean { return typeof left !== "undefined" && left !== right; } + +function likeString(left: string | undefined, right: string): boolean { + return typeof left !== "undefined" && left.match( getLikeRegExp(right) ) != null; +} \ No newline at end of file