[add] typescript logic
Christian Fraß

Christian Fraß commited on 2021-03-03 00:27:18
Zeige 29 geänderte Dateien mit 1468 Einfügungen und 0 Löschungen.

... ...
@@ -0,0 +1,15 @@
1
+namespace entities
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export type concept =
7
+	{
8
+		type_id : int;
9
+		description : string;
10
+		tags : Array<int>;
11
+		translations : Array<{language_id : int; value : string;}>;
12
+	};
13
+	
14
+}
15
+
... ...
@@ -0,0 +1,258 @@
1
+// import {int} from './types';
2
+
3
+
4
+namespace helpers.database
5
+{
6
+	
7
+	/**
8
+	 */
9
+	type type_query = {
10
+		sql_template : string;
11
+		arguments : {[name : string] : any};
12
+	};
13
+	
14
+	
15
+	/**
16
+	 */
17
+	function resolve_path
18
+	(
19
+		path_raw : string
20
+	) : string
21
+	{
22
+		return ("sql/" + path_raw.replace(new RegExp("\\.", "g"), "/") + ".sql");
23
+	}
24
+	
25
+	
26
+	/**
27
+	 */
28
+	function fix_query
29
+	(
30
+		query : type_query,
31
+	) : type_query
32
+	{
33
+		return {
34
+			"sql_template": query.sql_template.replace
35
+			(
36
+				new RegExp(":([0-9a-zA-Z_-]+)", "g"),
37
+				"$$$1"
38
+			),
39
+			"arguments": (
40
+				() =>
41
+				{
42
+					let arguments_ : {[name : string] : any} = {};
43
+					Object.keys(query.arguments).forEach
44
+					(
45
+						(name) => {arguments_["$" + name] = query.arguments[name];}
46
+					);
47
+					return arguments_;
48
+				}
49
+			) (),
50
+		};
51
+	}
52
+	
53
+	
54
+	/**
55
+	 */
56
+	function query_do_free_
57
+	(
58
+		query : type_query
59
+	) : Promise<void>
60
+	{
61
+		const nm_sqlite3 = require("sqlite3");
62
+		const query_fixed : type_query = fix_query(query);
63
+		// console.info("---\n" + query_fixed.sql_template + "\n" + JSON.stringify(query_fixed.arguments) + "\n---\n");
64
+		return (
65
+			new Promise<void>
66
+			(
67
+				(resolve, reject) =>
68
+				{
69
+					const database/* : nm_sqlite3.Database*/ = new nm_sqlite3.Database("concepts.sqlite");
70
+					database.run
71
+					(
72
+						query_fixed.sql_template,
73
+						query_fixed.arguments,
74
+						function (error)
75
+						{
76
+							if (error)
77
+							{
78
+								reject(error);
79
+							}
80
+							else
81
+							{
82
+								resolve(undefined);
83
+							}
84
+						}
85
+					);
86
+					database.close();
87
+				}
88
+			)
89
+		);
90
+	}
91
+	
92
+	
93
+	/**
94
+	 */
95
+	function query_get_free_
96
+	(
97
+		query : type_query
98
+	) : Promise<Array<type_row>>
99
+	{
100
+		const nm_sqlite3 = require("sqlite3");
101
+		const query_fixed : type_query = fix_query(query);
102
+		// console.info("---\n" + query_fixed.sql_template + "\n" + JSON.stringify(query_fixed.arguments) + "\n---\n");
103
+		return (
104
+			new Promise<Array<type_row>>
105
+			(
106
+				(resolve, reject) =>
107
+				{
108
+					const database/* : nm_sqlite3.Database*/ = new nm_sqlite3.Database("concepts.sqlite");
109
+					database.all
110
+					(
111
+						query_fixed.sql_template,
112
+						query_fixed.arguments,
113
+						function (error, rows)
114
+						{
115
+							// console.info({error,rows});
116
+							if (error)
117
+							{
118
+								reject(error);
119
+							}
120
+							else
121
+							{
122
+								resolve(rows);
123
+							}
124
+						}
125
+					);
126
+					database.close();
127
+				}
128
+			)
129
+		);
130
+	}
131
+	
132
+		
133
+	/**
134
+	 */
135
+	function query_put_free_
136
+	(
137
+		query : type_query
138
+	) : Promise<int>
139
+	{
140
+		const nm_sqlite3 = require("sqlite3");
141
+		const query_fixed : type_query = fix_query(query);
142
+		// console.info("---\n" + query_fixed.sql_template + "\n" + JSON.stringify(query_fixed.arguments) + "\n---\n");
143
+		return (
144
+			new Promise<int>
145
+			(
146
+				(resolve, reject) =>
147
+				{
148
+					const database/* : nm_sqlite3.Database*/ = new nm_sqlite3.Database("concepts.sqlite");
149
+					database.run
150
+					(
151
+						query_fixed.sql_template,
152
+						query_fixed.arguments,
153
+						function (error)
154
+						{
155
+							if (error)
156
+							{
157
+								reject(error);
158
+							}
159
+							else
160
+							{
161
+								resolve(this.lastID);
162
+							}
163
+						}
164
+					);
165
+					database.close();
166
+				}
167
+			)
168
+		);
169
+	}
170
+	
171
+	
172
+	/**
173
+	 */
174
+	export function query_do_free
175
+	(
176
+		sql_template : string,
177
+		arguments_ : {[name : string] : any} = {}
178
+	) : Promise<void>
179
+	{
180
+		return query_do_free_({"sql_template": sql_template, "arguments": arguments_});
181
+	}
182
+	
183
+	
184
+	/**
185
+	 */
186
+	export function query_get_free
187
+	(
188
+		sql_template : string,
189
+		arguments_ : {[name : string] : any} = {}
190
+	) : Promise<Array<type_row>>
191
+	{
192
+		return query_get_free_({"sql_template": sql_template, "arguments": arguments_});
193
+	}
194
+	
195
+	
196
+	/**
197
+	 */
198
+	export function query_put_free
199
+	(
200
+		sql_template : string,
201
+		arguments_ : {[name : string] : any} = {}
202
+	) : Promise<int>
203
+	{
204
+		return query_put_free_({"sql_template": sql_template, "arguments": arguments_});
205
+	}
206
+	
207
+	
208
+	/**
209
+	 */
210
+	export function query_do_named
211
+	(
212
+		name : string,
213
+		arguments_ : {[name : string] : any} = {}
214
+	) : Promise<void>
215
+	{
216
+		return query_do_free
217
+		(
218
+			helpers.file.read(resolve_path(name)),
219
+			arguments_
220
+		);
221
+	}
222
+	
223
+	
224
+	/**
225
+	 */
226
+	export function query_get_named
227
+	(
228
+		name : string,
229
+		arguments_ : {[name : string] : any} = {}
230
+	) : Promise<Array<type_row>>
231
+	{
232
+		return query_get_free
233
+		(
234
+			helpers.file.read(resolve_path(name)),
235
+			arguments_
236
+		);
237
+	}
238
+	
239
+	
240
+	/**
241
+	 */
242
+	export function query_put_named
243
+	(
244
+		name : string,
245
+		arguments_ : {[name : string] : any} = {}
246
+	) : Promise<int>
247
+	{
248
+		return query_put_free
249
+		(
250
+			helpers.file.read(resolve_path(name)),
251
+			arguments_
252
+		);
253
+	}
254
+	
255
+}
256
+
257
+
258
+
... ...
@@ -0,0 +1,18 @@
1
+namespace helpers.file
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export function read
7
+	(
8
+		path : string
9
+	) : string
10
+	{
11
+		const nm_fs = require("fs");
12
+		const buffer : Buffer = nm_fs.readFileSync(path);
13
+		const content : string = buffer.toString();
14
+		return content;
15
+	}
16
+	
17
+}
18
+
... ...
@@ -0,0 +1,33 @@
1
+namespace helpers.misc
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export function stdin
7
+	(
8
+	) : Promise<string>
9
+	{
10
+		return (
11
+			new Promise<string>
12
+			(
13
+				(resolve, reject) =>
14
+				{
15
+					const readline = require("readline");
16
+					const reader = readline.createInterface
17
+					(
18
+						{
19
+							"input": process.stdin,
20
+							"output": process.stdout,
21
+							"terminal": false
22
+						}
23
+					);
24
+					let lines : Array<string> = [];
25
+					reader.on("line", (line) => lines.push(line));
26
+					reader.on("close", () => resolve(lines.join("\n")));
27
+				}
28
+			)
29
+		);
30
+	}
31
+	
32
+}
33
+
... ...
@@ -0,0 +1,13 @@
1
+namespace helpers
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export type module =
7
+	{
8
+		setup : ()=>Promise<void>;
9
+		teardown : ()=>Promise<void>;
10
+	};
11
+	
12
+}
13
+
... ...
@@ -0,0 +1,24 @@
1
+namespace helpers
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export type repository<type_key, type_value> =
7
+	(
8
+		helpers.module
9
+		&
10
+		helpers.storage<type_key, type_value>
11
+	);
12
+	
13
+	
14
+	/**
15
+	 */
16
+	export type repository_sqltable =
17
+	(
18
+		helpers.module
19
+		&
20
+		helpers.storage_sqltable
21
+	);
22
+	
23
+}
24
+
... ...
@@ -0,0 +1,27 @@
1
+namespace helpers
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export type storage<type_key, type_value> =
7
+	{
8
+		create : (value : type_value)=>Promise<type_key>;
9
+		update : (key : type_key, value : type_value)=>Promise<void>;
10
+		delete : (key : type_key)=>Promise<void>;
11
+		read : (key : type_key)=>Promise<type_value>;
12
+	};
13
+	
14
+	
15
+	/**
16
+	 */
17
+	export type storage_sqltable = (
18
+		storage<int, type_row>
19
+		&
20
+		{
21
+			purge : (column : string, value : any)=>Promise<void>;
22
+			take : (column : string, value : any)=>Promise<Array<type_row>>;
23
+		}
24
+	);
25
+	
26
+}
27
+
... ...
@@ -0,0 +1,24 @@
1
+namespace helpers.string
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export function coin
7
+	(
8
+		template : string,
9
+		arguments_ : {[key : string] : string},
10
+		open : string = "{{",
11
+		close : string = "}}"
12
+	) : string
13
+	{
14
+		let result : string = template;
15
+		for (let [key, value] of Object.entries(arguments_))
16
+		{
17
+			const pattern : string = (open + key + close);
18
+			result = result.replace(new RegExp(pattern, "g"), value);
19
+		}
20
+		return result;
21
+	}
22
+	
23
+}
24
+
... ...
@@ -0,0 +1,95 @@
1
+#!/usr/bin/env node
2
+
3
+/*
4
+import {repositories.language} from './repository-language';
5
+import {repositories.type} from './repository-type';
6
+import {repositories.tag} from './repository-tag';
7
+import {repositories.concept} from './repository-concept';
8
+ */
9
+
10
+
11
+/**
12
+ */
13
+async function main(args : Array<string>) : Promise<void>
14
+{
15
+	const command : string = args.shift();
16
+	switch (command)
17
+	{
18
+		case "setup":
19
+		{
20
+			await repositories.language.setup()
21
+			await repositories.type.setup()
22
+			await repositories.tag.setup()
23
+			await repositories.concept.setup()
24
+			process.exit(0);
25
+			break;
26
+		}
27
+		case "feed":
28
+		{
29
+			const content : string = await helpers.misc.stdin();
30
+			const data : any = JSON.parse(content);
31
+			const concept_thing : any = data;
32
+			const concept_id : int = await services.concept.suck(concept_thing);
33
+			console.info(concept_id);
34
+			process.exit(0);
35
+			break;
36
+		}
37
+		case "translate":
38
+		{
39
+			const language_from : string = args.shift();
40
+			const language_to : string = args.shift();
41
+			const part : string = args.shift();
42
+			const result = await services.concept.get_translations
43
+			(
44
+				language_from,
45
+				language_to,
46
+				part
47
+			);
48
+			result.forEach
49
+			(
50
+				(entry) =>
51
+				{
52
+					console.info
53
+					(
54
+						helpers.string.coin
55
+						(
56
+							"[{{language_from}}] {{value_from}} ~ [{{language_to}}] {{value_to}}",
57
+							{
58
+								"language_from": language_from,
59
+								"value_from": entry["value_from"],
60
+								"language_to": language_to,
61
+								"value_to": entry["value_to"],
62
+							}
63
+						)
64
+					);
65
+				}
66
+			);
67
+			process.exit(0);
68
+			break;
69
+		}
70
+		case "export":
71
+		{
72
+			const result : Array<any> = await services.concept.export_();
73
+			console.info(JSON.stringify(result, undefined, "\t"));
74
+			process.exit(0);
75
+			break;
76
+		}
77
+		case "show":
78
+		{
79
+			const concept_id = parseInt(args.shift());
80
+			const concept_entity : entities.concept = await services.concept.get(concept_id);
81
+			console.info(JSON.stringify(concept_entity, undefined, "\t"));
82
+			break;
83
+		}
84
+		default:
85
+		{
86
+			console.error("unhandled command: " + command);
87
+			process.exit(1);
88
+			break;
89
+		}
90
+	}
91
+}
92
+
93
+
94
+main(process.argv.slice(2));
95
+
... ...
@@ -0,0 +1,78 @@
1
+namespace repositories
2
+{
3
+	
4
+	export var concept_core : helpers.repository_sqltable =
5
+	{
6
+		"setup": function ()
7
+		{
8
+			return helpers.database.query_do_named("concept.setup-core");
9
+		},
10
+		"teardown": function ()
11
+		{
12
+			throw (new Error("not implemented"));
13
+		},
14
+		"create": function (row)
15
+		{
16
+			return helpers.database.query_put_free
17
+			(
18
+				"INSERT INTO concepts(type_id, description) VALUES (:type_id, :description);",
19
+				{
20
+					"type_id": row["type_id"],
21
+					"description": row["description"],
22
+				}
23
+			);
24
+		},
25
+		"update": function (concept_id, row)
26
+		{
27
+			return helpers.database.query_do_free
28
+			(
29
+				"UPDATE concepts SET type_id = :type_id, description = :description WHERE (id = :id)",
30
+				{
31
+					"id": concept_id,
32
+					"type_id": row["type_id"],
33
+					"description": row["description"],
34
+				}
35
+			);
36
+		},
37
+		"delete": function (concept_id)
38
+		{
39
+			return helpers.database.query_do_free
40
+			(
41
+				"DELETE FROM concepts WHERE (id = :id)",
42
+				{
43
+					"id": concept_id,
44
+				}
45
+			);
46
+		},
47
+		"read": function (concept_id)
48
+		{
49
+			return (
50
+				helpers.database.query_get_free
51
+				(
52
+					"SELECT type_id,description FROM concepts WHERE (id = :id)",
53
+					{
54
+						"id": concept_id,
55
+					}
56
+				)
57
+				.then
58
+				(
59
+					(rows) => (
60
+						(rows.length === 1)
61
+						? Promise.resolve<type_row>(rows[0])
62
+						: Promise.reject<type_row>(new Error("not found"))
63
+					)
64
+				)
65
+			);
66
+		},
67
+		"purge": async function (column, value)
68
+		{
69
+			throw (new Error("not implemented"));
70
+		},
71
+		"take": async function (column, value)
72
+		{
73
+			throw (new Error("not implemented"));
74
+		},
75
+	};
76
+	
77
+}
78
+
... ...
@@ -0,0 +1,92 @@
1
+namespace repositories
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export var concept_tags : helpers.repository_sqltable =
7
+	{
8
+		"setup": function ()
9
+		{
10
+			return helpers.database.query_do_named("concept.setup-tags");
11
+		},
12
+		"teardown": function ()
13
+		{
14
+			throw (new Error("not implemented"));
15
+		},
16
+		"create": function (row)
17
+		{
18
+			return helpers.database.query_put_free
19
+			(
20
+				"INSERT INTO concept_tags(concept_id, tag_id) VALUES (:concept_id, :tag_id);",
21
+				{
22
+					"concept_id": row["concept_id"],
23
+					"tag_id": row["tag_id"],
24
+				}
25
+			);
26
+		},
27
+		"update": function (concept_tag_id, row)
28
+		{
29
+			return helpers.database.query_do_free
30
+			(
31
+				"UPDATE concept_tags SET concept_id = :concept_id, tag_id = :tag_id WHERE (id = :id)",
32
+				{
33
+					"id": concept_tag_id,
34
+					"concept_id": row["concept_id"],
35
+					"tag_id": row["tag_id"],
36
+				}
37
+			);
38
+		},
39
+		"delete": function (concept_tag_id)
40
+		{
41
+			return helpers.database.query_do_free
42
+			(
43
+				"DELETE FROM concept_tags WHERE (id = :id)",
44
+				{
45
+					"id": concept_tag_id,
46
+				}
47
+			);
48
+		},
49
+		"read": async function (concept_tag_id)
50
+		{
51
+			return (
52
+				helpers.database.query_get_free
53
+				(
54
+					"SELECT concept_id,tag_id FROM concept_tags WHERE (id = :id)",
55
+					{
56
+						"id": concept_tag_id,
57
+					}
58
+				)
59
+				.then
60
+				(
61
+					(rows) => (
62
+						(rows.length === 1)
63
+						? Promise.resolve<type_row>(rows[0])
64
+						: Promise.reject<type_row>(new Error("not found"))
65
+					)
66
+				)
67
+			);
68
+		},
69
+		"purge": async function (column, value)
70
+		{
71
+			return helpers.database.query_do_free
72
+			(
73
+				"DELETE FROM concept_tags WHERE (" + column + " = :value)",
74
+				{
75
+					"value": value,
76
+				}
77
+			);
78
+		},
79
+		"take": async function (column, value)
80
+		{
81
+			return await helpers.database.query_get_free
82
+			(
83
+				"SELECT concept_id,tag_id FROM concept_tags WHERE (" + column + " = :value)",
84
+				{
85
+					"value": value,
86
+				}
87
+			);
88
+		},
89
+	};
90
+	
91
+}
92
+
... ...
@@ -0,0 +1,94 @@
1
+namespace repositories
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export var concept_translations : helpers.repository_sqltable =
7
+	{
8
+		"setup": function ()
9
+		{
10
+			return helpers.database.query_do_named("concept.setup-translations");
11
+		},
12
+		"teardown": function ()
13
+		{
14
+			throw (new Error("not implemented"));
15
+		},
16
+		"create": function (row)
17
+		{
18
+			return helpers.database.query_put_free
19
+			(
20
+				"INSERT INTO concept_translations(concept_id, language_id, value) VALUES (:concept_id, :language_id, :value);",
21
+				{
22
+					"concept_id": row["concept_id"],
23
+					"language_id": row["language_id"],
24
+					"value": row["value"],
25
+				}
26
+			);
27
+		},
28
+		"update": function (concept_translation_id, row)
29
+		{
30
+			return helpers.database.query_do_free
31
+			(
32
+				"UPDATE concept_translations SET concept_id = :concept_id, language_id = :language_id, value = :value WHERE (id = :id)",
33
+				{
34
+					"id": concept_translation_id,
35
+					"concept_id": row["concept_id"],
36
+					"language_id": row["language_id"],
37
+					"value": row["value"],
38
+				}
39
+			);
40
+		},
41
+		"delete": function (concept_translation_id)
42
+		{
43
+			return helpers.database.query_do_free
44
+			(
45
+				"DELETE FROM concept_translations WHERE (id = :id)",
46
+				{
47
+					"id": concept_translation_id,
48
+				}
49
+			);
50
+		},
51
+		"read": async function (concept_translation_id)
52
+		{
53
+			return (
54
+				helpers.database.query_get_free
55
+				(
56
+					"SELECT concept_id,language_id,value FROM concept_translations WHERE (id = :id)",
57
+					{
58
+						"id": concept_translation_id,
59
+					}
60
+				)
61
+				.then
62
+				(
63
+					(rows) => (
64
+						(rows.length === 1)
65
+						? Promise.resolve<type_row>(rows[0])
66
+						: Promise.reject<type_row>(new Error("not found"))
67
+					)
68
+				)
69
+			);
70
+		},
71
+		"purge": async function (column, value)
72
+		{
73
+			return helpers.database.query_do_free
74
+			(
75
+				"DELETE FROM concept_translations WHERE (" + column + " = :value)",
76
+				{
77
+					"value": value,
78
+				}
79
+			);
80
+		},
81
+		"take": async function (column, value)
82
+		{
83
+			return await helpers.database.query_get_free
84
+			(
85
+				"SELECT concept_id,language_id,value FROM concept_translations WHERE (" + column + " = :value)",
86
+				{
87
+					"value": value,
88
+				}
89
+			);
90
+		},
91
+	};
92
+	
93
+}
94
+
... ...
@@ -0,0 +1,90 @@
1
+namespace repositories
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export var concept : (
7
+		helpers.repository<int, entities.concept>
8
+		&
9
+		{
10
+			get_translations : (language_from : string, language_to : string, part : string)=>Promise<Array<type_row>>;
11
+			export : ()=>Promise<Array<type_row>>;
12
+		}
13
+	) =
14
+	{
15
+		"setup": async function ()
16
+		{
17
+			await repositories.concept_core.setup();
18
+			await repositories.concept_tags.setup();
19
+			await repositories.concept_translations.setup();
20
+			return Promise.resolve<void>(undefined);
21
+		},
22
+		"teardown": async function ()
23
+		{
24
+			await repositories.concept_translations.teardown();
25
+			await repositories.concept_tags.teardown();
26
+			await repositories.concept_core.teardown();
27
+			return Promise.resolve<void>(undefined);
28
+		},
29
+		"create": async function (concept_entity)
30
+		{
31
+			const row_core : type_row = {"type_id": concept_entity.type_id, "description": concept_entity.description};
32
+			const concept_id : int = await repositories.concept_core.create(row_core);
33
+			for await (let tag_id of concept_entity.tags)
34
+			{
35
+				const row_tag : type_row = {"concept_id": concept_id, "tag_id": tag_id};
36
+				const concept_tag_id : int = await repositories.concept_tags.create(row_tag);
37
+			}
38
+			for await (let {"language_id": language_id, "value": value} of concept_entity.translations)
39
+			{
40
+				const row_translations : type_row = {"concept_id": concept_id, "language_id": language_id, "value": value};
41
+				const concept_translations_id : int = await repositories.concept_translations.create(row_translations);
42
+			}
43
+			return Promise.resolve<int>(concept_id);
44
+		},
45
+		"update": function (concept_id, concept_entity)
46
+		{
47
+			throw (new Error("not implemented"));
48
+		},
49
+		"delete": async function (concept_id)
50
+		{
51
+			await repositories.concept_translations.purge("concept_id", concept_id);
52
+			await repositories.concept_tags.purge("concept_id", concept_id);
53
+			await repositories.concept_core.delete(concept_id);
54
+			return Promise.resolve<void>(undefined);
55
+		},
56
+		"read": async function (concept_id)
57
+		{
58
+			const row_core : type_row = await repositories.concept_core.read(concept_id);;
59
+			const rows_tags : Array<type_row> = await repositories.concept_tags.take("concept_id", concept_id);
60
+			const rows_translations : Array<type_row> = await repositories.concept_translations.take("concept_id", concept_id);
61
+			const concept_entity : entities.concept =
62
+			{
63
+				"type_id": row_core["type_id"],
64
+				"description": row_core["description"],
65
+				"tags": rows_tags.map(row_tag => row_tag["tag_id"]),
66
+				"translations": rows_translations.map(row_translation => ({"language_id": row_translation["language_id"], "value": row_translation["value"]})),
67
+			};
68
+			return Promise.resolve<entities.concept>(concept_entity);
69
+		},
70
+		"get_translations": function (language_from : string, language_to : string, part : string) : Promise<Array<type_row>>
71
+		{
72
+			return helpers.database.query_get_named
73
+			(
74
+				"concept.get_translations",
75
+				{
76
+					"language_value_from": language_from,
77
+					"language_value_to": language_to,
78
+					"part": part.replace(new RegExp("-", "g"), "%"),
79
+				}
80
+			);
81
+		},
82
+		"export": function () : Promise<Array<type_row>>
83
+		{
84
+			return helpers.database.query_get_named("concept.export");
85
+		},
86
+	};
87
+	
88
+}
89
+
90
+
... ...
@@ -0,0 +1,97 @@
1
+namespace repositories
2
+{
3
+	
4
+	export var language : helpers.repository_sqltable & {identify : (value : string)=>Promise<int>;} =
5
+	{
6
+		"setup": async function ()
7
+		{
8
+			await helpers.database.query_put_named("language.setup");
9
+			return Promise.resolve<void>(undefined);
10
+		},
11
+		"teardown": function ()
12
+		{
13
+			return Promise.reject(new Error("not implemented"));
14
+		},
15
+		"create": function (row)
16
+		{
17
+			return helpers.database.query_put_free
18
+			(
19
+				"INSERT INTO languages(value) VALUES (:value);",
20
+				{
21
+					"value": row["value"],
22
+				}
23
+			);
24
+		},
25
+		"update": function (language_id, row)
26
+		{
27
+			return helpers.database.query_do_free
28
+			(
29
+				"UPDATE languages SET value = :vaule WHERE (id = :id);",
30
+				{
31
+					"id": language_id,
32
+					"value": row["value"],
33
+				}
34
+			);
35
+		},
36
+		"delete": function (language_id)
37
+		{
38
+			return helpers.database.query_do_free
39
+			(
40
+				"DELETE FROM languages WHERE (id = :id);",
41
+				{
42
+					"id": language_id,
43
+				}
44
+			);
45
+		},
46
+		"read": function (language_id)
47
+		{
48
+			return (
49
+				helpers.database.query_get_free
50
+				(
51
+					"SELECT value FROM languages WHERE (id = :id);",
52
+					{
53
+						"id": language_id,
54
+					}
55
+				)
56
+				.then
57
+				(
58
+					(rows) => (
59
+						(rows.length === 1)
60
+						? Promise.resolve<type_row>(rows[0])
61
+						: Promise.reject<type_row>(new Error("not found"))
62
+					)
63
+				)
64
+			);
65
+		},
66
+		"purge": function (column, value)
67
+		{
68
+			return Promise.reject(new Error("not implemented"));
69
+		},
70
+		"take": function (column, value)
71
+		{
72
+			return Promise.reject(new Error("not implemented"));
73
+		},
74
+		"identify": function (value : string) : Promise<int>
75
+		{
76
+			return (
77
+				helpers.database.query_get_free
78
+				(
79
+					"SELECT id FROM languages WHERE (value = :value);",
80
+					{
81
+						"value": value,
82
+					}
83
+				)
84
+				.then
85
+				(
86
+					(rows) => (
87
+						(rows.length === 1)
88
+						? Promise.resolve<int>(rows[0]["id"])
89
+						: Promise.reject<int>()
90
+					)
91
+				)
92
+			);
93
+		},
94
+	};
95
+	
96
+}
97
+
... ...
@@ -0,0 +1,97 @@
1
+namespace repositories
2
+{
3
+	
4
+	export var tag : helpers.repository_sqltable & {identify : (value : string)=>Promise<int>;} =
5
+	{
6
+		"setup": async function ()
7
+		{
8
+			await helpers.database.query_put_named("tag.setup");
9
+			return Promise.resolve<void>(undefined);
10
+		},
11
+		"teardown": function ()
12
+		{
13
+			return Promise.reject(new Error("not implemented"));
14
+		},
15
+		"create": function (row)
16
+		{
17
+			return helpers.database.query_put_free
18
+			(
19
+				"INSERT INTO tags(value) VALUES (:value);",
20
+				{
21
+					"value": row["value"],
22
+				}
23
+			);
24
+		},
25
+		"update": function (tag_id, row)
26
+		{
27
+			return helpers.database.query_do_free
28
+			(
29
+				"UPDATE tags SET value = :vaule WHERE (id = :id);",
30
+				{
31
+					"id": tag_id,
32
+					"value": row["value"],
33
+				}
34
+			);
35
+		},
36
+		"delete": function (tag_id)
37
+		{
38
+			return helpers.database.query_do_free
39
+			(
40
+				"DELETE FROM tags WHERE (id = :id);",
41
+				{
42
+					"id": tag_id,
43
+				}
44
+			);
45
+		},
46
+		"read": function (tag_id)
47
+		{
48
+			return (
49
+				helpers.database.query_get_free
50
+				(
51
+					"SELECT value FROM tags WHERE (id = :id);",
52
+					{
53
+						"id": tag_id,
54
+					}
55
+				)
56
+				.then
57
+				(
58
+					(rows) => (
59
+						(rows.length === 1)
60
+						? Promise.resolve<type_row>(rows[0])
61
+						: Promise.reject<type_row>(new Error("not found"))
62
+					)
63
+				)
64
+			);
65
+		},
66
+		"purge": function (column, value)
67
+		{
68
+			return Promise.reject(new Error("not implemented"));
69
+		},
70
+		"take": function (column, value)
71
+		{
72
+			return Promise.reject(new Error("not implemented"));
73
+		},
74
+		"identify": function (value : string) : Promise<int>
75
+		{
76
+			return (
77
+				helpers.database.query_get_free
78
+				(
79
+					"SELECT id FROM tags WHERE (value = :value);",
80
+					{
81
+						"value": value,
82
+					}
83
+				)
84
+				.then
85
+				(
86
+					(rows) => (
87
+						(rows.length === 1)
88
+						? Promise.resolve<int>(rows[0]["id"])
89
+						: Promise.reject<int>()
90
+					)
91
+				)
92
+			);
93
+		},
94
+	};
95
+	
96
+}
97
+
... ...
@@ -0,0 +1,97 @@
1
+namespace repositories
2
+{
3
+	
4
+	export var type : helpers.repository_sqltable & {identify : (value : string)=>Promise<int>;} =
5
+	{
6
+		"setup": async function ()
7
+		{
8
+			await helpers.database.query_put_named("type.setup");
9
+			return Promise.resolve<void>(undefined);
10
+		},
11
+		"teardown": function ()
12
+		{
13
+			return Promise.reject(new Error("not implemented"));
14
+		},
15
+		"create": function (row)
16
+		{
17
+			return helpers.database.query_put_free
18
+			(
19
+				"INSERT INTO types(value) VALUES (:value);",
20
+				{
21
+					"value": row["value"],
22
+				}
23
+			);
24
+		},
25
+		"update": function (type_id, row)
26
+		{
27
+			return helpers.database.query_do_free
28
+			(
29
+				"UPDATE types SET value = :vaule WHERE (id = :id);",
30
+				{
31
+					"id": type_id,
32
+					"value": row["value"],
33
+				}
34
+			);
35
+		},
36
+		"delete": function (type_id)
37
+		{
38
+			return helpers.database.query_do_free
39
+			(
40
+				"DELETE FROM types WHERE (id = :id);",
41
+				{
42
+					"id": type_id,
43
+				}
44
+			);
45
+		},
46
+		"read": function (type_id)
47
+		{
48
+			return (
49
+				helpers.database.query_get_free
50
+				(
51
+					"SELECT value FROM types WHERE (id = :id);",
52
+					{
53
+						"id": type_id,
54
+					}
55
+				)
56
+				.then
57
+				(
58
+					(rows) => (
59
+						(rows.length === 1)
60
+						? Promise.resolve<type_row>(rows[0])
61
+						: Promise.reject<type_row>(new Error("not found"))
62
+					)
63
+				)
64
+			);
65
+		},
66
+		"purge": function (column, value)
67
+		{
68
+			return Promise.reject(new Error("not implemented"));
69
+		},
70
+		"take": function (column, value)
71
+		{
72
+			return Promise.reject(new Error("not implemented"));
73
+		},
74
+		"identify": function (value : string) : Promise<int>
75
+		{
76
+			return (
77
+				helpers.database.query_get_free
78
+				(
79
+					"SELECT id FROM types WHERE (value = :value);",
80
+					{
81
+						"value": value,
82
+					}
83
+				)
84
+				.then
85
+				(
86
+					(rows) => (
87
+						(rows.length === 1)
88
+						? Promise.resolve<int>(rows[0]["id"])
89
+						: Promise.reject<int>()
90
+					)
91
+				)
92
+			);
93
+		},
94
+	};
95
+	
96
+}
97
+
... ...
@@ -0,0 +1,134 @@
1
+namespace services.concept
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export function get
7
+	(
8
+		concept_id : int
9
+	) : Promise<entities.concept>
10
+	{
11
+		return repositories.concept.read(concept_id);
12
+	}
13
+	
14
+	
15
+	/**
16
+	 */
17
+	export async function suck
18
+	(
19
+		concept_thing : any
20
+	) : Promise<int>
21
+	{
22
+		const type_id : int = await services.type.give(concept_thing["type"]);
23
+		const concept_id : int = await repositories.concept_core.create
24
+		(
25
+			{
26
+				"type_id": type_id,
27
+				"description": concept_thing["description"],
28
+			}
29
+		);
30
+		await concept_thing["tags"].map
31
+		(
32
+			async (tag_value) =>
33
+			{
34
+				const tag_id : int = await services.tag.give(tag_value);
35
+				const concept_tag_id : int = await repositories.concept_tags.create
36
+				(
37
+					{
38
+						"concept_id": concept_id,
39
+						"tag_id": tag_id,
40
+					}
41
+				);
42
+				return concept_tag_id;
43
+			}
44
+		);
45
+		await Object.keys(concept_thing["translations"]).map
46
+		(
47
+			async (language_value) =>
48
+			{
49
+				const language_id : int = await services.language.give(language_value);
50
+				const concept_translation_ids = await concept_thing["translations"][language_value].map
51
+				(
52
+					async (translation_value) =>
53
+					{
54
+						const concept_translation_id : int = await repositories.concept_translations.create
55
+						(
56
+							{
57
+								"concept_id": concept_id,
58
+								"language_id": language_id,
59
+								"value": translation_value,
60
+							}
61
+						);
62
+					}
63
+				);
64
+			}
65
+		);
66
+		return concept_id;
67
+	}
68
+	
69
+	
70
+	/**
71
+	 */
72
+	export function get_translations
73
+	(
74
+		language_from : string,
75
+		language_to : string,
76
+		part : string
77
+	) : Promise<Array<type_row>>
78
+	{
79
+		return repositories.concept.get_translations
80
+		(
81
+			language_from,
82
+			language_to,
83
+			part
84
+		);
85
+	}
86
+	
87
+	
88
+	/**
89
+	 */
90
+	export async function export_
91
+	(
92
+	) : Promise<Array<{id : int; type : string; description : string; tags : Array<string>; translations : {[language : string] : Array<string>}}>>
93
+	{
94
+		const parse_tags = function (tags_raw : string) : Array<string>
95
+		{
96
+			return (
97
+				(tags_raw === null)
98
+				? []
99
+				: tags_raw.split(",")
100
+			);
101
+		};
102
+		const parse_translations = function (translations_raw : string) : {[language : string] : Array<string>}
103
+		{
104
+			let result : {[language : string] : Array<string>} = {};
105
+			const parts : Array<string> = translations_raw.split(",")
106
+			parts.forEach
107
+			(
108
+				(part) =>
109
+				{
110
+					const [language, value] : Array<string> = part.split(":", 2);
111
+					if (! result.hasOwnProperty(language)) result[language] = [];
112
+					result[language].push(value);
113
+				}
114
+			);
115
+			return result;
116
+		};
117
+		const rows : Array<type_row> = await repositories.concept.export();
118
+		return Promise.resolve<any>(
119
+			rows.map
120
+			(
121
+				(row) => (
122
+				{
123
+					"id": row["id"],
124
+					"type": row["type"],
125
+					"description": row["description"],
126
+					"tags": parse_tags(row["tags"]),
127
+					"translations": parse_translations(row["translations"]),
128
+				})
129
+			)
130
+		)
131
+	}
132
+	
133
+}
134
+
... ...
@@ -0,0 +1,10 @@
1
+namespace services.language
2
+{
3
+	
4
+	export function give(value : string) : Promise<int>
5
+	{
6
+		return (repositories.language.identify(value).catch(() => repositories.language.create({"value": value})))
7
+	}
8
+	
9
+}
10
+
... ...
@@ -0,0 +1,10 @@
1
+namespace services.tag
2
+{
3
+	
4
+	export function give(value : string) : Promise<int>
5
+	{
6
+		return (repositories.tag.identify(value).catch(() => repositories.tag.create({"value": value})))
7
+	}
8
+	
9
+}
10
+
... ...
@@ -0,0 +1,10 @@
1
+namespace services.type
2
+{
3
+	
4
+	export function give(value : string) : Promise<int>
5
+	{
6
+		return (repositories.type.identify(value).catch(() => repositories.type.create({"value": value})))
7
+	}
8
+	
9
+}
10
+
... ...
@@ -0,0 +1,16 @@
1
+SELECT
2
+	x1.id AS id,
3
+	MIN(x2.value) AS type,
4
+	GROUP_CONCAT(DISTINCT x4.value) AS tags,
5
+	GROUP_CONCAT(x6.value || ':' || x5.value) AS translations
6
+FROM
7
+	concepts AS x1
8
+	LEFT OUTER JOIN types AS x2 ON (x1.type_id = x2.id)
9
+	LEFT OUTER JOIN concept_tags AS x3 ON (x1.id = x3.concept_id)
10
+	LEFT OUTER JOIN tags AS x4 ON (x3.tag_id = x4.id)
11
+	LEFT OUTER JOIN concept_translations AS x5 ON (x1.id = x5.concept_id)
12
+	LEFT OUTER JOIN languages AS x6 ON (x5.language_id = x6.id)
13
+GROUP BY
14
+	x1.id
15
+;
16
+
... ...
@@ -0,0 +1,16 @@
1
+SELECT
2
+	x.concept_id AS concept_id,
3
+	x.value AS value_from,
4
+	y.value AS value_to
5
+FROM
6
+	concept_translations AS x INNER JOIN concept_translations AS y ON (x.concept_id = y.concept_id)
7
+WHERE
8
+	(
9
+		(x.language_id = (SELECT id FROM languages WHERE (value = :language_value_from)))
10
+		AND
11
+		(y.language_id = (SELECT id FROM languages WHERE (value = :language_value_to)))
12
+		AND
13
+		(x.value LIKE :part)
14
+	)
15
+;
16
+
... ...
@@ -0,0 +1,20 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`concepts`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`type_id`
9
+			INTEGER
10
+			NOT NULL
11
+		,
12
+		`description`
13
+			TEXT
14
+			DEFAULT NULL
15
+		,
16
+		FOREIGN KEY
17
+			(`type_id`)
18
+			REFERENCES `types`(`id`)
19
+	)
20
+;
... ...
@@ -0,0 +1,24 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`concept_tags`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`concept_id`
9
+			INTEGER
10
+			NOT NULL
11
+		,
12
+		`tag_id`
13
+			INTEGER
14
+			NOT NULL
15
+		,
16
+		FOREIGN KEY
17
+			(`concept_id`)
18
+			REFERENCES `concepts`(`id`)
19
+		,
20
+		FOREIGN KEY
21
+			(`tag_id`)
22
+			REFERENCES `tags`(`id`)
23
+	)
24
+;
... ...
@@ -0,0 +1,28 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`concept_translations`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`concept_id`
9
+			INTEGER
10
+			NOT NULL
11
+		,
12
+		`language_id`
13
+			INTEGER
14
+			NOT NULL
15
+		,
16
+		`value`
17
+			TEXT
18
+			NOT NULL
19
+		,
20
+		FOREIGN KEY
21
+			(`language_id`)
22
+			REFERENCES `languages`(`id`)
23
+		,
24
+		FOREIGN KEY
25
+			(`concept_id`)
26
+			REFERENCES `concepts`(`id`)
27
+	)
28
+;
... ...
@@ -0,0 +1,15 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`languages`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`value`
9
+			TEXT
10
+			NOT NULL
11
+		,
12
+		UNIQUE
13
+			(`value`)
14
+	)
15
+;
... ...
@@ -0,0 +1,15 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`tags`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`value`
9
+			TEXT
10
+			NOT NULL
11
+		,
12
+		UNIQUE
13
+			(`value`)
14
+	)
15
+;
... ...
@@ -0,0 +1,15 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`types`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`value`
9
+			TEXT
10
+			NOT NULL
11
+		,
12
+		UNIQUE
13
+			(`value`)
14
+	)
15
+;
... ...
@@ -0,0 +1,3 @@
1
+type int = number;
2
+type type_row = {[field : string] : any};	
3
+
0 4