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
108
109
|
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 = new Database(":memory:", { create: false });
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: this.connection.prepare("attach database ? as ?"),
queryTerm: this.connection.prepare(""),
termPriority: this.connection.prepare(""),
} satisfies { [name: string]: Statement };
constructor() {
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);
this.statement.termPriority = this.connection.prepare("insert into sort_overlay (user_id, expression, reading, sort) values (?, ?, ?, ?)");
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;
}
async termPriority(userID: number, expression: string, reading: string, priority: number) {
await this.ready;
this.statement.termPriority.run(userID, expression, reading, priority);
}
};
|