[mod] makefile
Christian Fraß

Christian Fraß commited on 2021-03-03 23:53:00
Zeige 20 geänderte Dateien mit 747 Einfügungen und 425 Löschungen.

... ...
@@ -8,7 +8,7 @@ namespace entities
8 8
 		type_id : int;
9 9
 		description : string;
10 10
 		tags : Array<int>;
11
-		translations : Array<{language_id : int; value : string;}>;
11
+		expressions : Array<int>;
12 12
 	};
13 13
 	
14 14
 }
... ...
@@ -14,5 +14,35 @@ namespace helpers.file
14 14
 		return content;
15 15
 	}
16 16
 	
17
+	
18
+	/**
19
+	 */
20
+	export function write
21
+	(
22
+		path : string,
23
+		content : string
24
+	) : Promise<void>
25
+	{
26
+		const nm_fs = require("fs");
27
+		return (
28
+			new Promise<void>
29
+			(
30
+				(resolve, reject) =>
31
+				{
32
+					nm_fs.writeFileSync
33
+					(
34
+						path,
35
+						content,
36
+						(error) =>
37
+						{
38
+							if (error) reject(error);
39
+							else resolve(undefined);
40
+						}
41
+					);
42
+				}
43
+			)
44
+		);
45
+	}
46
+	
17 47
 }
18 48
 
... ...
@@ -20,5 +20,21 @@ namespace helpers.string
20 20
 		return result;
21 21
 	}
22 22
 	
23
+	
24
+	export function pad_left
25
+	(
26
+		subject : string,
27
+		length : int,
28
+		filler : string
29
+	) : string
30
+	{
31
+		let result : string = subject;
32
+		while (result.length < length)
33
+		{
34
+			result = (filler + result);
35
+		}
36
+		return result;
37
+	}
38
+	
23 39
 }
24 40
 
... ...
@@ -24,18 +24,19 @@ async function main(args : Array<string>) : Promise<void>
24 24
 	{
25 25
 		case "setup":
26 26
 		{
27
-			await repositories.language.setup()
28
-			await repositories.type.setup()
29
-			await repositories.tag.setup()
30
-			await repositories.concept.setup()
27
+			await repositories.language.setup();
28
+			await repositories.type.setup();
29
+			await repositories.tag.setup();
30
+			await repositories.expression.setup();
31
+			await repositories.concept.setup();
31 32
 			process.exit(0);
32 33
 			break;
33 34
 		}
34 35
 		case "show":
35 36
 		{
36 37
 			const concept_id = parseInt(args.shift());
37
-			const concept_entity : entities.concept = await services.concept.get(concept_id);
38
-			console.info(JSON.stringify(concept_entity, undefined, "\t"));
38
+			const exposal : services.concept.type_exposal = await services.concept.expose(concept_id);
39
+			console.info(JSON.stringify(exposal, undefined, "\t"));
39 40
 			process.exit(0);
40 41
 			break;
41 42
 		}
... ...
@@ -74,15 +75,29 @@ async function main(args : Array<string>) : Promise<void>
74 75
 		}
75 76
 		case "export":
76 77
 		{
77
-			const result : Array<any> = await services.concept.export_();
78
-			console.info(JSON.stringify(result, undefined, "\t"));
78
+			const directory : string = ((args.length >= 1) ? args.shift() : "/tmp");
79
+			const result : Array<services.concept.type_exposal> = await services.concept.export_();
80
+			for await (const exposal of result)
81
+			{
82
+				const path : string = helpers.string.coin
83
+				(
84
+					"{{directory}}/concept_{{id}}.json",
85
+					{
86
+						"directory": directory,
87
+						"id": helpers.string.pad_left(exposal.id.toFixed(0), 5, "0"),
88
+					}
89
+				);
90
+				const content : string = JSON.stringify(result, undefined, "\t");
91
+				await helpers.file.write(path, content);
92
+			}
93
+			console.info(directory);
79 94
 			process.exit(0);
80 95
 			break;
81 96
 		}
82 97
 		case "search":
83 98
 		{
84 99
 			const part : string = args.join(" "); args = [];
85
-			const result = await services.concept.search(part);
100
+			const result : Array<services.concept.type_exposal> = await services.concept.search(part);
86 101
 			result.forEach
87 102
 			(
88 103
 				(entry) =>
... ...
@@ -91,13 +106,23 @@ async function main(args : Array<string>) : Promise<void>
91 106
 					(
92 107
 						helpers.string.coin
93 108
 						(
94
-							"{{id}} | {{type}} | {{description}} | {{tags}} | {{translations}}",
109
+							"{{id}} | {{type}} | {{description}} | {{tags}} | {{expressions}}",
95 110
 							{
96 111
 								"id": entry["id"].toFixed(),
97 112
 								"type": entry["type"],
98 113
 								"description": (entry["description"] ?? '-'),
99 114
 								"tags": entry["tags"].join(","),
100
-								"translations": entry["translations"].map(foo => (foo["language"] + ":" + foo["value"])).join(","),
115
+								"expressions": (
116
+									() =>
117
+									{
118
+										let parts : Array<string> = [];
119
+										for (const [key, value] of Object.entries(entry["expressions"]))
120
+										{
121
+											parts.push(key + ":" + value.join("/"));
122
+										}
123
+										return parts.join(",");
124
+									}
125
+								) (),
101 126
 							}
102 127
 						)
103 128
 					);
... ...
@@ -140,7 +165,7 @@ async function main(args : Array<string>) : Promise<void>
140 165
 					"type": type,
141 166
 					"description": description,
142 167
 					"tags": tags,
143
-					"translations": [],
168
+					"expressions": [],
144 169
 				};
145 170
 				const concept_id : int = await services.concept.suck(concept_thing);
146 171
 				console.info(concept_id);
... ...
@@ -1,78 +0,0 @@
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
-
... ...
@@ -1,92 +0,0 @@
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
-
... ...
@@ -1,94 +0,0 @@
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
-
... ...
@@ -1,45 +1,291 @@
1 1
 namespace repositories
2 2
 {
3 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
+	export var concept_tags : helpers.repository_sqltable =
79
+	{
80
+		"setup": function ()
81
+		{
82
+			return helpers.database.query_do_named("concept.setup-tags");
83
+		},
84
+		"teardown": function ()
85
+		{
86
+			throw (new Error("not implemented"));
87
+		},
88
+		"create": function (row)
89
+		{
90
+			return helpers.database.query_put_free
91
+			(
92
+				"INSERT INTO concept_tags(concept_id, tag_id) VALUES (:concept_id, :tag_id);",
93
+				{
94
+					"concept_id": row["concept_id"],
95
+					"tag_id": row["tag_id"],
96
+				}
97
+			);
98
+		},
99
+		"update": function (concept_tag_id, row)
100
+		{
101
+			return helpers.database.query_do_free
102
+			(
103
+				"UPDATE concept_tags SET concept_id = :concept_id, tag_id = :tag_id WHERE (id = :id)",
104
+				{
105
+					"id": concept_tag_id,
106
+					"concept_id": row["concept_id"],
107
+					"tag_id": row["tag_id"],
108
+				}
109
+			);
110
+		},
111
+		"delete": function (concept_tag_id)
112
+		{
113
+			return helpers.database.query_do_free
114
+			(
115
+				"DELETE FROM concept_tags WHERE (id = :id)",
116
+				{
117
+					"id": concept_tag_id,
118
+				}
119
+			);
120
+		},
121
+		"read": async function (concept_tag_id)
122
+		{
123
+			return (
124
+				helpers.database.query_get_free
125
+				(
126
+					"SELECT concept_id,tag_id FROM concept_tags WHERE (id = :id)",
127
+					{
128
+						"id": concept_tag_id,
129
+					}
130
+				)
131
+				.then
132
+				(
133
+					(rows) => (
134
+						(rows.length === 1)
135
+						? Promise.resolve<type_row>(rows[0])
136
+						: Promise.reject<type_row>(new Error("not found"))
137
+					)
138
+				)
139
+			);
140
+		},
141
+		"purge": async function (column, value)
142
+		{
143
+			return helpers.database.query_do_free
144
+			(
145
+				"DELETE FROM concept_tags WHERE (" + column + " = :value)",
146
+				{
147
+					"value": value,
148
+				}
149
+			);
150
+		},
151
+		"take": async function (column, value)
152
+		{
153
+			return await helpers.database.query_get_free
154
+			(
155
+				"SELECT concept_id,tag_id FROM concept_tags WHERE (" + column + " = :value)",
156
+				{
157
+					"value": value,
158
+				}
159
+			);
160
+		},
161
+	};
162
+	
163
+	
4 164
 	/**
5 165
 	 */
166
+	export var concept_expressions : helpers.repository_sqltable =
167
+	{
168
+		"setup": function ()
169
+		{
170
+			return helpers.database.query_do_named("concept.setup-expressions");
171
+		},
172
+		"teardown": function ()
173
+		{
174
+			throw (new Error("not implemented"));
175
+		},
176
+		"create": function (row)
177
+		{
178
+			return helpers.database.query_put_free
179
+			(
180
+				"INSERT INTO concept_expressions(concept_id, expression_id) VALUES (:concept_id, :expression_id);",
181
+				{
182
+					"concept_id": row["concept_id"],
183
+					"expression_id": row["expression_id"],
184
+				}
185
+			);
186
+		},
187
+		"update": function (concept_expression_id, row)
188
+		{
189
+			return helpers.database.query_do_free
190
+			(
191
+				"UPDATE concept_expressions SET concept_id = :concept_id, expression_id = :expression_id WHERE (id = :id)",
192
+				{
193
+					"id": concept_expression_id,
194
+					"concept_id": row["concept_id"],
195
+					"expression_id": row["expression_id"],
196
+				}
197
+			);
198
+		},
199
+		"delete": function (concept_expression_id)
200
+		{
201
+			return helpers.database.query_do_free
202
+			(
203
+				"DELETE FROM concept_expressions WHERE (id = :id)",
204
+				{
205
+					"id": concept_expression_id,
206
+				}
207
+			);
208
+		},
209
+		"read": async function (concept_expression_id)
210
+		{
211
+			return (
212
+				helpers.database.query_get_free
213
+				(
214
+					"SELECT concept_id,expression_id FROM concept_expressions WHERE (id = :id)",
215
+					{
216
+						"id": concept_expression_id,
217
+					}
218
+				)
219
+				.then
220
+				(
221
+					(rows) => (
222
+						(rows.length === 1)
223
+						? Promise.resolve<type_row>(rows[0])
224
+						: Promise.reject<type_row>(new Error("not found"))
225
+					)
226
+				)
227
+			);
228
+		},
229
+		"purge": async function (column, value)
230
+		{
231
+			return helpers.database.query_do_free
232
+			(
233
+				"DELETE FROM concept_expressions WHERE (" + column + " = :value)",
234
+				{
235
+					"value": value,
236
+				}
237
+			);
238
+		},
239
+		"take": async function (column, value)
240
+		{
241
+			return await helpers.database.query_get_free
242
+			(
243
+				"SELECT concept_id,expression_id FROM concept_expressions WHERE (" + column + " = :value)",
244
+				{
245
+					"value": value,
246
+				}
247
+			);
248
+		},
249
+	};
250
+	
251
+	
6 252
 	export var concept : (
7 253
 		helpers.repository<int, entities.concept>
8 254
 		&
9 255
 		{
10 256
 			get_translations : (language_from : string, language_to : string, part : string)=>Promise<Array<type_row>>;
257
+			search : (part : string)=>Promise<Array<int>>;
11 258
 			export : ()=>Promise<Array<type_row>>;
12
-			search : (part : string)=>Promise<Array<type_row>>;
13 259
 		}
14 260
 	) =
15 261
 	{
16 262
 		"setup": async function ()
17 263
 		{
18
-			await repositories.concept_core.setup();
19
-			await repositories.concept_tags.setup();
20
-			await repositories.concept_translations.setup();
264
+			await concept_core.setup();
265
+			await concept_tags.setup();
266
+			await concept_expressions.setup();
21 267
 			return Promise.resolve<void>(undefined);
22 268
 		},
23 269
 		"teardown": async function ()
24 270
 		{
25
-			await repositories.concept_translations.teardown();
26
-			await repositories.concept_tags.teardown();
27
-			await repositories.concept_core.teardown();
271
+			await concept_expressions.teardown();
272
+			await concept_tags.teardown();
273
+			await concept_core.teardown();
28 274
 			return Promise.resolve<void>(undefined);
29 275
 		},
30 276
 		"create": async function (concept_entity)
31 277
 		{
32 278
 			const row_core : type_row = {"type_id": concept_entity.type_id, "description": concept_entity.description};
33
-			const concept_id : int = await repositories.concept_core.create(row_core);
279
+			const concept_id : int = await concept_core.create(row_core);
34 280
 			for await (let tag_id of concept_entity.tags)
35 281
 			{
36 282
 				const row_tag : type_row = {"concept_id": concept_id, "tag_id": tag_id};
37
-				const concept_tag_id : int = await repositories.concept_tags.create(row_tag);
283
+				const concept_tag_id : int = await concept_tags.create(row_tag);
38 284
 			}
39
-			for await (let {"language_id": language_id, "value": value} of concept_entity.translations)
285
+			for await (let expression_id of concept_entity.expressions)
40 286
 			{
41
-				const row_translations : type_row = {"concept_id": concept_id, "language_id": language_id, "value": value};
42
-				const concept_translations_id : int = await repositories.concept_translations.create(row_translations);
287
+				const row_expressions : type_row = {"concept_id": concept_id, "expression_id": expression_id};
288
+				const concept_expressions_id : int = await concept_expressions.create(row_expressions);
43 289
 			}
44 290
 			return Promise.resolve<int>(concept_id);
45 291
 		},
... ...
@@ -49,22 +295,22 @@ namespace repositories
49 295
 		},
50 296
 		"delete": async function (concept_id)
51 297
 		{
52
-			await repositories.concept_translations.purge("concept_id", concept_id);
53
-			await repositories.concept_tags.purge("concept_id", concept_id);
54
-			await repositories.concept_core.delete(concept_id);
298
+			await concept_expressions.purge("concept_id", concept_id);
299
+			await concept_tags.purge("concept_id", concept_id);
300
+			await concept_core.delete(concept_id);
55 301
 			return Promise.resolve<void>(undefined);
56 302
 		},
57 303
 		"read": async function (concept_id)
58 304
 		{
59
-			const row_core : type_row = await repositories.concept_core.read(concept_id);;
60
-			const rows_tags : Array<type_row> = await repositories.concept_tags.take("concept_id", concept_id);
61
-			const rows_translations : Array<type_row> = await repositories.concept_translations.take("concept_id", concept_id);
305
+			const row_core : type_row = await concept_core.read(concept_id);;
306
+			const rows_tags : Array<type_row> = await concept_tags.take("concept_id", concept_id);
307
+			const rows_expressions : Array<type_row> = await concept_expressions.take("concept_id", concept_id);
62 308
 			const concept_entity : entities.concept =
63 309
 			{
64 310
 				"type_id": row_core["type_id"],
65 311
 				"description": row_core["description"],
66 312
 				"tags": rows_tags.map(row_tag => row_tag["tag_id"]),
67
-				"translations": rows_translations.map(row_translation => ({"language_id": row_translation["language_id"], "value": row_translation["value"]})),
313
+				"expressions": rows_expressions.map(row_expression => row_expression["expression_id"]),
68 314
 			};
69 315
 			return Promise.resolve<entities.concept>(concept_entity);
70 316
 		},
... ...
@@ -80,13 +326,19 @@ namespace repositories
80 326
 				}
81 327
 			);
82 328
 		},
83
-		"export": function () : Promise<Array<type_row>>
329
+		"search": function (part) : Promise<Array<int>>
84 330
 		{
85
-			return helpers.database.query_get_named("concept.dump", {"part": null});
331
+			return (
332
+				helpers.database.query_get_named("concept.search", {"part": part.replace(new RegExp("-", "g"), "%")})
333
+				.then<Array<int>>
334
+				(
335
+					(rows) => Promise.resolve<Array<int>>(rows.map(row => row["id"]))
336
+				)
337
+			);
86 338
 		},
87
-		"search": function (part) : Promise<Array<type_row>>
339
+		"export": function () : Promise<Array<type_row>>
88 340
 		{
89
-			return helpers.database.query_get_named("concept.dump", {"part": part.replace(new RegExp("-", "g"), "%")});
341
+			return helpers.database.query_get_named("concept.dump", {"part": null});
90 342
 		},
91 343
 	};
92 344
 	
... ...
@@ -0,0 +1,113 @@
1
+namespace repositories
2
+{
3
+	
4
+	/**
5
+	 */
6
+	export var expression : helpers.repository_sqltable & {identify : (language_id : int, value : string)=>Promise<int>;} =
7
+	{
8
+		"setup": function ()
9
+		{
10
+			return helpers.database.query_do_named("expression.setup");
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 expressions(language_id, value) VALUES (:language_id, :value);",
21
+				{
22
+					"language_id": row["language_id"],
23
+					"value": row["value"],
24
+				}
25
+			);
26
+		},
27
+		"update": function (concept_expression_id, row)
28
+		{
29
+			return helpers.database.query_do_free
30
+			(
31
+				"UPDATE expressions SET language_id = :language_id, value = :value WHERE (id = :id)",
32
+				{
33
+					"id": concept_expression_id,
34
+					"language_id": row["language_id"],
35
+					"value": row["value"],
36
+				}
37
+			);
38
+		},
39
+		"delete": function (concept_expression_id)
40
+		{
41
+			return helpers.database.query_do_free
42
+			(
43
+				"DELETE FROM expressions WHERE (id = :id)",
44
+				{
45
+					"id": concept_expression_id,
46
+				}
47
+			);
48
+		},
49
+		"read": async function (concept_expression_id)
50
+		{
51
+			return (
52
+				helpers.database.query_get_free
53
+				(
54
+					"SELECT language_id,value FROM expressions WHERE (id = :id)",
55
+					{
56
+						"id": concept_expression_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 expressions 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 language_id,value FROM expressions WHERE (" + column + " = :value)",
84
+				{
85
+					"value": value,
86
+				}
87
+			);
88
+		},
89
+		"identify": function (language_id : int, value : string) : Promise<int>
90
+		{
91
+			return (
92
+				helpers.database.query_get_free
93
+				(
94
+					"SELECT id FROM expressions WHERE (language_id = :language_id) AND (value = :value);",
95
+					{
96
+						"language_id": language_id,
97
+						"value": value,
98
+					}
99
+				)
100
+				.then
101
+				(
102
+					(rows) => (
103
+						(rows.length === 1)
104
+						? Promise.resolve<int>(rows[0]["id"])
105
+						: Promise.reject<int>()
106
+					)
107
+				)
108
+			);
109
+		},
110
+	};
111
+	
112
+}
113
+
... ...
@@ -3,102 +3,209 @@ namespace services.concept
3 3
 	
4 4
 	/**
5 5
 	 */
6
-	export function get
7
-	(
8
-		concept_id : int
9
-	) : Promise<entities.concept>
6
+	export type type_bloated =
7
+	{
8
+		id : int;
9
+		description : string;
10
+		type :
11
+		{
12
+			id : int;
13
+			value : string;
14
+		};
15
+		tags : Array<
16
+			{
17
+				id : int;
18
+				value : string;
19
+			}
20
+		>;
21
+		expressions : Array<
22
+			{
23
+				id : int;
24
+				language :
10 25
 				{
11
-		return repositories.concept.read(concept_id);
26
+					id : int;
27
+					value : string;
28
+				};
29
+				value : string;
12 30
 			}
31
+		>;
32
+	};
13 33
 	
14 34
 	
15 35
 	/**
16 36
 	 */
17
-	export async function suck
37
+	export type type_exposal =
38
+	{
39
+		id : int;
40
+		description : string;
41
+		type : string;
42
+		tags : Array<string>;
43
+		expressions : {[language : string] : Array<string>};
44
+	};
45
+	
46
+	
47
+	/**
48
+	 */
49
+	function parse_tags(
50
+		tags_raw : string
51
+	) : Array<string>
52
+	{
53
+		return (
54
+			(tags_raw === null)
55
+			? []
56
+			: tags_raw.split(",")
57
+		);
58
+	}
59
+	
60
+	
61
+	/**
62
+	 */
63
+	function parse_expressions
18 64
 	(
19
-		concept_thing : any
20
-	) : Promise<int>
65
+		expressions_raw : string
66
+	) : {[language : string] : Array<string>}
21 67
 	{
22
-		const type_id : int = await services.type.give(concept_thing["type"]);
23
-		const concept_id : int = await repositories.concept_core.create
68
+		let result : {[language : string] : Array<string>} = {};
69
+		const parts : Array<string> = expressions_raw.split(",");
70
+		parts.forEach
24 71
 		(
72
+			(part) =>
25 73
 			{
26
-				"type_id": type_id,
27
-				"description": concept_thing["description"],
74
+				const [language, value] : Array<string> = part.split(":", 2);
75
+				if (! result.hasOwnProperty(language)) result[language] = [];
76
+				result[language].push(value);
28 77
 			}
29 78
 		);
30
-		await concept_thing["tags"].map
79
+		return result;
80
+	}
81
+	
82
+	
83
+	/**
84
+	 */
85
+	export async function bloat
31 86
 	(
32
-			async (tag_value) =>
87
+		concept_id : int
88
+	) : Promise<type_bloated>
33 89
 	{
34
-				const tag_id : int = await services.tag.give(tag_value);
35
-				const concept_tag_id : int = await repositories.concept_tags.create
90
+		const concept_entity : entities.concept = await repositories.concept.read(concept_id);
91
+		const type_value : string = (await repositories.type.read(concept_entity.type_id))["value"];
92
+		let result : type_bloated =
93
+		{
94
+			"id": concept_id,
95
+			"description": concept_entity.description,
96
+			"type":
97
+			{
98
+				"id": concept_entity.type_id,
99
+				"value": type_value,
100
+			},
101
+			"tags": [],
102
+			"expressions": [],
103
+		};
104
+		for await (const tag_id of concept_entity.tags)
105
+		{
106
+			const tag_value : string = (await repositories.tag.read(tag_id))["value"];
107
+			result.tags.push({"id": tag_id, "value": tag_value});
108
+		}
109
+		for await (const expression_id of concept_entity.expressions)
110
+		{
111
+			const expression_row : type_row = await repositories.expression.read(expression_id);
112
+			const language_id : int = expression_row["language_id"];
113
+			const language_row : type_row = (await repositories.language.read(expression_row["language_id"]));
114
+			result.expressions.push
36 115
 			(
37 116
 				{
38
-						"concept_id": concept_id,
39
-						"tag_id": tag_id,
117
+					"id": expression_id,
118
+					"language":
119
+					{
120
+						"id": language_id,
121
+						"value": language_row["value"]
122
+					},
123
+					"value": expression_row["value"]
40 124
 				}
41 125
 			);
42
-				return concept_tag_id;
43 126
 		}
44
-		);
45
-		await Object.keys(concept_thing["translations"]).map
127
+		return Promise.resolve<type_bloated>(result);
128
+	}
129
+	
130
+	
131
+	/**
132
+	 */
133
+	export async function expose
46 134
 	(
47
-			async (language_value) =>
135
+		concept_id : int
136
+	) : Promise<type_exposal>
48 137
 	{
49
-				const language_id : int = await services.language.give(language_value);
50
-				const concept_translation_ids = await concept_thing["translations"][language_value].map
138
+		const bloated : type_bloated = await bloat(concept_id);
139
+		return Promise.resolve<type_exposal>
51 140
 		(
52
-					async (translation_value) =>
53 141
 			{
54
-						const concept_translation_id : int = await repositories.concept_translations.create
142
+				"id": bloated.id,
143
+				"description": bloated.description,
144
+				"type": bloated.type.value,
145
+				"tags": bloated.tags.map(tag_entry => tag_entry.value),
146
+				"expressions": (
147
+					() =>
148
+					{
149
+						let expressions : {[language : string] : Array<string>} = {};
150
+						bloated.expressions.forEach
55 151
 						(
152
+							expression_entry =>
56 153
 							{
57
-								"concept_id": concept_id,
58
-								"language_id": language_id,
59
-								"value": translation_value,
154
+								const language : string = expression_entry.language.value;
155
+								if (! expressions.hasOwnProperty(language))
156
+								{
157
+									expressions[language] = [];
60 158
 								}
61
-						);
159
+								expressions[language].push(expression_entry.value);
62 160
 							}
63 161
 						);
162
+						return expressions;
163
+					}
164
+				) (),
64 165
 			}
65 166
 		);
66
-		return concept_id;
67 167
 	}
68 168
 	
69 169
 	
70 170
 	/**
71 171
 	 */
72
-	function parse_tags(
73
-		tags_raw : string
74
-	) : Array<string>
172
+	export async function export_
173
+	(
174
+	) : Promise<Array<type_exposal>>
75 175
 	{
76
-		return (
77
-			(tags_raw === null)
78
-			? []
79
-			: tags_raw.split(",")
176
+		const rows : Array<type_row> = await repositories.concept.export();
177
+		return Promise.resolve<Array<type_exposal>>
178
+		(
179
+			rows.map
180
+			(
181
+				(row) => (
182
+					{
183
+						"id": row["id"],
184
+						"type": row["type"],
185
+						"description": row["description"],
186
+						"tags": parse_tags(row["tags"]),
187
+						"expressions": parse_expressions(row["expressions"]),
188
+					}
189
+				)
190
+			)
80 191
 		);
81 192
 	}
82 193
 
83 194
 	
84 195
 	/**
85 196
 	 */
86
-	function parse_translations
197
+	export async function search
87 198
 	(
88
-		translations_raw : string
89
-	) : Array<{id : int; language : string; value : string;}>
199
+		part : string
200
+	) : Promise<Array<type_exposal>>
90 201
 	{
91
-		let result : Array<{id : int; language : string; value : string;}> = [];
92
-		const parts : Array<string> = translations_raw.split(",")
93
-		parts.forEach
94
-		(
95
-			(part) =>
202
+		const concept_ids : Array<int> = await repositories.concept.search(part);
203
+		let result : Array<type_exposal> = [];
204
+		for await (const concept_id of concept_ids)
96 205
 		{
97
-				const [id, language, value] : Array<string> = part.split(":", 3);
98
-				result.push({"id": parseInt(id), "language": language, "value": value});
206
+			result.push(await expose(concept_id));
99 207
 		}
100
-		);
101
-		return result;
208
+		return Promise.resolve<Array<type_exposal>>(result);
102 209
 	}
103 210
 	
104 211
 	
... ...
@@ -122,62 +229,46 @@ namespace services.concept
122 229
 	
123 230
 	/**
124 231
 	 */
125
-	export async function export_
232
+	export async function suck
126 233
 	(
127
-	) : Promise<Array<{id : int; type : string; description : string; tags : Array<string>; translations : Array<{id : int; language : string; value : string;}>;}>>
234
+		concept_thing : any
235
+	) : Promise<int>
128 236
 	{
129
-		return (
130
-			repositories.concept.export()
131
-			.then
132
-			(
133
-				rows => Promise.resolve
237
+		const type_id : int = await services.type.give(concept_thing["type"]);
238
+		const concept_id : int = await repositories.concept_core.create
134 239
 		(
135
-					rows.map
240
+			{
241
+				"type_id": type_id,
242
+				"description": concept_thing["description"],
243
+			}
244
+		);
245
+		for await (const tag_value of concept_thing["tags"])
246
+		{
247
+			const tag_id : int = await services.tag.give(tag_value);
248
+			const concept_tag_id : int = await repositories.concept_tags.create
136 249
 			(
137
-						(row) => (
138 250
 				{
139
-								"id": row["id"],
140
-								"type": row["type"],
141
-								"description": row["description"],
142
-								"tags": parse_tags(row["tags"]),
143
-								"translations": parse_translations(row["translations"]),
251
+					"concept_id": concept_id,
252
+					"tag_id": tag_id,
144 253
 				}
145
-						)
146
-					)
147
-				)
148
-			)
149
-		)
254
+			);
150 255
 		}
151
-
152
-	
153
-	/**
154
-	 */
155
-	export function search
156
-	(
157
-		part : string
158
-	) : Promise<Array<{id : int; type : string; description : string; tags : Array<string>; translations : Array<{id : int; language : string; value : string;}>;}>>
256
+		for await (const [language_value, expression_values] of Object.entries(concept_thing["expressions"]))
159 257
 		{
160
-		return (
161
-			repositories.concept.search(part)
162
-			.then
163
-			(
164
-				rows => Promise.resolve
165
-				(
166
-					rows.map
258
+			const language_id : int = await services.language.give(language_value);
259
+			for await (const expression_value of <Array<string>>(expression_values))
260
+			{
261
+				const expression_id : int = await services.expression.give(language_id, expression_value);
262
+				const concept_expression_id : int = await repositories.concept_expressions.create
167 263
 				(
168
-						(row) => (
169 264
 					{
170
-								"id": row["id"],
171
-								"type": row["type"],
172
-								"description": row["description"],
173
-								"tags": parse_tags(row["tags"]),
174
-								"translations": parse_translations(row["translations"]),
265
+						"concept_id": concept_id,
266
+						"expression_id": expression_id,
175 267
 					}
176
-						)
177
-					)
178
-				)
179
-			)
180
-		)
268
+				);
269
+			}
270
+		}
271
+		return concept_id;
181 272
 	}
182 273
 	
183 274
 }
... ...
@@ -0,0 +1,13 @@
1
+namespace services.expression
2
+{
3
+	
4
+	export function give(language_id : int, value : string) : Promise<int>
5
+	{
6
+		return (
7
+			repositories.expression.identify(language_id, value)
8
+			.catch(() => repositories.expression.create({"language_id": language_id, "value": value}))
9
+		);
10
+	}
11
+	
12
+}
13
+
... ...
@@ -3,7 +3,10 @@ namespace services.language
3 3
 	
4 4
 	export function give(value : string) : Promise<int>
5 5
 	{
6
-		return (repositories.language.identify(value).catch(() => repositories.language.create({"value": value})))
6
+		return (
7
+			repositories.language.identify(value)
8
+			.catch(() => repositories.language.create({"value": value}))
9
+		);
7 10
 	}
8 11
 	
9 12
 }
... ...
@@ -3,7 +3,10 @@ namespace services.tag
3 3
 	
4 4
 	export function give(value : string) : Promise<int>
5 5
 	{
6
-		return (repositories.tag.identify(value).catch(() => repositories.tag.create({"value": value})))
6
+		return (
7
+			repositories.tag.identify(value)
8
+			.catch(() => repositories.tag.create({"value": value}))
9
+		);
7 10
 	}
8 11
 	
9 12
 }
... ...
@@ -3,7 +3,10 @@ namespace services.type
3 3
 	
4 4
 	export function give(value : string) : Promise<int>
5 5
 	{
6
-		return (repositories.type.identify(value).catch(() => repositories.type.create({"value": value})))
6
+		return (
7
+			repositories.type.identify(value)
8
+			.catch(() => repositories.type.create({"value": value}))
9
+		);
7 10
 	}
8 11
 	
9 12
 }
... ...
@@ -3,14 +3,15 @@ SELECT
3 3
 	MIN(x2.value) AS type,
4 4
 	MIN(x1.description) AS description,
5 5
 	GROUP_CONCAT(DISTINCT x4.value) AS tags,
6
-	GROUP_CONCAT(x5.id || ':' || x6.value || ':' || x5.value) AS translations
6
+	GROUP_CONCAT(x7.value || ':' || x6.value) AS expressions
7 7
 FROM
8 8
 	concepts AS x1
9 9
 	LEFT OUTER JOIN types AS x2 ON (x1.type_id = x2.id)
10 10
 	LEFT OUTER JOIN concept_tags AS x3 ON (x1.id = x3.concept_id)
11 11
 	LEFT OUTER JOIN tags AS x4 ON (x3.tag_id = x4.id)
12
-	LEFT OUTER JOIN concept_translations AS x5 ON (x1.id = x5.concept_id)
13
-	LEFT OUTER JOIN languages AS x6 ON (x5.language_id = x6.id)
12
+	LEFT OUTER JOIN concept_expressions AS x5 ON (x1.id = x5.concept_id)
13
+	LEFT OUTER JOIN expressions AS x6 ON (x5.expression_id = x6.id)
14
+	LEFT OUTER JOIN languages AS x7 ON (x5.language_id = x7.id)
14 15
 WHERE
15 16
 	(
16 17
 		(:part IS NULL)
... ...
@@ -1,29 +1,30 @@
1 1
 SELECT
2 2
 	x1.concept_id AS concept_id,
3
-	x2.value AS language_from,
4
-	x1.value AS value_from,
5
-	y2.value AS language_to,
6
-	y1.value AS value_to
3
+	x3.value AS language_from,
4
+	x2.value AS value_from,
5
+	y3.value AS language_to,
6
+	y2.value AS value_to
7 7
 FROM
8
-	concept_translations AS x1
9
-	INNER JOIN languages AS x2 ON (x1.language_id = x2.id)
10
-	INNER JOIN concept_translations AS y1 ON ((x1.id <> y1.id) AND (x1.concept_id = y1.concept_id))
11
-	INNER JOIN languages AS y2 ON (y1.language_id = y2.id)
8
+	concept_expressions AS x1 INNER JOIN concept_expressions AS y1 ON ((x1.id <> y1.id) AND (x1.concept_id = y1.concept_id))
9
+	LEFT OUTER JOIN expressions AS x2 ON (x1.expression_id = x2.id)
10
+	LEFT OUTER JOIN languages AS x3 ON (x2.language_id = x3.id)
11
+	LEFT OUTER JOIN expressions AS y2 ON (y1.expression_id = y2.id)
12
+	LEFT OUTER JOIN languages AS y3 ON (y2.language_id = y3.id)
12 13
 WHERE
13 14
 	(
14 15
 		(
15 16
 			(:language_from = '_')
16 17
 			OR
17
-			(x2.value = :language_from)
18
+			(x3.value = :language_from)
18 19
 		)
19 20
 		AND
20 21
 		(
21 22
 			(:language_to = '_')
22 23
 			OR
23
-			(y2.value = :language_to)
24
+			(y3.value = :language_to)
24 25
 		)
25 26
 		AND
26
-		(x1.value LIKE :part)
27
+		(x2.value LIKE :part)
27 28
 	)
28 29
 ;
29 30
 
... ...
@@ -0,0 +1,20 @@
1
+SELECT
2
+	x1.id
3
+FROM
4
+	concepts AS x1
5
+	LEFT OUTER JOIN types AS x2 ON (x1.type_id = x2.id)
6
+	LEFT OUTER JOIN concept_tags AS x3 ON (x1.id = x3.concept_id)
7
+	LEFT OUTER JOIN tags AS x4 ON (x3.tag_id = x4.id)
8
+	LEFT OUTER JOIN concept_expressions AS x5 ON (x1.id = x5.concept_id)
9
+	LEFT OUTER JOIN expressions AS x6 ON (x5.expression_id = x6.id)
10
+	LEFT OUTER JOIN languages AS x7 ON (x6.language_id = x7.id)
11
+WHERE
12
+	(
13
+		(:part IS NULL)
14
+		OR
15
+		(x6.value LIKE :part)
16
+	)
17
+GROUP BY
18
+	x1.id
19
+;
20
+
... ...
@@ -1,5 +1,5 @@
1 1
 CREATE TABLE IF NOT EXISTS
2
-	`concept_translations`(
2
+	`concept_expressions`(
3 3
 		`id`
4 4
 			INTEGER
5 5
 			PRIMARY KEY
... ...
@@ -9,20 +9,16 @@ CREATE TABLE IF NOT EXISTS
9 9
 			INTEGER
10 10
 			NOT NULL
11 11
 		,
12
-		`language_id`
12
+		`expression_id`
13 13
 			INTEGER
14 14
 			NOT NULL
15 15
 		,
16
-		`value`
17
-			TEXT
18
-			NOT NULL
19
-		,
20
-		FOREIGN KEY
21
-			(`language_id`)
22
-			REFERENCES `languages`(`id`)
23
-		,
24 16
 		FOREIGN KEY
25 17
 			(`concept_id`)
26 18
 			REFERENCES `concepts`(`id`)
19
+		,
20
+		FOREIGN KEY
21
+			(`expression_id`)
22
+			REFERENCES `expression`(`id`)
27 23
 	)
28 24
 ;
... ...
@@ -0,0 +1,20 @@
1
+CREATE TABLE IF NOT EXISTS
2
+	`expressions`(
3
+		`id`
4
+			INTEGER
5
+			PRIMARY KEY
6
+			AUTOINCREMENT
7
+		,
8
+		`language_id`
9
+			INTEGER
10
+			NOT NULL
11
+		,
12
+		`value`
13
+			TEXT
14
+			NOT NULL
15
+		,
16
+		FOREIGN KEY
17
+			(`language_id`)
18
+			REFERENCES `languages`(`id`)
19
+	)
20
+;
... ...
@@ -32,13 +32,12 @@ ${dir_build}/manage: \
32 32
 	${dir_source}/repositories/language.ts \
33 33
 	${dir_source}/repositories/type.ts \
34 34
 	${dir_source}/repositories/tag.ts \
35
-	${dir_source}/repositories/concept-core.ts \
36
-	${dir_source}/repositories/concept-tags.ts \
37
-	${dir_source}/repositories/concept-translations.ts \
35
+	${dir_source}/repositories/expression.ts \
38 36
 	${dir_source}/repositories/concept.ts \
39 37
 	${dir_source}/services/language.ts \
40 38
 	${dir_source}/services/type.ts \
41 39
 	${dir_source}/services/tag.ts \
40
+	${dir_source}/services/expression.ts \
42 41
 	${dir_source}/services/concept.ts \
43 42
 	${dir_source}/main.ts
44 43
 	@ ${cmd_dir_make} ${dir_build}
45 44