datafolder 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -0
- package/index.js +3 -0
- package/package.json +27 -0
- package/sample.js +37 -0
- package/scripts/airbnb.js +73 -0
- package/scripts/airbnb2.js +74 -0
- package/scripts/airbnb2_queries.js +231 -0
- package/scripts/airbnb_queries.js +264 -0
- package/scripts/downloadFile.js +42 -0
- package/scripts/express.js +46 -0
- package/scripts/fastify.js +79 -0
- package/scripts/flights.js +75 -0
- package/scripts/flights2.js +81 -0
- package/scripts/flights2_queries.js +453 -0
- package/scripts/flights_queries.js +403 -0
- package/src/QyAcl.js +252 -0
- package/src/QyAclSaver.js +14 -0
- package/src/QyAclSaver_Worker.js +29 -0
- package/src/QyAclWriter.js +19 -0
- package/src/QyBatch.js +501 -0
- package/src/QyBinWriter.js +140 -0
- package/src/QyCD.js +61 -0
- package/src/QyCache.js +212 -0
- package/src/QyCompressor.js +60 -0
- package/src/QyCompressor_Worker.js +13 -0
- package/src/QyDB.js +122 -0
- package/src/QyDefaultOptions.js +59 -0
- package/src/QyDir.js +192 -0
- package/src/QyFetch.js +38 -0
- package/src/QyFile.js +124 -0
- package/src/QyFileContentUtils.js +175 -0
- package/src/QyFileLogger.js +58 -0
- package/src/QyIndex.js +237 -0
- package/src/QyIndexPropTree.js +92 -0
- package/src/QyIntersectNode.js +48 -0
- package/src/QyItem.js +105 -0
- package/src/QyJsonSaver.js +20 -0
- package/src/QyKVData.js +289 -0
- package/src/QyKVDataCleaner.js +17 -0
- package/src/QyKVDataCleaner_Worker.js +94 -0
- package/src/QyKVDataLoader.js +65 -0
- package/src/QyKVDataSaver.js +17 -0
- package/src/QyKVDataSaver_Worker.js +81 -0
- package/src/QyLogFileSaver.js +14 -0
- package/src/QyLogFileSaver_Worker.js +26 -0
- package/src/QyLogger.js +76 -0
- package/src/QyMessageWorker.js +41 -0
- package/src/QyMessager.js +84 -0
- package/src/QyMessager_Run.js +13 -0
- package/src/QyMod.js +15 -0
- package/src/QyOpRunner.js +73 -0
- package/src/QyQueue.js +60 -0
- package/src/QySaver.js +83 -0
- package/src/QySnapshotCompactor.js +17 -0
- package/src/QySnapshotCompactor_Worker.js +151 -0
- package/src/QySnapshotSaver.js +17 -0
- package/src/QySnapshotSaver_Worker.js +164 -0
- package/src/QySnapshots.js +354 -0
- package/src/QyStructure.js +50 -0
- package/src/QyTrigger.js +133 -0
- package/src/QyUnionNode.js +105 -0
- package/src/QyUtils.js +250 -0
- package/src/QyWorker.js +33 -0
- package/src/hackernews.js +93 -0
- package/src/rpc/evalCode.js +9 -0
- package/src/rpc/getFileContent.js +16 -0
- package/src/rpc/getSubItems.js +32 -0
- package/src/rpc/queryFiles.js +33 -0
- package/src/rpc/reloadRpc.js +1 -0
- package/src/simulate.js +114 -0
- package/src/simulate2.js +110 -0
- package/src/soc_pokec.js +43 -0
- package/static/bootstrap-5.3.8-dist/css/bootstrap.min.css +6 -0
- package/static/bootstrap-5.3.8-dist/js/bootstrap.bundle.js +6312 -0
- package/static/datafolderui/QyStyledElement.js +30 -0
- package/static/datafolderui/QyUIFolderTree.js +203 -0
- package/static/datafolderui/QyUIUtils.js +42 -0
- package/static/datafolderui/display-tree.js +108 -0
- package/static/datafolderui/explore-tree.js +122 -0
- package/static/datafolderui/folder-tree.js +5 -0
- package/static/datafolderui/hscrpt.js +25 -0
- package/static/datafolderui/index.css +6 -0
- package/static/datafolderui/index.html +20 -0
- package/static/datafolderui/json-view.js +74 -0
- package/static/datafolderui/kv-input.js +66 -0
- package/static/datafolderui/list-input.js +52 -0
- package/static/datafolderui/main-page.js +98 -0
- package/static/datafolderui/num-input.js +27 -0
- package/static/datafolderui/query-editor.js +229 -0
- package/static/datafolderui/querySelectorShadowRoot.js +24 -0
- package/static/datafolderui/resizable-input.js +67 -0
- package/static/favicon.ico +0 -0
- package/static/icons-1.13.1/font/bootstrap-icons.min.css +5 -0
- package/static/icons-1.13.1/font/fonts/bootstrap-icons.woff +0 -0
- package/static/icons-1.13.1/font/fonts/bootstrap-icons.woff2 +0 -0
- package/static/json-view/dist/jsonview.js +433 -0
- package/static/tree.js/tree.css +106 -0
- package/static/tree.js/tree.js +374 -0
- package/static/w2ui/dist/w2ui.min.css +2 -0
- package/static/w2ui/src/less/icons/icons.json +1 -0
- package/static/w2ui/src/less/icons/preview.html +33 -0
- package/static/w2ui/src/less/icons/readme.md +15 -0
- package/static/w2ui/src/less/icons/svg/box.svg +3 -0
- package/static/w2ui/src/less/icons/svg/check.svg +3 -0
- package/static/w2ui/src/less/icons/svg/colors.svg +3 -0
- package/static/w2ui/src/less/icons/svg/columns.svg +5 -0
- package/static/w2ui/src/less/icons/svg/cross.svg +4 -0
- package/static/w2ui/src/less/icons/svg/drop.svg +6 -0
- package/static/w2ui/src/less/icons/svg/empty.svg +3 -0
- package/static/w2ui/src/less/icons/svg/eye-dropper.svg +4 -0
- package/static/w2ui/src/less/icons/svg/info.svg +8 -0
- package/static/w2ui/src/less/icons/svg/paste.svg +4 -0
- package/static/w2ui/src/less/icons/svg/pencil.svg +5 -0
- package/static/w2ui/src/less/icons/svg/plus.svg +3 -0
- package/static/w2ui/src/less/icons/svg/reload.svg +5 -0
- package/static/w2ui/src/less/icons/svg/search.svg +3 -0
- package/static/w2ui/src/less/icons/svg/settings.svg +8 -0
- package/static/w2ui/src/less/icons/w2ui-font.css +36 -0
- package/static/w2ui/src/less/icons/w2ui-font.woff +0 -0
- package/static/w2ui/src/less/src/buttons.less +184 -0
- package/static/w2ui/src/less/src/common.less +541 -0
- package/static/w2ui/src/less/src/fields.less +302 -0
- package/static/w2ui/src/less/src/form.less +319 -0
- package/static/w2ui/src/less/src/grid.less +1057 -0
- package/static/w2ui/src/less/src/icons.less +37 -0
- package/static/w2ui/src/less/src/layout.less +86 -0
- package/static/w2ui/src/less/src/mixins.less +87 -0
- package/static/w2ui/src/less/src/popup.less +277 -0
- package/static/w2ui/src/less/src/sidebar.less +343 -0
- package/static/w2ui/src/less/src/tabs.less +145 -0
- package/static/w2ui/src/less/src/toolbar.less +219 -0
- package/static/w2ui/src/less/src/tooltip.less +948 -0
- package/static/w2ui/src/less/w2ui.less +196 -0
- package/static/w2ui/src/locale/az-az.json +114 -0
- package/static/w2ui/src/locale/ba-ba.json +114 -0
- package/static/w2ui/src/locale/bg-bg.json +114 -0
- package/static/w2ui/src/locale/ca-es.json +114 -0
- package/static/w2ui/src/locale/da-dk.json +114 -0
- package/static/w2ui/src/locale/de-de.json +114 -0
- package/static/w2ui/src/locale/en-gb.json +17 -0
- package/static/w2ui/src/locale/en-us.json +17 -0
- package/static/w2ui/src/locale/es-ar.json +115 -0
- package/static/w2ui/src/locale/es-cr.json +119 -0
- package/static/w2ui/src/locale/es-es.json +114 -0
- package/static/w2ui/src/locale/es-mx.json +114 -0
- package/static/w2ui/src/locale/fr-fr.json +114 -0
- package/static/w2ui/src/locale/gl-es.json +114 -0
- package/static/w2ui/src/locale/hr-hr.json +114 -0
- package/static/w2ui/src/locale/hu-hu.json +114 -0
- package/static/w2ui/src/locale/id-id.json +114 -0
- package/static/w2ui/src/locale/it-it.json +114 -0
- package/static/w2ui/src/locale/ja-jp.json +114 -0
- package/static/w2ui/src/locale/kk-kz.json +116 -0
- package/static/w2ui/src/locale/ko-kr.json +114 -0
- package/static/w2ui/src/locale/lt-lt.json +114 -0
- package/static/w2ui/src/locale/nl-nl.json +114 -0
- package/static/w2ui/src/locale/no-no.json +114 -0
- package/static/w2ui/src/locale/pl-pl.json +114 -0
- package/static/w2ui/src/locale/pt-br.json +114 -0
- package/static/w2ui/src/locale/ru-ru.json +116 -0
- package/static/w2ui/src/locale/sk-sk.json +114 -0
- package/static/w2ui/src/locale/sl-si.json +116 -0
- package/static/w2ui/src/locale/sr-rs.json +114 -0
- package/static/w2ui/src/locale/tr-tr.json +114 -0
- package/static/w2ui/src/locale/uk-ua.json +114 -0
- package/static/w2ui/src/locale/zh-cn.json +114 -0
- package/static/w2ui/src/locale/zh-tw.json +114 -0
- package/static/w2ui/src/query.js +583 -0
- package/static/w2ui/src/readme.md +11 -0
- package/static/w2ui/src/w2base.js +311 -0
- package/static/w2ui/src/w2compat.js +207 -0
- package/static/w2ui/src/w2field.js +1854 -0
- package/static/w2ui/src/w2form.js +2411 -0
- package/static/w2ui/src/w2grid.js +8916 -0
- package/static/w2ui/src/w2layout.js +1194 -0
- package/static/w2ui/src/w2locale.js +129 -0
- package/static/w2ui/src/w2popup.js +909 -0
- package/static/w2ui/src/w2sidebar.js +1769 -0
- package/static/w2ui/src/w2tabs.js +669 -0
- package/static/w2ui/src/w2toolbar.js +1180 -0
- package/static/w2ui/src/w2tooltip.js +3134 -0
- package/static/w2ui/src/w2utils.js +2457 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const assert = require("node:assert/strict");
|
|
2
|
+
|
|
3
|
+
function query1(qyDB) {
|
|
4
|
+
console.time("query1");
|
|
5
|
+
assert.deepEqual(
|
|
6
|
+
qyDB
|
|
7
|
+
.queryFiles("airbnb1", {
|
|
8
|
+
property_type: "Loft",
|
|
9
|
+
room_type: "Entire home/apt",
|
|
10
|
+
bed_type: "Real Bed",
|
|
11
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
12
|
+
})
|
|
13
|
+
.map((x) => x.view(["name"]).name),
|
|
14
|
+
[
|
|
15
|
+
"Porto city centre apartment H",
|
|
16
|
+
"Romantic loft near historic center",
|
|
17
|
+
"Lovely sun light in a stylish loft, Downtown Spot",
|
|
18
|
+
"Charming & Sunny Mezzanine Loft",
|
|
19
|
+
"Be Happy in Porto",
|
|
20
|
+
"Quarry Apartment",
|
|
21
|
+
"Loft with balcony and view of Casa da Música PORTO",
|
|
22
|
+
"For 4 or 6 - Wonderful Apartment downtown",
|
|
23
|
+
"Clérigos Apartments - Apt. 4E for 2/3 Pax",
|
|
24
|
+
"Bright Top Floor Two Rooms Apartment w/ Terrace",
|
|
25
|
+
"ReUrban Flats - Santa Catarina #3",
|
|
26
|
+
"The Blue and White Porto House - Vintage",
|
|
27
|
+
"4twoLoft at Great Location",
|
|
28
|
+
"Step In Porto - Loft w/Mezzanine",
|
|
29
|
+
"Your OWM Invicta",
|
|
30
|
+
"Pury Apartments",
|
|
31
|
+
"Live Porto & Douro - Breiner III",
|
|
32
|
+
],
|
|
33
|
+
);
|
|
34
|
+
console.timeEnd("query1");
|
|
35
|
+
}
|
|
36
|
+
function query2(qyDB) {
|
|
37
|
+
console.time("query2");
|
|
38
|
+
assert.deepEqual(
|
|
39
|
+
qyDB
|
|
40
|
+
.queryFiles(
|
|
41
|
+
"airbnb1",
|
|
42
|
+
{
|
|
43
|
+
property_type: "Loft",
|
|
44
|
+
room_type: "Entire home/apt",
|
|
45
|
+
bed_type: "Real Bed",
|
|
46
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
47
|
+
},
|
|
48
|
+
9,
|
|
49
|
+
)
|
|
50
|
+
.map((x) => x.view(["name"]).name),
|
|
51
|
+
[
|
|
52
|
+
"Porto city centre apartment H",
|
|
53
|
+
"Romantic loft near historic center",
|
|
54
|
+
"Lovely sun light in a stylish loft, Downtown Spot",
|
|
55
|
+
"Charming & Sunny Mezzanine Loft",
|
|
56
|
+
"Be Happy in Porto",
|
|
57
|
+
"Quarry Apartment",
|
|
58
|
+
"Loft with balcony and view of Casa da Música PORTO",
|
|
59
|
+
"For 4 or 6 - Wonderful Apartment downtown",
|
|
60
|
+
"Clérigos Apartments - Apt. 4E for 2/3 Pax",
|
|
61
|
+
],
|
|
62
|
+
);
|
|
63
|
+
console.timeEnd("query2");
|
|
64
|
+
}
|
|
65
|
+
function query3(qyDB) {
|
|
66
|
+
console.time("query3");
|
|
67
|
+
assert.deepEqual(
|
|
68
|
+
qyDB
|
|
69
|
+
.queryFiles(
|
|
70
|
+
"airbnb1",
|
|
71
|
+
{
|
|
72
|
+
property_type: "Loft",
|
|
73
|
+
room_type: "Entire home/apt",
|
|
74
|
+
bed_type: "Real Bed",
|
|
75
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
76
|
+
},
|
|
77
|
+
9,
|
|
78
|
+
9,
|
|
79
|
+
)
|
|
80
|
+
.map((x) => x.view(["name"]).name),
|
|
81
|
+
[
|
|
82
|
+
"Bright Top Floor Two Rooms Apartment w/ Terrace",
|
|
83
|
+
"ReUrban Flats - Santa Catarina #3",
|
|
84
|
+
"The Blue and White Porto House - Vintage",
|
|
85
|
+
"4twoLoft at Great Location",
|
|
86
|
+
"Step In Porto - Loft w/Mezzanine",
|
|
87
|
+
"Your OWM Invicta",
|
|
88
|
+
"Pury Apartments",
|
|
89
|
+
"Live Porto & Douro - Breiner III",
|
|
90
|
+
],
|
|
91
|
+
);
|
|
92
|
+
console.timeEnd("query3");
|
|
93
|
+
}
|
|
94
|
+
function query4(qyDB) {
|
|
95
|
+
console.time("query4");
|
|
96
|
+
assert.deepEqual(
|
|
97
|
+
qyDB
|
|
98
|
+
.queryFiles("airbnb1", {
|
|
99
|
+
$or: [
|
|
100
|
+
{
|
|
101
|
+
property_type: "Loft",
|
|
102
|
+
room_type: "Entire home/apt",
|
|
103
|
+
bed_type: "Real Bed",
|
|
104
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
105
|
+
},
|
|
106
|
+
{ property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 },
|
|
107
|
+
],
|
|
108
|
+
})
|
|
109
|
+
.map((x) => x.view(["name"]).name),
|
|
110
|
+
[
|
|
111
|
+
"Porto city centre apartment H",
|
|
112
|
+
"Romantic loft near historic center",
|
|
113
|
+
"Lovely sun light in a stylish loft, Downtown Spot",
|
|
114
|
+
"Charming & Sunny Mezzanine Loft",
|
|
115
|
+
"Brand New Luxury Downtown Studio",
|
|
116
|
+
"Be Happy in Porto",
|
|
117
|
+
"Quarry Apartment",
|
|
118
|
+
"Loft with balcony and view of Casa da Música PORTO",
|
|
119
|
+
"For 4 or 6 - Wonderful Apartment downtown",
|
|
120
|
+
"Clérigos Apartments - Apt. 4E for 2/3 Pax",
|
|
121
|
+
"Bright Top Floor Two Rooms Apartment w/ Terrace",
|
|
122
|
+
"ReUrban Flats - Santa Catarina #3",
|
|
123
|
+
"The Blue and White Porto House - Vintage",
|
|
124
|
+
"4twoLoft at Great Location",
|
|
125
|
+
"Step In Porto - Loft w/Mezzanine",
|
|
126
|
+
"Your OWM Invicta",
|
|
127
|
+
"Pury Apartments",
|
|
128
|
+
"Live Porto & Douro - Breiner III",
|
|
129
|
+
],
|
|
130
|
+
);
|
|
131
|
+
console.timeEnd("query4");
|
|
132
|
+
}
|
|
133
|
+
function query5(qyDB) {
|
|
134
|
+
console.time("query5");
|
|
135
|
+
assert.deepEqual(
|
|
136
|
+
qyDB
|
|
137
|
+
.queryFiles(
|
|
138
|
+
"airbnb1",
|
|
139
|
+
{
|
|
140
|
+
$or: [
|
|
141
|
+
{
|
|
142
|
+
property_type: "Loft",
|
|
143
|
+
room_type: "Entire home/apt",
|
|
144
|
+
bed_type: "Real Bed",
|
|
145
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
146
|
+
},
|
|
147
|
+
{ property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
3,
|
|
151
|
+
)
|
|
152
|
+
.map((x) => x.view(["name"]).name),
|
|
153
|
+
[
|
|
154
|
+
"Porto city centre apartment H",
|
|
155
|
+
"Romantic loft near historic center",
|
|
156
|
+
"Lovely sun light in a stylish loft, Downtown Spot",
|
|
157
|
+
],
|
|
158
|
+
);
|
|
159
|
+
console.timeEnd("query5");
|
|
160
|
+
}
|
|
161
|
+
function query6(qyDB) {
|
|
162
|
+
console.time("query6");
|
|
163
|
+
assert.deepEqual(
|
|
164
|
+
qyDB
|
|
165
|
+
.queryFiles(
|
|
166
|
+
"airbnb1",
|
|
167
|
+
{
|
|
168
|
+
$or: [
|
|
169
|
+
{
|
|
170
|
+
property_type: "Loft",
|
|
171
|
+
room_type: "Entire home/apt",
|
|
172
|
+
bed_type: "Real Bed",
|
|
173
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
174
|
+
},
|
|
175
|
+
{ property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 },
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
20,
|
|
179
|
+
10,
|
|
180
|
+
)
|
|
181
|
+
.map((x) => x.view(["name"]).name),
|
|
182
|
+
[
|
|
183
|
+
"Bright Top Floor Two Rooms Apartment w/ Terrace",
|
|
184
|
+
"ReUrban Flats - Santa Catarina #3",
|
|
185
|
+
"The Blue and White Porto House - Vintage",
|
|
186
|
+
"4twoLoft at Great Location",
|
|
187
|
+
"Step In Porto - Loft w/Mezzanine",
|
|
188
|
+
"Your OWM Invicta",
|
|
189
|
+
"Pury Apartments",
|
|
190
|
+
"Live Porto & Douro - Breiner III",
|
|
191
|
+
],
|
|
192
|
+
);
|
|
193
|
+
console.timeEnd("query6");
|
|
194
|
+
}
|
|
195
|
+
function query7(qyDB) {
|
|
196
|
+
console.time("query7");
|
|
197
|
+
assert.deepEqual(
|
|
198
|
+
qyDB
|
|
199
|
+
.queryFiles("airbnb1", { property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 })
|
|
200
|
+
.map((x) => x.view(["name"]).name),
|
|
201
|
+
["Romantic loft near historic center", "Brand New Luxury Downtown Studio"],
|
|
202
|
+
);
|
|
203
|
+
console.timeEnd("query7");
|
|
204
|
+
}
|
|
205
|
+
function query8(qyDB) {
|
|
206
|
+
console.time("query8");
|
|
207
|
+
assert.deepEqual(
|
|
208
|
+
qyDB
|
|
209
|
+
.queryFiles("airbnb1", { property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 }, 10, 10)
|
|
210
|
+
.map((x) => x.view(["name"]).name),
|
|
211
|
+
[],
|
|
212
|
+
);
|
|
213
|
+
console.timeEnd("query8");
|
|
214
|
+
}
|
|
215
|
+
function query9(qyDB) {
|
|
216
|
+
console.time("query9");
|
|
217
|
+
assert.deepEqual(
|
|
218
|
+
qyDB
|
|
219
|
+
.queryFiles(
|
|
220
|
+
"airbnb1",
|
|
221
|
+
{
|
|
222
|
+
$or: [
|
|
223
|
+
{
|
|
224
|
+
property_type: "Loft",
|
|
225
|
+
room_type: "Entire home/apt",
|
|
226
|
+
bed_type: "Real Bed",
|
|
227
|
+
address: { street: "Porto, Porto, Portugal" },
|
|
228
|
+
},
|
|
229
|
+
{ property_type: (x) => x == "Loft", minimum_nights: (x) => x >= 60 },
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
3,
|
|
233
|
+
)
|
|
234
|
+
.map((x) => x.view(["name"]).name),
|
|
235
|
+
[
|
|
236
|
+
"Porto city centre apartment H",
|
|
237
|
+
"Romantic loft near historic center",
|
|
238
|
+
"Lovely sun light in a stylish loft, Downtown Spot",
|
|
239
|
+
],
|
|
240
|
+
);
|
|
241
|
+
console.timeEnd("query9");
|
|
242
|
+
}
|
|
243
|
+
function runQueries(qyDB) {
|
|
244
|
+
query1(qyDB);
|
|
245
|
+
query1(qyDB);
|
|
246
|
+
query2(qyDB);
|
|
247
|
+
query2(qyDB);
|
|
248
|
+
query3(qyDB);
|
|
249
|
+
query3(qyDB);
|
|
250
|
+
query4(qyDB);
|
|
251
|
+
query4(qyDB);
|
|
252
|
+
query5(qyDB);
|
|
253
|
+
query5(qyDB);
|
|
254
|
+
query6(qyDB);
|
|
255
|
+
query6(qyDB);
|
|
256
|
+
query7(qyDB);
|
|
257
|
+
query7(qyDB);
|
|
258
|
+
query8(qyDB);
|
|
259
|
+
query8(qyDB);
|
|
260
|
+
query9(qyDB);
|
|
261
|
+
query9(qyDB);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Object.assign(module.exports, { runQueries });
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const https = require("https");
|
|
3
|
+
const { ensureParentDir, folderOrFileExists } = require("../src/QyUtils.js");
|
|
4
|
+
const { logger } = require("../src/QyLogger.js");
|
|
5
|
+
|
|
6
|
+
async function downloadFile(fileUrl, filePath) {
|
|
7
|
+
if (await folderOrFileExists(filePath)) return;
|
|
8
|
+
await ensureParentDir(filePath);
|
|
9
|
+
let resolve, reject;
|
|
10
|
+
const promise = new Promise((res, rej) => {
|
|
11
|
+
resolve = res;
|
|
12
|
+
reject = rej;
|
|
13
|
+
});
|
|
14
|
+
https
|
|
15
|
+
.get(fileUrl, (response) => {
|
|
16
|
+
if (response.statusCode !== 200) {
|
|
17
|
+
logger.error(`Download failed: Status Code ${response.statusCode}`);
|
|
18
|
+
reject(response.statusCode);
|
|
19
|
+
} else {
|
|
20
|
+
const fileStream = fs.createWriteStream(filePath);
|
|
21
|
+
let accu = 0;
|
|
22
|
+
response.on("data", (chunk) => {
|
|
23
|
+
fileStream.write(chunk);
|
|
24
|
+
accu += chunk.length;
|
|
25
|
+
if (accu >= 1000_000) {
|
|
26
|
+
process.stdout.write(".");
|
|
27
|
+
accu = 0;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
response.on("end", () => {
|
|
31
|
+
fileStream.close();
|
|
32
|
+
resolve();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
.on("error", (err) => {
|
|
37
|
+
logger.error(`Request error: ${err.message}`);
|
|
38
|
+
reject(err.message);
|
|
39
|
+
});
|
|
40
|
+
return promise;
|
|
41
|
+
}
|
|
42
|
+
Object.assign(module.exports, { downloadFile });
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const path = require("node:path");
|
|
2
|
+
const { QyDB } = require("./QyDB.js");
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
port: 3629,
|
|
6
|
+
qyDBDataFolder: "./tmp/QyExpress",
|
|
7
|
+
staticRoot: path.join(__dirname, "../static/"),
|
|
8
|
+
rpcFolder: path.join(__dirname, "rpc"),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const { port, qyDBDataFolder } = config;
|
|
12
|
+
const app = require("express")();
|
|
13
|
+
const qyDB = new QyDB(qyDBDataFolder);
|
|
14
|
+
|
|
15
|
+
let server;
|
|
16
|
+
process.on("SIGINT", async () => {
|
|
17
|
+
logger.log("SIGINT signal received: closing HTTP server");
|
|
18
|
+
if (server) {
|
|
19
|
+
server.close(() => logger.log("HTTP server closed"));
|
|
20
|
+
server.closeAllConnections();
|
|
21
|
+
}
|
|
22
|
+
await qyDB.stop();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
run();
|
|
26
|
+
|
|
27
|
+
async function run() {
|
|
28
|
+
try {
|
|
29
|
+
await qyDB.start();
|
|
30
|
+
server = app.listen(port, () => {
|
|
31
|
+
logger.log(`Example app listening on port ${port}`);
|
|
32
|
+
});
|
|
33
|
+
app.get("/", (request, reply) => {
|
|
34
|
+
reply.send({ hello: "world from express" });
|
|
35
|
+
});
|
|
36
|
+
app.get("/test", (request, reply) => {
|
|
37
|
+
qyDB.insert("users/test", { a: 3, b: 4 });
|
|
38
|
+
const content = qyDB.view("users/test");
|
|
39
|
+
reply.send(content);
|
|
40
|
+
logger.log(content);
|
|
41
|
+
});
|
|
42
|
+
} catch (exception) {
|
|
43
|
+
logger.error(exception);
|
|
44
|
+
await qyDB.stop();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const fsPromises = require("node:fs/promises");
|
|
4
|
+
const fastifyStatic = require("@fastify/static");
|
|
5
|
+
const fastifyCompress = require("@fastify/compress");
|
|
6
|
+
const { QyDB } = require("../src/QyDB.js");
|
|
7
|
+
const { folderOrFileExists } = require("../src/QyUtils.js");
|
|
8
|
+
|
|
9
|
+
const config = {
|
|
10
|
+
port: 3628,
|
|
11
|
+
staticRoot: path.join(__dirname, "../static/"),
|
|
12
|
+
rpcFolder: path.join(__dirname, "../src/rpc"),
|
|
13
|
+
};
|
|
14
|
+
const { port, staticRoot } = config;
|
|
15
|
+
|
|
16
|
+
const fastify = require("fastify")({ logger: false, forceCloseConnections: true });
|
|
17
|
+
|
|
18
|
+
const qyDB = new QyDB();
|
|
19
|
+
|
|
20
|
+
let sigintReceived = false;
|
|
21
|
+
|
|
22
|
+
process.on("SIGINT", async () => {
|
|
23
|
+
logger.log("SIGINT signal received: closing HTTP server");
|
|
24
|
+
if (!sigintReceived) {
|
|
25
|
+
sigintReceived = true;
|
|
26
|
+
await fastify.close();
|
|
27
|
+
await qyDB.stop();
|
|
28
|
+
logger.log("All closed");
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
run();
|
|
33
|
+
|
|
34
|
+
async function insertRpcs() {
|
|
35
|
+
const { rpcFolder } = config;
|
|
36
|
+
if (await folderOrFileExists(rpcFolder)) {
|
|
37
|
+
await Promise.all(
|
|
38
|
+
(await fsPromises.readdir(rpcFolder)).map(async (x) => {
|
|
39
|
+
qyDB.insertRpc(path.basename(x, ".js"), (await fsPromises.readFile(path.join(rpcFolder, x))).toString());
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function handleGet(request, reply) {
|
|
46
|
+
const { query, params } = request;
|
|
47
|
+
const result = await qyDB.callRpc(params.funName, JSON.parse(query.args));
|
|
48
|
+
if (Error.isError(result)) {
|
|
49
|
+
logger.warn(result.message);
|
|
50
|
+
}
|
|
51
|
+
return reply.send(result);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function handlePost(request, reply) {
|
|
55
|
+
logger.log("handling post", request.body);
|
|
56
|
+
reply.send({ body: request.body });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function run() {
|
|
60
|
+
try {
|
|
61
|
+
await qyDB.start();
|
|
62
|
+
await insertRpcs();
|
|
63
|
+
await fastify.register(fastifyStatic, { root: staticRoot });
|
|
64
|
+
await fastify.register(fastifyCompress);
|
|
65
|
+
fastify.get("/rpc/:funName", handleGet);
|
|
66
|
+
fastify.post("/rpc/:funName", handlePost);
|
|
67
|
+
fastify.listen({ port }, (err) => {
|
|
68
|
+
if (err) {
|
|
69
|
+
logger.error(err);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
} else {
|
|
72
|
+
logger.log(`Example app listening on port ${port}`);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
} catch (exception) {
|
|
76
|
+
logger.error(exception);
|
|
77
|
+
await qyDB.stop();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// node --prof profile.js
|
|
2
|
+
// node --prof-process isolate-0xnnnnnnnnnnnn-v8.log > processed.txt
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const { rm } = require("node:fs/promises");
|
|
6
|
+
const { QyDB } = require("../src/QyDB.js");
|
|
7
|
+
const { folderOrFileExists } = require("../src/QyUtils.js");
|
|
8
|
+
const { runQueries } = require("./flights_queries.js");
|
|
9
|
+
|
|
10
|
+
logger.level = "info";
|
|
11
|
+
|
|
12
|
+
const arangoJsonFolderPath = "../GraphCourse_DemoData_ArangoDB-2";
|
|
13
|
+
const dataFolder = "./tmp/flights";
|
|
14
|
+
|
|
15
|
+
const qyDB = new QyDB(dataFolder, { preloadFoldersAtStart: false });
|
|
16
|
+
|
|
17
|
+
run();
|
|
18
|
+
|
|
19
|
+
function insertAirports() {
|
|
20
|
+
const data = JSON.parse(fs.readFileSync(path.join(arangoJsonFolderPath, "airports.json")));
|
|
21
|
+
console.time("insertAirports");
|
|
22
|
+
const { batch } = qyDB;
|
|
23
|
+
for (const record of data) {
|
|
24
|
+
batch.insert(`airports/${record._key}`, record);
|
|
25
|
+
}
|
|
26
|
+
batch.run();
|
|
27
|
+
console.timeEnd("insertAirports");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function insertFlights() {
|
|
31
|
+
const data = JSON.parse(fs.readFileSync(path.join(arangoJsonFolderPath, "flights.json")));
|
|
32
|
+
console.time("insertFlights");
|
|
33
|
+
const { batch } = qyDB;
|
|
34
|
+
for (let i = 0; i < data.length; ++i) {
|
|
35
|
+
const record = data[i];
|
|
36
|
+
// const filePath = `flights/${record._from}/${record._to}/${i}`;
|
|
37
|
+
const filePath = `flights/${i}`;
|
|
38
|
+
batch.insert(filePath, record);
|
|
39
|
+
}
|
|
40
|
+
batch.run();
|
|
41
|
+
console.timeEnd("insertFlights");
|
|
42
|
+
console.time("createIndex");
|
|
43
|
+
// qyDB.createIndex("flights", ["_from", "_to"]);
|
|
44
|
+
qyDB.createIndex("flights", ["_from", "_to", "Month", "Day", "Year"]);
|
|
45
|
+
console.timeEnd("createIndex");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function run() {
|
|
49
|
+
console.time("total");
|
|
50
|
+
if (process.argv[3]) {
|
|
51
|
+
logger.level = process.argv[3];
|
|
52
|
+
}
|
|
53
|
+
let shouldInsertData;
|
|
54
|
+
if (process.argv[2] == "true") {
|
|
55
|
+
try {
|
|
56
|
+
await rm(dataFolder, { recursive: true });
|
|
57
|
+
} catch (exception) {}
|
|
58
|
+
shouldInsertData = true;
|
|
59
|
+
} else if (!(await folderOrFileExists(dataFolder))) shouldInsertData = true;
|
|
60
|
+
console.time("run");
|
|
61
|
+
console.time("start");
|
|
62
|
+
await qyDB.start();
|
|
63
|
+
console.timeEnd("start");
|
|
64
|
+
if (shouldInsertData) {
|
|
65
|
+
insertAirports();
|
|
66
|
+
insertFlights();
|
|
67
|
+
}
|
|
68
|
+
// console.log(qyDB.dir("/%/index/0dJIntKA55/_from").subdirNameList);
|
|
69
|
+
runQueries(qyDB);
|
|
70
|
+
console.time("stop");
|
|
71
|
+
await qyDB.stop();
|
|
72
|
+
console.timeEnd("stop");
|
|
73
|
+
console.timeEnd("run");
|
|
74
|
+
console.timeEnd("total");
|
|
75
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// node --prof profile.js
|
|
2
|
+
// node --prof-process isolate-0xnnnnnnnnnnnn-v8.log > processed.txt
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const { rm } = require("node:fs/promises");
|
|
6
|
+
const { QyDB } = require("../src/QyDB.js");
|
|
7
|
+
const { folderOrFileExists } = require("../src/QyUtils.js");
|
|
8
|
+
const { runQueries } = require("./flights2_queries.js");
|
|
9
|
+
|
|
10
|
+
logger.level = "info";
|
|
11
|
+
|
|
12
|
+
const arangoJsonFolderPath = "../GraphCourse_DemoData_ArangoDB-2";
|
|
13
|
+
const dataFolder = "./tmp/flights2";
|
|
14
|
+
const qyDB = new QyDB(dataFolder, { preloadFoldersAtStart: false });
|
|
15
|
+
|
|
16
|
+
run();
|
|
17
|
+
|
|
18
|
+
function insertAirports() {
|
|
19
|
+
const data = JSON.parse(fs.readFileSync(path.join(arangoJsonFolderPath, "airports.json")));
|
|
20
|
+
console.time("insertAirports");
|
|
21
|
+
const { batch } = qyDB;
|
|
22
|
+
for (const record of data) {
|
|
23
|
+
const { country, state, city } = record;
|
|
24
|
+
batch.insert(`airports/${country}/${state}/${city}/${record._key}`, record);
|
|
25
|
+
}
|
|
26
|
+
batch.run();
|
|
27
|
+
console.timeEnd("insertAirports");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function insertFlights() {
|
|
31
|
+
const data = JSON.parse(fs.readFileSync(path.join(arangoJsonFolderPath, "flights.json")));
|
|
32
|
+
console.time("insertFlights");
|
|
33
|
+
const { batch } = qyDB;
|
|
34
|
+
for (let i = 0; i < data.length; ++i) {
|
|
35
|
+
const record = data[i];
|
|
36
|
+
const { Year, Month, Day } = record;
|
|
37
|
+
batch.insert(`flights/${Year}/${Month}/${Day}/${i}`, record);
|
|
38
|
+
// batch.insertP(["flights", Year, Month, Day, i], record);
|
|
39
|
+
}
|
|
40
|
+
batch.run();
|
|
41
|
+
console.timeEnd("insertFlights");
|
|
42
|
+
console.time("createFlightsIndex");
|
|
43
|
+
// qyDB.createIndex("flights", ["_from", "_to"]);
|
|
44
|
+
for (const yearDir of qyDB.dir("flights").subdirList) {
|
|
45
|
+
for (const monthDir of yearDir.subdirList) {
|
|
46
|
+
for (const dayDir of monthDir.subdirList) {
|
|
47
|
+
batch.createIndex(dayDir, ["_from", "_to"]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
batch.run();
|
|
52
|
+
console.timeEnd("createFlightsIndex");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function run() {
|
|
56
|
+
console.time("total");
|
|
57
|
+
if (process.argv[3]) {
|
|
58
|
+
logger.level = process.argv[3];
|
|
59
|
+
}
|
|
60
|
+
let shouldInsertData;
|
|
61
|
+
if (process.argv[2] == "true") {
|
|
62
|
+
try {
|
|
63
|
+
await rm(dataFolder, { recursive: true });
|
|
64
|
+
} catch (exception) {}
|
|
65
|
+
shouldInsertData = true;
|
|
66
|
+
} else if (!(await folderOrFileExists(dataFolder))) shouldInsertData = true;
|
|
67
|
+
console.time("run");
|
|
68
|
+
console.time("start");
|
|
69
|
+
await qyDB.start();
|
|
70
|
+
console.timeEnd("start");
|
|
71
|
+
if (shouldInsertData) {
|
|
72
|
+
insertAirports();
|
|
73
|
+
insertFlights();
|
|
74
|
+
}
|
|
75
|
+
runQueries(qyDB);
|
|
76
|
+
console.time("stop");
|
|
77
|
+
await qyDB.stop();
|
|
78
|
+
console.timeEnd("stop");
|
|
79
|
+
console.timeEnd("run");
|
|
80
|
+
console.timeEnd("total");
|
|
81
|
+
}
|