4#include "Stroika/Foundation/StroikaPreComp.h"
10#include "Stroika/Foundation/Common/GUID.h"
23using namespace Characters;
24using namespace Containers;
26using namespace DataExchange;
27using namespace Database;
28using namespace Database::Document::LocalDocumentDB;
29using namespace Execution;
57 const shared_ptr<MemoryDatabaseRep_> fConnectionRep_;
60 MyCollectionRep_ (
const shared_ptr<MemoryDatabaseRep_>& connectionRep,
const String& collectionName)
61 : fConnectionRep_{connectionRep}
62 , fTableName_{collectionName}
67#if USE_NOISY_TRACE_IN_THIS_MODULE_
70 optional<VariantValue> vID = v.
Lookup (Document::kID);
71 Require (not vID.has_value () or fConnectionRep_->fOptions_.fAddAllowsExternallySpecifiedIDs);
72 auto rwLock = fConnectionRep_->fCollections_.rwget ();
73 CollectionRep_ collection = rwLock.cref ().LookupValue (fTableName_);
77 doc2Add.
Remove (Document::kID);
79 collection.Add (
id, doc2Add);
80 rwLock.rwref ().Add (fTableName_, collection);
81 return id.ToString ();
83 virtual optional<Document::Document> Get (
const IDType&
id,
const optional<Projection>& projection)
override
85#if USE_NOISY_TRACE_IN_THIS_MODULE_
88 auto r = fConnectionRep_->fCollections_->LookupValue (fTableName_).Lookup (
GUID{
id});
90 r->Add (Document::kID,
id);
92 if (projection and r) {
93 r = projection->Apply (*r);
99#if USE_NOISY_TRACE_IN_THIS_MODULE_
100 TraceContextBumper ctx{
"LocalDocumentDB::MemoryDatabaseRep_::MyCollectionRep_::GetAll",
"filter={}, projection={}"_f, filter, projection};
102 return fConnectionRep_->fCollections_->LookupValue (fTableName_)
105 d.
Add (Document::kID, kvp.fKey.ToString ());
106 if (filter and not filter->Matches (d)) {
111 d = projection->
Apply (d);
119#if USE_NOISY_TRACE_IN_THIS_MODULE_
120 TraceContextBumper ctx{
"LocalDocumentDB::MemoryDatabaseRep_::MyCollectionRep_::Update"};
123 if (onlyTheseFields) {
128 auto rwLock = fConnectionRep_->fCollections_.rwget ();
129 CollectionRep_ collection = rwLock.cref ().LookupChecked (fTableName_, kExcept1_);
132 if (onlyTheseFields) {
133 d2Update.
AddAll (uploadDoc);
138 collection.Add (
id, d2Update);
139 rwLock.rwref ().Add (fTableName_, collection);
141 virtual void Remove (
const IDType&
id)
override
143#if USE_NOISY_TRACE_IN_THIS_MODULE_
144 TraceContextBumper ctx{
"LocalDocumentDB::MemoryDatabaseRep_::MyCollectionRep_::Remove"};
146 auto rwLock = fConnectionRep_->fCollections_.rwget ();
147 if (optional<CollectionRep_> oc = rwLock.cref ().Lookup (fTableName_)) {
148 CollectionRep_ c = *oc;
149 if (c.RemoveIf (
id)) {
150 rwLock.rwref ().Add (fTableName_, c);
157 virtual void Commit ()
override
161 virtual void Rollback ()
override
165 virtual Disposition GetDisposition ()
const override
167 return Disposition::eCompleted;
171 MemoryDatabaseRep_ () =
delete;
172 MemoryDatabaseRep_ (
const MemoryDatabaseRep_&) =
delete;
179 virtual shared_ptr<const EngineProperties> GetEngineProperties ()
const override
182 virtual String GetEngineName ()
const override
184 return "LocalDocumentDB.MemoryDB"sv;
187 static const shared_ptr<const EngineProperties> kProps_ = Memory::MakeSharedPtr<const MyEngineProperties_> ();
190 virtual Database::Document::Connection::Options GetOptions ()
const override
200 auto rwLock = fCollections_.
rwget ();
201 if (not rwLock.cref ().Lookup (name)) {
202 rwLock.rwref ().Add (name, {});
204 return GetCollection (name);
206 virtual void DropCollection (
const String& name)
override
208 auto rwLock = fCollections_.
rwget ();
209 rwLock.rwref ().RemoveIf (name);
213 Require (fCollections_.
load ().ContainsKey (name));
215 Memory::MakeSharedPtr<MyCollectionRep_> (Debug::UncheckedDynamicPointerCast<MemoryDatabaseRep_> (shared_from_this ()), name)};
229 const filesystem::path fExternalFile_;
230 shared_ptr<MemoryDatabaseRep_> fMemoryDB_;
235 const shared_ptr<SingleFileDatabaseRep_> fDBRep_;
236 shared_ptr<Database::Document::Collection::IRep> fDelegateToInMemoryDB_;
238 MyCollectionRep_ (
const shared_ptr<SingleFileDatabaseRep_>& dbRep,
const shared_ptr<Database::Document::Collection::IRep>& delgateImplTo)
240 , fDelegateToInMemoryDB_{delgateImplTo}
245#if USE_NOISY_TRACE_IN_THIS_MODULE_
246 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::MyCollectionRep_::Add"};
248 [[maybe_unused]]
auto rwLock = fDBRep_->fMemoryDB_->fCollections_.rwget ();
249 auto id = fDelegateToInMemoryDB_->Add (v);
250 fDBRep_->DoWriteToFS ();
253 virtual optional<Document::Document> Get (
const IDType&
id,
const optional<Projection>& projection)
override
255#if USE_NOISY_TRACE_IN_THIS_MODULE_
256 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::MyCollectionRep_::Get"};
258 return fDelegateToInMemoryDB_->Get (
id, projection);
262#if USE_NOISY_TRACE_IN_THIS_MODULE_
263 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::MyCollectionRep_::GetAll",
"filter={}, projection={}"_f,
266 return fDelegateToInMemoryDB_->GetAll (filter, projection);
270#if USE_NOISY_TRACE_IN_THIS_MODULE_
271 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::MyCollectionRep_::Update"};
273 [[maybe_unused]]
auto rwLock = fDBRep_->fMemoryDB_->fCollections_.rwget ();
274 fDelegateToInMemoryDB_->Update (
id, newV, onlyTheseFields);
275 fDBRep_->DoWriteToFS ();
277 virtual void Remove (
const IDType&
id)
override
279#if USE_NOISY_TRACE_IN_THIS_MODULE_
280 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::MyCollectionRep_::Remove"};
282 [[maybe_unused]]
auto rwLock = fDBRep_->fMemoryDB_->fCollections_.rwget ();
283 fDelegateToInMemoryDB_->Remove (
id);
284 fDBRep_->DoWriteToFS ();
289 virtual void Commit ()
override
293 virtual void Rollback ()
override
297 virtual Disposition GetDisposition ()
const override
299 return Disposition::eCompleted;
303 SingleFileDatabaseRep_ () =
delete;
304 SingleFileDatabaseRep_ (
const SingleFileDatabaseRep_&) =
delete;
306 const Document::LocalDocumentDB::Options::SingleFileStorage& sfOptions)
307 : fExternalFile_{sfOptions.fFile}
308 , fMemoryDB_{make_shared<MemoryDatabaseRep_> (options)}
309 , fReader_{get<DataExchange::Variant::Reader> (sfOptions.fSerialization)}
310 , fWriter_{get<DataExchange::Variant::Writer> (sfOptions.fSerialization)}
314 virtual shared_ptr<const EngineProperties> GetEngineProperties ()
const override
317 virtual String GetEngineName ()
const override
319 return "LocalDocumentDB.SingleFile"sv;
322 static const shared_ptr<const EngineProperties> kProps_ = Memory::MakeSharedPtr<const MyEngineProperties_> ();
325 virtual Database::Document::Connection::Options GetOptions ()
const override
327 return fMemoryDB_->GetOptions ();
331 return fMemoryDB_->GetCollections ();
335 [[maybe_unused]]
auto rwLock = fMemoryDB_->fCollections_.rwget ();
336 fMemoryDB_->CreateCollection (name);
338 return GetCollection (name);
340 virtual void DropCollection (
const String& name)
override
342 [[maybe_unused]]
auto rwLock = fMemoryDB_->fCollections_.rwget ();
343 fMemoryDB_->DropCollection (name);
350 Debug::UncheckedDynamicPointerCast<SingleFileDatabaseRep_> (shared_from_this ()), memDBCollection)};
358 using namespace IO::FileSystem;
359#if USE_NOISY_TRACE_IN_THIS_MODULE_
360 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::DoReadFromFS",
"path={}"_f, fExternalFile_};
362 if (filesystem::exists (fExternalFile_)) {
363 auto rwLock = fMemoryDB_->fCollections_.rwget ();
364 rwLock.rwref ().clear ();
367 rwLock.rwref ().Add (collectionAndDocument.fKey,
370 return {GUID{kvp.fKey}, kvp.fValue.As<Document::Document> ()};
377#if USE_NOISY_TRACE_IN_THIS_MODULE_
378 TraceContextBumper ctx{
"LocalDocumentDB::SingleFileDatabaseRep_::DoWriteToFS",
"path={}"_f, fExternalFile_};
380 using namespace IO::FileSystem;
381 ThroughTmpFileWriter tmpFile{fExternalFile_};
382 IO::FileSystem::FileOutputStream::Ptr outStream = IO::FileSystem::FileOutputStream::New (tmpFile.GetFilePath ());
388 collWithStringKey.
Add (kvp.fKey.ToString (),
VariantValue{kvp.fValue});
390 collectionsAsVV.
Add (collection.fKey,
VariantValue{collWithStringKey});
401 const filesystem::path fRoot_;
406 const shared_ptr<DirectoryFilesystemDatabaseRep_> fDBRep_;
408 const filesystem::path fCollectionRoot_;
410 MyCollectionRep_ (
const shared_ptr<DirectoryFilesystemDatabaseRep_>& dbRep,
const String& name)
413 , fCollectionRoot_{dbRep->GetCollectionFilePath_ (name)}
418#if USE_NOISY_TRACE_IN_THIS_MODULE_
419 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::MyCollectionRep_::Add"};
421 optional<VariantValue> vID = v.
Lookup (Document::kID);
422 Require (not vID.has_value () or fDBRep_->fOptions_.fAddAllowsExternallySpecifiedIDs);
426 doc2Add.
Remove (Document::kID);
431 virtual optional<Document::Document> Get (
const IDType&
id,
const optional<Projection>& projection)
override
433#if USE_NOISY_TRACE_IN_THIS_MODULE_
434 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::MyCollectionRep_::Get"};
436 if (
auto od = DoReadFromFS_ (
GUID{
id})) {
438 d.
Add (Document::kID,
id);
440 d = projection->
Apply (d);
450#if USE_NOISY_TRACE_IN_THIS_MODULE_
451 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::MyCollectionRep_::GetAll",
452 "filter={}, projection={}"_f, filter, projection};
455 for (
const auto& entry : filesystem::directory_iterator{fCollectionRoot_}) {
456 if (entry.path ().extension () ==
".json"sv) {
458 fDBRep_->fReader_.Read (IO::FileSystem::FileInputStream::New (entry.path ())).
As<
Document::Document> ();
459 d.
Add (Document::kID, entry.path ().stem ().string ());
460 if (not filter or filter->Matches (d)) {
462 d = projection->
Apply (d);
472#if USE_NOISY_TRACE_IN_THIS_MODULE_
473 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::MyCollectionRep_::Update",
474 "id={},newV={}, onlyTheseFields={}"_f, id, newV, onlyTheseFields};
477 onlyTheseFields ? Memory::ValueOfOrThrow (DoReadFromFS_ (
id),
RuntimeErrorException{
"no such id"sv}) : newV;
479 if (onlyTheseFields) {
480 updateWithDoc.
RetainAll (*onlyTheseFields);
482 updatedDoc.
AddAll (updateWithDoc);
483 if (onlyTheseFields) {
490 virtual void Remove (
const IDType&
id)
override
492#if USE_NOISY_TRACE_IN_THIS_MODULE_
493 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::MyCollectionRep_::Remove",
"id={}"_f,
id};
495 (void)filesystem::remove (GetDocumentFilePath_ (
GUID{
id}));
497 filesystem::path GetDocumentFilePath_ (
const GUID&
id)
const
499 return fCollectionRoot_ / (
id.As<
String> () +
".json"sv).As<filesystem::path> ();
501 optional<Document::Document> DoReadFromFS_ (
const GUID&
id)
503 using namespace IO::FileSystem;
504 filesystem::path docFilePath = GetDocumentFilePath_ (
id);
505#if USE_NOISY_TRACE_IN_THIS_MODULE_
506 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::DoReadFromFS",
"path={}"_f, docFilePath};
508 if (filesystem::exists (docFilePath)) {
509 return fDBRep_->fReader_.Read (FileInputStream::New (docFilePath)).As<
Document::Document> ();
515 filesystem::path docFilePath = GetDocumentFilePath_ (
id);
516#if USE_NOISY_TRACE_IN_THIS_MODULE_
517 TraceContextBumper ctx{
"LocalDocumentDB::DirectoryFilesystemDatabaseRep_::DoWriteToFS()",
"path={}"_f, docFilePath};
519 using namespace IO::FileSystem;
520 ThroughTmpFileWriter tmpFile{docFilePath};
521 IO::FileSystem::FileOutputStream::Ptr outStream = IO::FileSystem::FileOutputStream::New (tmpFile.GetFilePath ());
522 fDBRep_->fWriter_.Write (vv, outStream);
529 virtual void Commit ()
override
533 virtual void Rollback ()
override
537 virtual Disposition GetDisposition ()
const override
539 return Disposition::eCompleted;
543 filesystem::path GetCollectionFilePath_ (
const String& collectionName)
const
547 return fRoot_ / (collectionName.
As<filesystem::path> ());
550 DirectoryFilesystemDatabaseRep_ () =
delete;
551 DirectoryFilesystemDatabaseRep_ (
const DirectoryFilesystemDatabaseRep_&) =
delete;
553 const Document::LocalDocumentDB::Options::DirectoryFileStorage& dfOptions)
555 , fRoot_{dfOptions.fRoot}
556 , fReader_{get<DataExchange::Variant::Reader> (dfOptions.fSerialization)}
557 , fWriter_{get<DataExchange::Variant::Writer> (dfOptions.fSerialization)}
559 filesystem::create_directories (fRoot_);
561 virtual shared_ptr<const EngineProperties> GetEngineProperties ()
const override
564 virtual String GetEngineName ()
const override
566 return "LocalDocumentDB.Folder"sv;
569 static const shared_ptr<const EngineProperties> kProps_ = Memory::MakeSharedPtr<const MyEngineProperties_> ();
572 virtual Database::Document::Connection::Options GetOptions ()
const override
579 for (
const auto& entry : filesystem::directory_iterator{fRoot_}) {
580 if (filesystem::is_directory (entry.path ())) {
581 result +=
String{entry.path ().filename ()};
588 filesystem::create_directories (GetCollectionFilePath_ (name));
590 Debug::UncheckedDynamicPointerCast<DirectoryFilesystemDatabaseRep_> (shared_from_this ()), name)};
592 virtual void DropCollection (
const String& name)
override
594 filesystem::remove_all (GetCollectionFilePath_ (name));
598 Require (GetCollections ().Contains (name));
600 Debug::UncheckedDynamicPointerCast<DirectoryFilesystemDatabaseRep_> (shared_from_this ()), name)};
614auto Document::LocalDocumentDB::New (
const Options& options) ->
Ptr
616 if (get_if<Options::MemoryStorage> (&options.fStorage)) {
617 return Ptr{Memory::MakeSharedPtr<MemoryDatabaseRep_> (options)};
619 else if (
auto fop = get_if<Options::SingleFileStorage> (&options.fStorage)) {
620 return Ptr{Memory::MakeSharedPtr<SingleFileDatabaseRep_> (options, *fop)};
622 else if (
auto dop = get_if<Options::DirectoryFileStorage> (&options.fStorage)) {
623 return Ptr{Memory::MakeSharedPtr<DirectoryFilesystemDatabaseRep_> (options, *dop)};
#define AssertNotImplemented()
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual CONTAINER_OF_Key_T As() const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
nonvirtual mapped_type LookupChecked(ArgByValueType< key_type > key, const THROW_IF_MISSING &throwIfMissing) const
nonvirtual unsigned int AddAll(ITERABLE_OF_ADDABLE &&items, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual bool RemoveIf(ArgByValueType< key_type > key)
Remove the given item, if it exists. Return true if found and removed.
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so container template defaults to Mapping, and improve that ca...
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
nonvirtual Iterable< key_type > Keys() const
nonvirtual void RetainAll(const ITERABLE_OF_KEY_TYPE &items)
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
abstract class specifying interface for readers that map a source like XML or JSON to a VariantValue ...
abstract class specifying interface for writers VariantValue objects to serialized formats like JSON,...
nonvirtual void Write(const VariantValue &v, const Streams::OutputStream::Ptr< byte > &out) const
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
virtual Collection::Ptr CreateCollection(const String &name)=0
virtual Transaction mkTransaction()=0
EngineProperties captures the features associated with a given database engine (being talked to throu...
define a (simple) projection on a document, subsetting the fields of that document.
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
nonvirtual WritableReference rwget()
get a read-write smart pointer to the underlying Synchronized<> object, holding the full lock the who...
nonvirtual T load() const
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
static GUID GenerateNew() noexcept