feature: initial commit
This commit is contained in:
commit
ce024ba87a
17 changed files with 1141 additions and 0 deletions
13
tests/01_module_import.test.ts
Normal file
13
tests/01_module_import.test.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import * as asserts from '@std/assert';
|
||||
|
||||
Deno.test({
|
||||
name: 'import fsdb',
|
||||
permissions: {
|
||||
env: true
|
||||
},
|
||||
fn: async () => {
|
||||
const fsdb = await import('../fsdb.ts');
|
||||
|
||||
asserts.assert(fsdb);
|
||||
}
|
||||
});
|
39
tests/02_store_and_retrieve_an_item.test.ts
Normal file
39
tests/02_store_and_retrieve_an_item.test.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import * as asserts from '@std/assert';
|
||||
import * as fsdb from '../fsdb.ts';
|
||||
import { get_data_dir } from './helpers.ts';
|
||||
|
||||
Deno.test({
|
||||
name: 'store and retrieve an item',
|
||||
permissions: {
|
||||
env: true,
|
||||
read: ['./'],
|
||||
write: ['./data']
|
||||
},
|
||||
fn: async () => {
|
||||
type ITEM = {
|
||||
id: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
const items: fsdb.FSDB_COLLECTION<ITEM> = new fsdb.FSDB_COLLECTION<ITEM>({
|
||||
name: 'test-02-items',
|
||||
root: get_data_dir() + '/test-02-items'
|
||||
});
|
||||
|
||||
asserts.assert(items);
|
||||
|
||||
const item = {
|
||||
id: 'blah-fish-test-with-cozy-home-down-here-yall-work',
|
||||
value: 'the blah fish test, of course'
|
||||
};
|
||||
|
||||
const stored_item = await items.create(item);
|
||||
|
||||
asserts.assertObjectMatch(stored_item, item);
|
||||
|
||||
const fetched_item = await items.get(item.id);
|
||||
|
||||
asserts.assert(fetched_item);
|
||||
asserts.assertObjectMatch(fetched_item, stored_item);
|
||||
}
|
||||
});
|
88
tests/03_index_items.test.ts
Normal file
88
tests/03_index_items.test.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import * as asserts from '@std/assert';
|
||||
import * as fsdb from '../fsdb.ts';
|
||||
import { FSDB_INDEXER_SYMLINKS } from '../indexers/symlinks.ts';
|
||||
import { get_data_dir, random_email_address, random_phone_number } from './helpers.ts';
|
||||
import lurid from '@andyburke/lurid';
|
||||
import by_email from '../organizers/by_email.ts';
|
||||
import by_character from '../organizers/by_character.ts';
|
||||
import by_phone from '../organizers/by_phone.ts';
|
||||
import { sentence } from 'jsr:@ndaidong/txtgen';
|
||||
|
||||
Deno.test({
|
||||
name: 'index some items',
|
||||
permissions: {
|
||||
env: true,
|
||||
|
||||
// https://github.com/denoland/deno/discussions/17258
|
||||
read: true,
|
||||
write: true
|
||||
},
|
||||
fn: async () => {
|
||||
type ITEM = {
|
||||
id: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
const item_collection: fsdb.FSDB_COLLECTION<ITEM> = new fsdb.FSDB_COLLECTION<ITEM>({
|
||||
name: 'test-03-items',
|
||||
root: get_data_dir() + '/test-03-items',
|
||||
indexers: {
|
||||
email: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'email',
|
||||
field: 'email',
|
||||
organize: by_email
|
||||
}),
|
||||
phone: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'phone',
|
||||
field: 'phone',
|
||||
organize: by_phone
|
||||
}),
|
||||
by_character_test: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'by_character_test',
|
||||
organize: by_character,
|
||||
get_values_to_index: (item: ITEM) => item.value.split(/\W/).filter((word) => word.length > 3),
|
||||
to_many: true
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
asserts.assert(item_collection);
|
||||
|
||||
const items: ITEM[] = [];
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
const item = {
|
||||
id: lurid(),
|
||||
email: random_email_address(),
|
||||
phone: random_phone_number(),
|
||||
value: sentence()
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
|
||||
const stored_item: ITEM = await item_collection.create(item);
|
||||
|
||||
asserts.assertObjectMatch(stored_item, item);
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
const fetched_by_email: ITEM[] = await item_collection.find({ email: item.email });
|
||||
asserts.assertLess(fetched_by_email.length, items.length);
|
||||
asserts.assertGreater(fetched_by_email.length, 0);
|
||||
asserts.assert(fetched_by_email.find((email_item) => email_item.id === item.id));
|
||||
|
||||
const fetched_by_phone: ITEM[] = await item_collection.find({ phone: item.phone });
|
||||
asserts.assertLess(fetched_by_phone.length, items.length);
|
||||
asserts.assertGreater(fetched_by_phone.length, 0);
|
||||
asserts.assert(fetched_by_phone.find((phone_item) => phone_item.id === item.id));
|
||||
|
||||
const words_in_value: string[] = item.value.split(/\W/).filter((word) => word.length > 3);
|
||||
const random_word_in_value: string = words_in_value[Math.floor(Math.random() * words_in_value.length)];
|
||||
const fetched_by_word_in_value: ITEM[] = await item_collection.find({ by_character_test: random_word_in_value });
|
||||
asserts.assertLess(fetched_by_word_in_value.length, items.length);
|
||||
asserts.assertGreater(fetched_by_word_in_value.length, 0);
|
||||
asserts.assert(fetched_by_word_in_value.find((word_in_value_item) => word_in_value_item.id === item.id));
|
||||
}
|
||||
}
|
||||
});
|
104
tests/04_indexing_sanity_checks.test.ts
Normal file
104
tests/04_indexing_sanity_checks.test.ts
Normal file
|
@ -0,0 +1,104 @@
|
|||
import * as asserts from '@std/assert';
|
||||
import * as fsdb from '../fsdb.ts';
|
||||
import { FSDB_INDEXER_SYMLINKS } from '../indexers/symlinks.ts';
|
||||
import { get_data_dir, random_email_address, random_phone_number } from './helpers.ts';
|
||||
import lurid from '@andyburke/lurid';
|
||||
import by_email from '../organizers/by_email.ts';
|
||||
import by_character from '../organizers/by_character.ts';
|
||||
import by_phone from '../organizers/by_phone.ts';
|
||||
import { sentence } from 'jsr:@ndaidong/txtgen';
|
||||
|
||||
Deno.test({
|
||||
name: 'index some items',
|
||||
permissions: {
|
||||
env: true,
|
||||
|
||||
// https://github.com/denoland/deno/discussions/17258
|
||||
read: true,
|
||||
write: true
|
||||
},
|
||||
fn: async () => {
|
||||
type ITEM = {
|
||||
id: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
const item_collection: fsdb.FSDB_COLLECTION<ITEM> = new fsdb.FSDB_COLLECTION<ITEM>({
|
||||
name: 'test-04-items',
|
||||
root: get_data_dir() + '/test-04-items',
|
||||
indexers: {
|
||||
email: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'email',
|
||||
field: 'email',
|
||||
organize: by_email
|
||||
}),
|
||||
phone: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'phone',
|
||||
field: 'phone',
|
||||
organize: by_phone
|
||||
}),
|
||||
by_character_test: new FSDB_INDEXER_SYMLINKS<ITEM>({
|
||||
name: 'by_character_test',
|
||||
organize: by_character,
|
||||
get_values_to_index: (item: ITEM) => item.value.split(/\W/).filter((word) => word.length > 3),
|
||||
to_many: true
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
asserts.assert(item_collection);
|
||||
|
||||
const items: ITEM[] = [];
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
const item = {
|
||||
id: lurid(),
|
||||
email: random_email_address(),
|
||||
phone: random_phone_number(),
|
||||
value: sentence()
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
|
||||
const stored_item: ITEM = await item_collection.create(item);
|
||||
|
||||
asserts.assertObjectMatch(stored_item, item);
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
const fetched_by_email: ITEM[] = await item_collection.find({ email: item.email });
|
||||
asserts.assertLess(fetched_by_email.length, items.length);
|
||||
asserts.assertGreater(fetched_by_email.length, 0);
|
||||
asserts.assert(fetched_by_email.find((email_item) => email_item.id === item.id));
|
||||
|
||||
const fetched_by_phone: ITEM[] = await item_collection.find({ phone: item.phone });
|
||||
asserts.assertLess(fetched_by_phone.length, items.length);
|
||||
asserts.assertGreater(fetched_by_phone.length, 0);
|
||||
asserts.assert(fetched_by_phone.find((phone_item) => phone_item.id === item.id));
|
||||
|
||||
const words_in_value: string[] = item.value.split(/\W/).filter((word) => word.length > 3);
|
||||
const random_word_in_value: string = words_in_value[Math.floor(Math.random() * words_in_value.length)];
|
||||
const fetched_by_word_in_value: ITEM[] = await item_collection.find({ by_character_test: random_word_in_value });
|
||||
asserts.assertLess(fetched_by_word_in_value.length, items.length);
|
||||
asserts.assertGreater(fetched_by_word_in_value.length, 0);
|
||||
asserts.assert(fetched_by_word_in_value.find((word_in_value_item) => word_in_value_item.id === item.id));
|
||||
}
|
||||
|
||||
// leave one item behind so the whole db for this test doesn't get cleaned up so I can hand-review it
|
||||
for (const item of items.slice(1)) {
|
||||
await item_collection.delete(item);
|
||||
|
||||
const fetched_by_email: ITEM[] = await item_collection.find({ email: item.email });
|
||||
asserts.assertFalse(fetched_by_email.find((email_item) => email_item.id === item.id));
|
||||
|
||||
const fetched_by_phone: ITEM[] = await item_collection.find({ phone: item.phone });
|
||||
asserts.assertFalse(fetched_by_phone.find((phone_item) => phone_item.id === item.id));
|
||||
|
||||
const words_in_value: string[] = item.value.split(/\W/).filter((word) => word.length > 3);
|
||||
const random_word_in_value: string = words_in_value[Math.floor(Math.random() * words_in_value.length)];
|
||||
const fetched_by_word_in_value: ITEM[] = await item_collection.find({ by_character_test: random_word_in_value });
|
||||
asserts.assertFalse(fetched_by_word_in_value.find((word_in_value_item) => word_in_value_item.id === item.id));
|
||||
}
|
||||
}
|
||||
});
|
53
tests/helpers.ts
Normal file
53
tests/helpers.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import lurid from '@andyburke/lurid';
|
||||
import { convert_to_words } from '@andyburke/lurid/word_bytes';
|
||||
|
||||
const TLDs: string[] = [
|
||||
'com',
|
||||
'org',
|
||||
'net',
|
||||
'edu',
|
||||
'gov',
|
||||
'nexus',
|
||||
'shop',
|
||||
'unreasonablylongtldname'
|
||||
];
|
||||
|
||||
const random_byte_buffer: Uint8Array = new Uint8Array(3);
|
||||
export function random_email_address(): string {
|
||||
crypto.getRandomValues(random_byte_buffer);
|
||||
const name = convert_to_words(random_byte_buffer).join('-');
|
||||
|
||||
crypto.getRandomValues(random_byte_buffer);
|
||||
const domain = convert_to_words(random_byte_buffer).join('-');
|
||||
|
||||
const tld = TLDs[Math.floor(Math.random() * TLDs.length)];
|
||||
return `${name}@${domain}.${tld}`;
|
||||
}
|
||||
|
||||
export function random_username(): string {
|
||||
crypto.getRandomValues(random_byte_buffer);
|
||||
return convert_to_words(random_byte_buffer).join('-');
|
||||
}
|
||||
|
||||
function get_a_random_array_element(values: any[]): any {
|
||||
return values[Math.floor(Math.random() * values.length)];
|
||||
}
|
||||
|
||||
const country_codes: string[] = ['', '+1', '1', '01', '219', '40', '506', '999'];
|
||||
const digits: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
const joinings: string[] = [' ', '-', '.'];
|
||||
export function random_phone_number(): string {
|
||||
const country_code = get_a_random_array_element(country_codes);
|
||||
const area_code = [0, 0, 0].map((_) => get_a_random_array_element(digits)).join('');
|
||||
const central_office_code = [0, 0, 0].map((_) => get_a_random_array_element(digits)).join('');
|
||||
const subscriber_code = [0, 0, 0, 0].map((_) => get_a_random_array_element(digits)).join('');
|
||||
|
||||
return `${country_code}${country_code ? get_a_random_array_element(joinings) : ''}${area_code}${
|
||||
get_a_random_array_element(joinings)
|
||||
}${central_office_code}${get_a_random_array_element(joinings)}${subscriber_code}`;
|
||||
}
|
||||
|
||||
const DATA_DIR = lurid();
|
||||
export function get_data_dir(): string {
|
||||
return Deno.env.get('TEST_DATA_STORAGE_ROOT') ?? DATA_DIR;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue