Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F7113008
datastore.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Referenced Files
None
Subscribers
None
datastore.ts
View Options
import
{
MongoClient
,
Db
,
Collection
as
MongoCollection
}
from
"mongodb"
;
import
{
App
}
from
"../main"
;
import
Collection
from
"../chip-types/collection"
;
import
{
QueryStage
}
from
"./query"
;
import
asyncForEach
from
"../utils/async-foreach"
;
import
QueryStep
from
"./query-step"
;
export
type
OutputOptions
=
Partial
<
{
skip
:
number
;
amount
:
number
;
sort
:
{
[
field_name
:
string
]
:
-
1
|
1
};
}
>
;
export
default
class
Datastore
{
client
:
MongoClient
;
db
:
Db
;
constructor
(
public
app
:
App
)
{
this
.
app
=
app
;
}
async
start
()
:
Promise
<
void
>
{
const
config
=
this
.
app
.
ConfigManager
.
get
(
"datastore_mongo"
)
as
{
host
:
string
;
port
:
number
;
db_name
:
string
;
};
const
url
=
`mongodb://
${
config
.
host
}
:
${
config
.
port
}
/
${
config
.
db_name
}
`
;
this
.
client
=
await
MongoClient
.
connect
(
url
,
{
useNewUrlParser
:
true
,
useUnifiedTopology
:
true
,
});
if
(
!
this
.
client
)
{
return
Promise
.
reject
(
"MongoDB was not found, please make sure it's installed. Check https://docs.mongodb.org/manual/tutorial/ for more info."
);
}
this
.
db
=
this
.
client
.
db
(
config
.
db_name
);
await
this
.
post_start
();
}
async
post_start
()
:
Promise
<
void
>
{
await
asyncForEach
(
Object
.
values
(
this
.
app
.
collections
),
(
collection
)
=>
this
.
create_index
(
collection
)
);
}
async
create_index
(
collection
:
Collection
)
:
Promise
<
void
>
{
const
indexes
:
{
[
field
:
string
]
:
number
}[]
=
[];
const
text_index
:
{
[
field
:
string
]
:
"text"
}
=
{};
for
(
const
field_name
in
collection
.
fields
)
{
const
index_answer
=
collection
.
fields
[
field_name
].
hasIndex
();
if
(
index_answer
===
false
)
{
continue
;
}
if
(
index_answer
===
"text"
)
{
text_index
[
field_name
]
=
"text"
;
}
else
if
(
typeof
index_answer
===
"boolean"
&&
index_answer
)
{
indexes
.
push
({
[
field_name
]
:
1
});
}
else
if
(
Array
.
isArray
(
index_answer
))
{
for
(
const
[
subfield
,
index
]
of
index_answer
)
{
const
key
=
`
${
field_name
}
.
${
subfield
as
string
}
`
;
if
(
index
===
"text"
)
{
text_index
[
key
]
=
"text"
;
}
else
if
(
index
)
{
indexes
.
push
({
[
key
]
:
1
});
}
}
}
}
const
db_collection
=
this
.
db
.
collection
(
collection
.
name
);
await
asyncForEach
(
[
...
indexes
,
...(
Object
.
keys
(
text_index
).
length
?
[
text_index
]
:
[]),
],
async
(
index
)
=>
{
await
this
.
createIndex
(
collection
.
name
,
index
).
catch
(
async
(
error
:
Error
&
{
code
?:
number
;
message
:
string
}
)
=>
{
if
(
error
&&
error
.
code
===
85
)
{
const
index_name
=
(
error
.
message
.
match
(
/name: "([^"]+)"/g
)
as
string
[])[
1
]
.
replace
(
'name: "'
,
""
)
.
replace
(
'"'
,
""
);
await
db_collection
.
dropIndex
(
index_name
);
return
this
.
createIndex
(
collection
.
name
,
index
);
}
throw
error
;
}
);
}
);
}
find
(
collection_name
:
string
,
query
:
Record
<
string
,
any
>
,
options
:
Parameters
<
MongoCollection
[
"find"
]
>
[
1
]
=
{},
output_options
:
OutputOptions
=
{}
)
{
this
.
app
.
Logger
.
debug2
(
"DB"
,
"find "
+
collection_name
,
{
query
,
options
,
},
null
);
const
cursor
=
this
.
db
.
collection
(
collection_name
).
find
(
query
,
options
);
if
(
output_options
.
sort
)
{
cursor
.
sort
(
output_options
.
sort
);
}
if
(
output_options
.
skip
)
{
cursor
.
skip
(
output_options
.
skip
);
}
if
(
output_options
.
amount
)
{
cursor
.
limit
(
output_options
.
amount
);
}
return
cursor
.
toArray
();
}
async
aggregate
(
collection_name
:
string
,
pipeline
:
QueryStage
[],
_
=
{},
output_options
:
OutputOptions
=
{}
)
:
Promise
<
Record
<
string
,
any
>
[]
>
{
const
cursor
=
this
.
db
.
collection
(
collection_name
).
aggregate
(
pipeline
);
if
(
pipeline
.
find
((
element
)
=>
element
instanceof
QueryStep
))
{
throw
new
Error
(
"Pipeline elements should be simple objects, not QuerySteps. Perhaps you should use .toPipeline()?"
);
}
this
.
app
.
Logger
.
debug2
(
"DB"
,
"Running aggregate"
,
{
collection_name
,
pipeline
,
output_options
,
},
null
);
if
(
output_options
.
sort
)
{
cursor
.
sort
(
output_options
.
sort
);
}
if
(
output_options
.
skip
)
{
cursor
.
skip
(
output_options
.
skip
);
}
if
(
output_options
.
amount
)
{
cursor
.
limit
(
output_options
.
amount
);
}
const
ret
=
await
cursor
.
toArray
();
this
.
app
.
Logger
.
debug3
(
"DB"
,
`Aggregate on collection
${
collection_name
}
returns`
,
ret
);
return
ret
as
Record
<
string
,
any
>
[];
}
async
insert
(
collection_name
:
string
,
to_insert
:
Record
<
string
,
any
>
,
options
?:
Parameters
<
MongoCollection
[
"insertOne"
]
>
[
1
]
)
{
this
.
app
.
Logger
.
debug2
(
"DB"
,
"Running insert"
,
{
collection_name
,
to_insert
,
options
,
});
const
result
=
await
this
.
db
.
collection
(
collection_name
)
.
insertOne
(
to_insert
,
options
);
return
result
.
ops
[
0
];
}
update
(
collection_name
:
string
,
query
:
any
,
new_value
:
any
)
{
this
.
app
.
Logger
.
debug2
(
"DB"
,
"Update"
,
{
collection_name
,
query
:
query
as
unknown
,
new_value
:
new_value
as
unknown
,
},
4
);
query
=
process_query
(
query
);
return
this
.
db
.
collection
(
collection_name
).
updateOne
(
query
,
new_value
);
}
async
remove
(
collection_name
:
string
,
query
:
any
,
just_one
:
boolean
)
{
this
.
app
.
Logger
.
debug2
(
"DB"
,
"remove"
,
{
collection_name
,
query
:
query
as
unknown
,
},
3
);
query
=
process_query
(
query
);
const
method
=
just_one
?
"deleteOne"
:
"deleteMany"
;
const
ret
=
await
this
.
db
.
collection
(
collection_name
)[
method
](
query
);
return
ret
;
}
createIndex
(
collection_name
:
string
,
index
:
any
,
options
?:
Parameters
<
MongoCollection
[
"createIndex"
]
>
[
1
]
)
{
const
collection
=
this
.
db
.
collection
(
collection_name
);
return
collection
.
createIndex
(
index
,
options
);
}
async
stop
()
{
return
this
.
client
?
.
close
();
}
}
function
process_query
(
query
:
Record
<
string
,
unknown
>
)
{
if
(
!
query
)
{
return
{};
}
const
new_query
:
Record
<
string
,
unknown
>
=
{};
for
(
const
attribute_name
in
query
)
{
const
value
=
query
[
attribute_name
];
if
(
attribute_name
==
"id"
)
{
new_query
[
attribute_name
]
=
value
;
continue
;
}
if
(
typeof
value
===
"object"
)
{
if
(
attribute_name
[
0
]
===
"$"
)
{
new_query
[
attribute_name
]
=
value
;
}
else
{
for
(
const
i
in
value
)
{
new_query
[
attribute_name
+
"."
+
i
]
=
(
value
as
Record
<
string
,
any
>
)[
i
];
}
}
}
else
{
new_query
[
attribute_name
]
=
query
[
attribute_name
];
}
}
return
new_query
;
}
File Metadata
Details
Attached
Mime Type
text/x-java
Expires
Fri, Jul 4, 08:33 (5 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
799861
Default Alt Text
datastore.ts (6 KB)
Attached To
Mode
rS Sealious
Attached
Detach File
Event Timeline
Log In to Comment