This commit is contained in:
polwex 2024-10-20 19:51:30 +07:00
parent 91e03ffb10
commit 22ee15654f
13 changed files with 407 additions and 1 deletions

10
README.md Normal file
View File

@ -0,0 +1,10 @@
# 範疇
## Category learning
### TODO
Use SCOWL project for English
categorize every word!!
important: Frequency

Binary file not shown.

BIN
data/data.db-shm Normal file

Binary file not shown.

0
data/data.db-wal Normal file
View File

View File

@ -1,5 +1,9 @@
-- Enable foreign key support -- Enable foreign key support
PRAGMA foreign_keys = ON; PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL;
PRAGMA cache_size = -2000;
PRAGMA mmap_size = 30000000000;
-- Words table -- Words table
CREATE TABLE words ( CREATE TABLE words (
@ -7,8 +11,12 @@ CREATE TABLE words (
spelling TEXT NOT NULL, spelling TEXT NOT NULL,
ipa TEXT NOT NULL, ipa TEXT NOT NULL,
language_id INTEGER NOT NULL, language_id INTEGER NOT NULL,
frequency INTEGER,
FOREIGN KEY (language_id) REFERENCES languages(id) FOREIGN KEY (language_id) REFERENCES languages(id)
); );
CREATE INDEX idx_words_spelling ON words(spelling);
CREATE INDEX idx_words_language_id ON words(language_id);
-- Languages table -- Languages table
CREATE TABLE languages ( CREATE TABLE languages (
@ -29,14 +37,18 @@ CREATE TABLE categories (
part_of_speech_id INTEGER NOT NULL, part_of_speech_id INTEGER NOT NULL,
FOREIGN KEY (part_of_speech_id) REFERENCES parts_of_speech(id) FOREIGN KEY (part_of_speech_id) REFERENCES parts_of_speech(id)
); );
CREATE INDEX idx_categories_name ON categories(name);
CREATE INDEX idx_categories_part_of_speech_id ON categories(part_of_speech_id);
-- Word Categories junction table -- Word Categories junction table
CREATE TABLE word_categories ( CREATE TABLE word_categories (
word_id INTEGER NOT NULL, word_id INTEGER NOT NULL,
category_id INTEGER NOT NULL, category_id INTEGER NOT NULL,
PRIMARY KEY (word_id, category_id), PRIMARY KEY (word_id, category_id),
FOREIGN KEY (word_id) REFERENCES words(id) FOREIGN KEY (word_id) REFERENCES words(id),
FOREIGN KEY (category_id) REFERENCES categories(id)
); );
CREATE INDEX idx_word_categories_category_id ON word_categories(category_id);
-- Example data insertion -- Example data insertion
INSERT INTO languages (name) VALUES ('en-us'); INSERT INTO languages (name) VALUES ('en-us');
@ -58,6 +70,7 @@ INSERT INTO categories (name, part_of_speech_id) VALUES
('intransitive', 2), ('intransitive', 2),
('action', 2), ('action', 2),
('mental', 2), ('mental', 2),
('auxiliar', 2),
('preposition', 6), ('preposition', 6),
('postposition', 6), ('postposition', 6),
('circumposition', 6); ('circumposition', 6);
@ -83,3 +96,72 @@ SELECT
id id
FROM categories FROM categories
WHERE name IN ('intransitive', 'mental'); WHERE name IN ('intransitive', 'mental');
-- multi word stuff
CREATE TABLE idioms(
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
language_id INTEGER NOT NULL,
frequency INTEGER,
FOREIGN KEY (language_id) REFERENCES languages(id)
);
CREATE TABLE idioms_words(
idiom_id INTEGER NOT NULL,
word_id INTEGER NOT NULL,
PRIMARY KEY (idiom_id, word_id),
FOREIGN KEY (word_id) REFERENCES words(id),
FOREIGN KEY (idiom_id) REFERENCES idioms(id)
);
-- phrasal verbs, other sui generis stuff
CREATE TABLE expressions(
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
type TEXT NOT NULL, -- phrasal-verb, result-complement etc.
language_id INTEGER NOT NULL,
FOREIGN KEY (language_id) REFERENCES languages(id)
);
CREATE TABLE expression_words(
expression_id INTEGER NOT NULL,
word_id INTEGER NOT NULL,
PRIMARY KEY (expression_id, word_id),
FOREIGN KEY (expression_id) REFERENCES expressions(id),
FOREIGN KEY (word_id) REFERENCES words(id)
);
-- Progress
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
creds TEXT NOT NULL
);
CREATE TABLE attempts(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
timestamp INTEGER NOT NULL,
resource_id INTEGER NOT NULL,
resources_type TEXT NOT NULL, -- name of the table, words, expressions, lessons etc.
good INTEGER NOT NULL, -- 0 or 1
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Index to query attempts on a specific resource
CREATE INDEX idx_attempts_resource ON attempts(resource_id, resources_type);
-- Index to query attempts for a specific user
CREATE INDEX idx_attempts_user ON attempts(user_id);
-- (Optional) Index to query attempts by user and resource (useful if you often query by both)
CREATE INDEX idx_attempts_user_resource ON attempts(user_id, resource_id, resources_type);
-- Lessons
CREATE TABLE lessons(
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL
);
CREATE TABLE lessons_resources(
resource_id INTEGER NOT NULL,
resources_type TEXT NOT NULL, -- name of the table, words, expressions etc.
lesson_id INTEGER NOT NULL,
FOREIGN KEY (lesson_id) REFERENCES lessons(id)
);

View File

@ -11,12 +11,18 @@
# https://devenv.sh/packages/ # https://devenv.sh/packages/
packages = with pkgs; [ packages = with pkgs; [
sqlite sqlite
nodePackages.typescript-language-server
nodePackages.prettier
]; ];
# https://devenv.sh/languages/ # https://devenv.sh/languages/
# languages.rust.enable = true; # languages.rust.enable = true;
languages = { languages = {
elm.enable = true; elm.enable = true;
javascript = {
enable = true;
bun.enable = true;
};
}; };
# https://devenv.sh/processes/ # https://devenv.sh/processes/

175
server/.gitignore vendored Normal file
View File

@ -0,0 +1,175 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

6
server/.prettierrc.json Normal file
View File

@ -0,0 +1,6 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}

15
server/README.md Normal file
View File

@ -0,0 +1,15 @@
# server
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run index.ts
```
This project was created using `bun init` in bun v1.1.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

BIN
server/bun.lockb Executable file

Binary file not shown.

11
server/package.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "server",
"module": "server.ts",
"type": "module",
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}

74
server/server.ts Normal file
View File

@ -0,0 +1,74 @@
import { Database } from 'bun:sqlite';
const db = new Database('../data/data.db');
db.exec('PRAGMA journal_mode = WAL;');
Bun.serve({
fetch(req) {
console.log('req object', req);
const url = new URL(req.url);
if (url.pathname === '/') return new Response('Home page!');
if (req.method === 'POST' && url.pathname === '/api')
return handlePost(req, url);
if (req.method === 'GET' && url.pathname.startsWith('/api'))
return handleGet(req, url);
return new Response('404!');
},
});
async function handleGet(_req: Request, url: URL) {
if (url.pathname === '/api/resource') return handleGetResource(url);
else return new Response('huh');
}
function handleGetResource(url: URL) {
const params = new URLSearchParams(url.search);
console.log(params);
const type = params.get('type');
const resource = params.get('res');
const data = fetchResource(type!, resource!);
return Response.json({ ok: true, data });
}
async function handlePost(req: Request, url: URL) {
const data = await req.json();
if (url.pathname === '/api/user') return handlePostUser(data);
else return new Response('huh');
}
// https://bun.sh/guides/http/server
type PostUser = { name: string; creds: string };
function handlePostUser(user: PostUser) {
addUser(user.name, user.creds);
return new Response('ok');
}
function addUser(name: string, creds: string) {
const query = db.query(`
INSERT
INTO users(name, creds)
VALUES($name, $creds)
`);
query.run({ $name: name, $creds: creds });
}
function fetchResource(type: string, resource: string) {
if (type === 'word') return fetchWord(resource);
else return {};
}
function fetchWord(word: string) {
const query = db.query(`
SELECT
spelling,
ipa,
languages.name AS language,
GROUP_CONCAT(c.name, ',') AS category,
ps.name AS pos
FROM words
JOIN languages ON languages.id = words.language_id
JOIN word_categories wc ON words.id = wc.word_id
JOIN categories c ON wc.category_id = c.id
JOIN parts_of_speech ps ON ps.id = c.part_of_speech_id
WHERE spelling = $spelling
GROUP BY words.id
`);
return query.get({ $spelling: word });
}

27
server/tsconfig.json Normal file
View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}