aboutsummaryrefslogtreecommitdiff
path: root/db/db.ts
blob: 7bb315c977b50e36ad9e7a837e4d71bdf493c968 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { Database, Statement } from "https://deno.land/x/sqlite3@0.9.1/mod.ts";
import * as path from 'https://deno.land/std@0.102.0/path/mod.ts';

import { TokenTags } from "../search/tags.ts";
import "../util/string.ts";

export interface DBDictInfo {
	id: number;
	name: string;
	language: string;
	priority: number;
};

export interface FindResult {
	id: number;
	expression: string;
	reading: string;
	tags: TokenTags;
	sort: number;
	depth: number;
	original: string;
	match: {
		writing: boolean;
		reading: boolean;
	};
}

interface DBFindResult {
	id: number;
	expression: string;
	reading: string;
	tags: string;
  rules: string;
	depth: number;
	original: string;
	deinflected: string;
	root_overlay: number;
	user_overlay: number;
}

/**
 * @summary dictionary database connection, handles deconjugation and lookup in SQL
 *
 * @example
 * const db = new DB();
 * await db.prepare();
 * const results = db.findTerm("なった");
 */
export default class DB {
	private connection: Database;
	public ready: Promise<void>;
  private here = path.dirname(path.fromFileUrl(import.meta.url));
	private paths = {
		db: {
			dict: path.resolve(this.here, 'dict.db'),
			user: path.resolve(this.here, 'user.db'),
		},
		query: {
			find: path.resolve(this.here, 'find.sql'),
		},
	} as const;
	private statement: {
		attach: Statement;
		queryTerm: Statement;
	};

	constructor() {
		this.connection = new Database(":memory:", { create: false });
		this.statement = {
			attach: this.connection.prepare("attach database ? as ?"),
			queryTerm: this.connection.prepare(""),
		};
		this.attach(this.paths.db.dict, 'dict');
		this.attach(this.paths.db.user, 'user');
		this.ready = new Promise<void>(async resolve => {
			const statement = await Deno.readTextFile(this.paths.query.find);
			this.statement.queryTerm = this.connection.prepare(statement);
			resolve();
		});
	}
	
	private attach(dbPath: string, alias?: string) {
		this.statement.attach.run(dbPath, alias);
	}

	async findTerm(term: string): Promise<FindResult[]> {
		await this.ready;
		var results = this.statement.queryTerm.all({ term }) as unknown as DBFindResult[];
		var terms: FindResult[] = results?.map(term => {
			if (term.rules == null) term.rules = "";
			return {
				id: term.id,
				expression: term.expression,
				reading: term.reading,
				tags: (term.tags + ' ' + term.rules).parseTags(),
				sort: term.user_overlay ?? term.root_overlay ?? 100,
				depth: term.depth,
				original: term.original,
				match: {
					writing: term.expression == term.deinflected,
					reading: term.reading == term.deinflected,
				},
			};
		});
		return terms;
	}
};