Added DocumentStoreCore
Added DocumentStoreEngine Added Addon::isSharedDocument
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define CONNECTOR_DATABASE_MODEL_CARD_DATABASE
|
||||
|
||||
#include "Active/Serialise/Package/Package.h"
|
||||
#include "Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h"
|
||||
#include "Speckle/Utility/String.h"
|
||||
|
||||
namespace connector::database {
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
#include "Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h"
|
||||
|
||||
#include "Active/Utility/Memory.h"
|
||||
#include "Active/Utility/String.h"
|
||||
#include "Speckle/Environment/Addon.h"
|
||||
#include "Speckle/Utility/Guid.h"
|
||||
#include "Speckle/Utility/String.h"
|
||||
|
||||
#ifdef ARCHICAD
|
||||
#include <ACAPinc.h>
|
||||
#include <BM.hpp>
|
||||
#endif
|
||||
|
||||
using namespace active::setting;
|
||||
using namespace speckle::database;
|
||||
using namespace speckle::environment;
|
||||
using namespace speckle::utility;
|
||||
|
||||
using enum DocumentStoreCore::Status;
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef ARCHICAD
|
||||
/*--------------------------------------------------------------------
|
||||
Convert an Archicad API error code to a DocumentStoreCore status
|
||||
|
||||
acErrorCode: The API error code
|
||||
|
||||
return: An equivalent status code
|
||||
--------------------------------------------------------------------*/
|
||||
DocumentStoreCore::Status convertArchicadError(long acErrorCode) {
|
||||
using enum DocumentStoreCore::Status;
|
||||
switch (acErrorCode) {
|
||||
case NoError:
|
||||
return nominal;
|
||||
case APIERR_BADPARS:
|
||||
return badParameter;
|
||||
case APIERR_BADID:
|
||||
return badID;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
} //convertArchicadError
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Determine if a specified data store exists
|
||||
|
||||
id: The store identity
|
||||
|
||||
return: True if the store exists
|
||||
--------------------------------------------------------------------*/
|
||||
bool isExistingStore(active::utility::NameID& storeID) {
|
||||
if (storeID.id)
|
||||
return true; //We must have a store if the ID is populated
|
||||
bool isStoreFound = false;
|
||||
#ifdef ARCHICAD
|
||||
API_Guid acID;
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_GetObjectGuidFromName(String{storeID.name}, &acID)); statusCode != nominal)
|
||||
throw std::system_error(DocumentStoreCore::makeError(statusCode));
|
||||
storeID.id = Guid{acID};
|
||||
isStoreFound = true;
|
||||
#endif
|
||||
return isStoreFound;
|
||||
} //isExistingStore
|
||||
|
||||
#endif
|
||||
|
||||
///Category for DocumentStore processing errors
|
||||
class DocumentStoreCategory : public std::error_category {
|
||||
public:
|
||||
///Category name
|
||||
const char* name() const noexcept override {
|
||||
return "active::database::sqlite::category";
|
||||
}
|
||||
/*!
|
||||
Get a message for a specified error code
|
||||
@param errorCode A DocumentStore processing code
|
||||
@return The error message for the specified code
|
||||
*/
|
||||
std::string message(int errorCode) const override {
|
||||
//TODO: These error messages are ok for developers - but can we help users more?
|
||||
switch (static_cast<DocumentStoreCore::Status>(errorCode)) {
|
||||
case nominal:
|
||||
return "";
|
||||
case badParameter:
|
||||
return "An internal function has been incorrectly used";
|
||||
case badID:
|
||||
return "Internal data has been requested using an invalid identity";
|
||||
case error:
|
||||
return "A non-specific error occurred";
|
||||
default:
|
||||
return "An unknown error occurred";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///DocumentStore processing category error instance
|
||||
static DocumentStoreCategory instance;
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Make an error code for DocumentStore processing
|
||||
|
||||
return: An STL error code
|
||||
--------------------------------------------------------------------*/
|
||||
std::error_code DocumentStoreCore::makeError(DocumentStoreCore::Status code) {
|
||||
return std::error_code(static_cast<int>(code), instance);
|
||||
} //DocumentStoreCore::makeError
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Read the data stored in the document
|
||||
|
||||
return: The stored data (empty if the data doesn't exist)
|
||||
--------------------------------------------------------------------*/
|
||||
active::utility::Memory DocumentStoreCore::readStore() const {
|
||||
active::utility::Memory result;
|
||||
//First establish that we actually have stored data to read
|
||||
if (!isExistingStore(m_id))
|
||||
return result;
|
||||
//Read the stored data
|
||||
#ifdef ARCHICAD
|
||||
GS::UniString storeName{String{m_id.name}};
|
||||
GSHandle storedData;
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_GetObjectContent(Guid{m_id.id}, &storeName, &storedData)); statusCode != nominal)
|
||||
throw std::system_error(makeError(statusCode));
|
||||
//Copy the stored data into the result
|
||||
auto storeSize = BMGetHandleSize(storedData);
|
||||
result.resize(storeSize);
|
||||
active::utility::Memory::copy(result.data(), *storedData, storeSize, storeSize);
|
||||
BMKillHandle(&storedData);
|
||||
#endif
|
||||
return result;
|
||||
} //DocumentStoreCore::readStore
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Write the data to document storage
|
||||
|
||||
toWrite: The data to write to storage
|
||||
--------------------------------------------------------------------*/
|
||||
void DocumentStoreCore::writeStore() {
|
||||
#ifdef ARCHICAD
|
||||
//Ensure a suitable data store exists
|
||||
if (!isExistingStore(m_id)) {
|
||||
//Create when missing
|
||||
API_Guid acID;
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_CreateUniqueObject(String{m_id.name}, &acID)); statusCode != nominal)
|
||||
throw std::system_error(makeError(statusCode));
|
||||
m_id = Guid{acID};
|
||||
}
|
||||
//Reserve the storage object in TW
|
||||
if (addon()->isSharedDocument()) {
|
||||
GS::HashTable<API_Guid, short> conflicts;
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ReserveObjects({Guid{m_id.id}}, &conflicts)); statusCode != nominal)
|
||||
throw std::system_error(makeError(statusCode));
|
||||
//TODO: Implamenent handling for conflicts
|
||||
}
|
||||
auto toWrite = buildStore();
|
||||
//Write the new data
|
||||
GSHandle output = BMAllocateHandle(static_cast<GSSize>(toWrite.size()), ALLOCATE_CLEAR, 0);
|
||||
active::utility::Memory::copy(*output, toWrite.data(), toWrite.size(), toWrite.size());
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ModifyObject({Guid{m_id.id}}, nullptr, &output)); statusCode != nominal)
|
||||
throw std::system_error(makeError(statusCode));
|
||||
BMKillHandle(&output);
|
||||
//Release the storage object in TW
|
||||
if (addon()->isSharedDocument()) {
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ReleaseObjects({Guid{m_id.id}})); statusCode != nominal)
|
||||
throw std::system_error(makeError(statusCode));
|
||||
}
|
||||
#endif
|
||||
} //DocumentStoreCore::writeStore
|
||||
@@ -0,0 +1,91 @@
|
||||
#ifndef SPECKLE_DATABASE_DOCUMENT_STORE_CORE
|
||||
#define SPECKLE_DATABASE_DOCUMENT_STORE_CORE
|
||||
|
||||
#include "Active/File/Path.h"
|
||||
#include "Active/Setting/SettingList.h"
|
||||
#include "Active/Database/Storage/DBaseSchema.h"
|
||||
#include "Active/Utility/NameID.h"
|
||||
|
||||
namespace speckle::database {
|
||||
|
||||
/*!
|
||||
Core functionality and definitions for a mechanism to store data in a BIM (3rd-party) document/database
|
||||
|
||||
Currently implement for Archicad Add-On Objects
|
||||
*/
|
||||
class DocumentStoreCore {
|
||||
public:
|
||||
|
||||
// MARK: - Types
|
||||
|
||||
///Status of of the DocumentStore database
|
||||
enum class Status {
|
||||
nominal, ///<No errors logged
|
||||
badParameter, ///<The data supplied to an SDK function call was invalid
|
||||
badID, ///<The ID for the stored data is invalid
|
||||
error, ///<An unidentified error occurred
|
||||
};
|
||||
|
||||
// MARK: - Static functions
|
||||
|
||||
/*!
|
||||
Make an error code for DocumentStore processing
|
||||
@return An STL error code
|
||||
*/
|
||||
static std::error_code makeError(DocumentStoreCore::Status code);
|
||||
|
||||
// MARK: - Constructors
|
||||
|
||||
/*!
|
||||
Default constructor
|
||||
@param id The document storage identifier
|
||||
*/
|
||||
DocumentStoreCore(const active::utility::NameID& id) : m_id(id) {}
|
||||
/*!
|
||||
Destructor
|
||||
*/
|
||||
virtual ~DocumentStoreCore() {}
|
||||
|
||||
// MARK: - Function (const)
|
||||
|
||||
/*!
|
||||
Get the database id
|
||||
@return The database id
|
||||
*/
|
||||
const active::utility::NameID& getID() const { return m_id; }
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Read the data stored in the document (should be lazy-loading, only at the point where data is actually requested)
|
||||
@return The stored data (empty if the data doesn't exist)
|
||||
*/
|
||||
active::utility::Memory readStore() const;
|
||||
|
||||
/*!
|
||||
Write the data to document storage (currently happens at every change - could implement delayed storage until the point of send/save)
|
||||
*/
|
||||
void writeStore();
|
||||
/*!
|
||||
Build new store data from the latest records
|
||||
@return Data to store from the latest records
|
||||
*/
|
||||
virtual active::utility::Memory buildStore() = 0;
|
||||
/*!
|
||||
Merge existing stored data with incoming stored data (from an external source)
|
||||
@param toMerge The external stored data to merge
|
||||
@return The merged data to be stored
|
||||
*/
|
||||
virtual active::utility::Memory mergeStore(const active::utility::Memory& toMerge) = 0;
|
||||
/*!
|
||||
Reset the stored data (some external change has invalidated previous data, e.g. the document was closed)
|
||||
*/
|
||||
virtual void resetStore() = 0;
|
||||
|
||||
private:
|
||||
///The database ID (mutable to allow lazy loading when data is accessed)
|
||||
mutable active::utility::NameID m_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SPECKLE_DATABASE_DOCUMENT_STORE_CORE
|
||||
@@ -0,0 +1,283 @@
|
||||
#ifndef SPECKLE_DATABASE_DOCUMENT_STORE_ENGINE
|
||||
#define SPECKLE_DATABASE_DOCUMENT_STORE_ENGINE
|
||||
|
||||
#include "Active/Database/Storage/DBaseEngine.h"
|
||||
#include "Active/Database/Storage/RecordCache.h"
|
||||
#include "Active/File/Path.h"
|
||||
#include "Active/Serialise/Cargo.h"
|
||||
#include "Active/Serialise/CargoHold.h"
|
||||
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
|
||||
#include "Active/Serialise/Transport.h"
|
||||
#include "Active/Utility/BufferIn.h"
|
||||
#include "Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h"
|
||||
#include "Speckle/Utility/Guid.h"
|
||||
#include "Speckle/Utility/String.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
namespace speckle::database {
|
||||
|
||||
///Concept for the ability to store objects in a document
|
||||
template<typename Obj, typename Transport>
|
||||
concept DocumentStorable = std::is_base_of_v<active::serialise::Cargo, Obj> &&
|
||||
std::is_base_of_v<active::serialise::Transport, Transport>;
|
||||
|
||||
/*!
|
||||
A database engine to store records in a 3rd-party BIM document
|
||||
|
||||
Due to the fact that these records are intended to represent a single table and are stored in a document, the concepts of 'table' and
|
||||
'document' aren't currently applicable (this could be extended in future if there is a use-case)
|
||||
@tparam Obj Interface for the stored object. NB: This can be a base class for an object hierarchy, not necessarily a concrete class
|
||||
@tparam Transport The serialisation transport mechanism for objects
|
||||
@tparam ObjID The object identifier type, e.g. Guid
|
||||
*/
|
||||
template<typename Obj, typename Transport, typename ObjID = utility::String>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
class DocumentStoreEngine : public DocumentStoreCore, public active::database::DBaseEngine<Obj, ObjID, utility::String, utility::String> {
|
||||
public:
|
||||
|
||||
// MARK: - Types
|
||||
|
||||
using base = active::database::DBaseEngine<Obj, ObjID, utility::String, utility::String>;
|
||||
using Filter = base::Filter;
|
||||
using Cache = active::database::RecordCache<Obj, ObjID>;
|
||||
|
||||
// MARK: - Constructors
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
@param id The document storage identifier
|
||||
*/
|
||||
DocumentStoreEngine(const active::utility::NameID& id) : DocumentStoreCore{id} {}
|
||||
/*!
|
||||
Copy constructor
|
||||
@param source The object to copy
|
||||
*/
|
||||
DocumentStoreEngine(const DocumentStoreEngine& source) : DocumentStoreCore{source}, base{source} {
|
||||
m_cache = (source.m_cache) ? std::make_unique<Cache>(*source.m_cache) : nullptr;
|
||||
}
|
||||
/*!
|
||||
Object cloning
|
||||
@return A clone of this object
|
||||
*/
|
||||
DocumentStoreEngine* clonePtr() const override { return new DocumentStoreEngine{*this}; }
|
||||
|
||||
// MARK: - Functions (const)
|
||||
|
||||
/*!
|
||||
Get an object by index
|
||||
@param ID The object ID
|
||||
@param tableID Optional table ID (defaults to the first table)
|
||||
@param documentID Optional document ID (when the object is bound to a specific document)
|
||||
@return The requested object (nullptr on failure)
|
||||
*/
|
||||
std::unique_ptr<Obj> getObject(const ObjID& ID, utility::String::Option tableID = std::nullopt, utility::String::Option documentID = std::nullopt) const override;
|
||||
/*!
|
||||
Get all objects
|
||||
@param tableID Optional table ID (defaults to the first table)
|
||||
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
|
||||
@return The requested objects (nullptr on failure)
|
||||
*/
|
||||
active::container::Vector<Obj> getObjects(utility::String::Option tableID = std::nullopt, utility::String::Option documentID = std::nullopt) const override;
|
||||
/*!
|
||||
Get a filtered list of objects
|
||||
@param filter The object filter
|
||||
@param tableID Optional table ID (defaults to the first table)
|
||||
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
|
||||
@return The filtered objects (nullptr on failure)
|
||||
*/
|
||||
active::container::Vector<Obj> getObjects(const Filter& filter, utility::String::Option tableID = std::nullopt,
|
||||
utility::String::Option documentID = std::nullopt) const override;
|
||||
/*!
|
||||
Erase an object by index
|
||||
@param ID The object ID
|
||||
@param tableID Optional table ID (defaults to the first table)
|
||||
@param documentID Optional document ID (when the object is bound to a specific document)
|
||||
@throw Exception thrown on SQL error
|
||||
*/
|
||||
void erase(const ObjID& ID, utility::String::Option tableID = std::nullopt, utility::String::Option documentID = std::nullopt) const override;
|
||||
/*!
|
||||
Erase all objects
|
||||
@param tableID Optional table ID (defaults to the first table)
|
||||
@param documentID Optional document ID (when the object is bound to a specific document)
|
||||
@throw Exception thrown on SQL error
|
||||
*/
|
||||
void erase(utility::String::Option tableID = std::nullopt, utility::String::Option documentID = std::nullopt) const override;
|
||||
protected:
|
||||
/*!
|
||||
Get the cache of records built from the data stored in the document
|
||||
@return The cached records
|
||||
*/
|
||||
Cache* getCache() const;
|
||||
/*!
|
||||
Build new store data from the latest records
|
||||
@return Data to store from the latest records
|
||||
*/
|
||||
active::utility::Memory buildStore() override;
|
||||
/*!
|
||||
Merge existing stored data with incoming stored data (from an external source)
|
||||
@param toMerge The external stored data to merge
|
||||
@return The merged data to be stored
|
||||
*/
|
||||
active::utility::Memory mergeStore(const active::utility::Memory& toMerge) override;
|
||||
/*!
|
||||
Reset the stored data (some external change has invalidated previous data, e.g. the document was closed)
|
||||
*/
|
||||
void resetStore() override { m_cache.reset(); }
|
||||
|
||||
private:
|
||||
//Cached records from the document store
|
||||
std::unique_ptr<Cache> m_cache;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Get the cache of records built from the data stored in the document
|
||||
|
||||
return: The cached records (nullptr on failure)
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
typename DocumentStoreEngine<Obj, Transport, ObjID>::Cache* DocumentStoreEngine<Obj, Transport, ObjID>::getCache() const {
|
||||
if (m_cache)
|
||||
return m_cache;
|
||||
//Read the data stored in the document
|
||||
auto storedData = readStore();
|
||||
m_cache = std::make_unique<Cache>();
|
||||
if (!storedData)
|
||||
return m_cache; //Return an empty container if there's no data
|
||||
//Import the document data into the record cache
|
||||
Transport().receive(std::forward<active::serialise::Cargo&&>(*m_cache), active::serialise::Identity{}, storedData);
|
||||
return m_cache;
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::getCache
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Get an object by index
|
||||
|
||||
index: The object index
|
||||
tableID: Optional table ID (defaults to the first table)
|
||||
documentID: Optional document ID (when the object is bound to a specific document)
|
||||
|
||||
return: The requested object (nullptr on failure)
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
std::unique_ptr<Obj> DocumentStoreEngine<Obj, Transport, ObjID>::getObject(const ObjID& ID, utility::String::Option tableID,
|
||||
utility::String::Option documentID) const {
|
||||
auto cache = getCache();
|
||||
return cache ? cache->read(ID) : nullptr;
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::getObject
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Get all objects
|
||||
|
||||
tableID: Optional table ID (defaults to the first table)
|
||||
documentID: Optional document ID (filter for this document only - nullopt = all objects)
|
||||
|
||||
return: The requested objects (nullptr on failure)
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
active::container::Vector<Obj> DocumentStoreEngine<Obj, Transport, ObjID>::getObjects(utility::String::Option tableID,
|
||||
utility::String::Option documentID) const {
|
||||
auto cache = getCache();
|
||||
return cache ? cache->read() : nullptr;
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::getObjects
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Get all objects
|
||||
|
||||
filter: The object filter
|
||||
tableID: Optional table ID (defaults to the first table)
|
||||
documentID: Optional document ID (filter for this document only - nullopt = all objects)
|
||||
|
||||
return: The requested objects (nullptr on failure)
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
active::container::Vector<Obj> DocumentStoreEngine<Obj, Transport, ObjID>::getObjects(const Filter& filter, utility::String::Option tableID,
|
||||
utility::String::Option documentID) const {
|
||||
auto cache = getCache();
|
||||
return cache ? cache->read(filter) : nullptr;
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::getObjects
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Erase an object by index
|
||||
|
||||
objID: The object ID
|
||||
tableID: Optional table ID (defaults to the first table)
|
||||
documentID: Optional document ID (when the object is bound to a specific document)
|
||||
|
||||
return: True if the object was successfully erased
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
void DocumentStoreEngine<Obj, Transport, ObjID>::erase(const ObjID& ID, utility::String::Option tableID,
|
||||
utility::String::Option documentID) const {
|
||||
auto cache = getCache();
|
||||
if (cache)
|
||||
cache->erase(ID);
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::erase
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Erase all objects
|
||||
|
||||
tableID: Optional table ID (defaults to the first table)
|
||||
documentID: Optional document ID (filter for this document only - nullopt = all objects)
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
void DocumentStoreEngine<Obj, Transport, ObjID>::erase(utility::String::Option tableID, utility::String::Option documentID) const {
|
||||
auto cache = getCache();
|
||||
if (cache)
|
||||
cache->erase();
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::erase
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Build new store data from the latest records
|
||||
|
||||
return: Data to store from the latest records
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
active::utility::Memory DocumentStoreEngine<Obj, Transport, ObjID>::buildStore() {
|
||||
active::utility::Memory result;
|
||||
auto cache = getCache();
|
||||
if (!cache)
|
||||
cache = std::make_unique<Cache>(); //We still want to export an empty cache object even if it contains no records
|
||||
//Export the cached records
|
||||
Transport().send(std::forward<active::serialise::Cargo&&>(*m_cache), active::serialise::Identity{}, result);
|
||||
return result;
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::buildStore
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Merge existing stored data with incoming stored data (from an external source)
|
||||
|
||||
toMerge: The external stored data to merge
|
||||
|
||||
return: The merged data to be stored
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
active::utility::Memory DocumentStoreEngine<Obj, Transport, ObjID>::mergeStore(const active::utility::Memory& toMerge) {
|
||||
//Import the incoming records from the data to merge
|
||||
Cache incoming;
|
||||
Transport().receive(std::forward<active::serialise::Cargo&&>(incoming), active::serialise::Identity{}, toMerge);
|
||||
//Get the data currently stored in the document
|
||||
auto cache = getCache();
|
||||
if (!cache)
|
||||
cache = std::make_unique<Cache>(); //We still want to export an empty cache object even if it contains no records
|
||||
cache->merge(incoming);
|
||||
return buildStore();
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::mergeStore
|
||||
|
||||
}
|
||||
|
||||
#endif //SPECKLE_DATABASE_DOCUMENT_STORE_ENGINE
|
||||
@@ -46,11 +46,27 @@ String Addon::getLocalString(short itemIndex, short resourceIndex) const {
|
||||
RSGetIndString(&string, itemIndex, resourceIndex, ACAPI_GetOwnResModule());
|
||||
return string;
|
||||
#else
|
||||
return String{}
|
||||
return String{};
|
||||
#endif
|
||||
} //Addon::getLocalString
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Determine if the active document is shared (in collaborative environments)
|
||||
|
||||
return: True if the active document is shared
|
||||
--------------------------------------------------------------------*/
|
||||
bool Addon::isSharedDocument() const {
|
||||
#ifdef ARCHICAD
|
||||
API_ProjectInfo pi{};
|
||||
ACAPI_ProjectOperation_Project(&pi);
|
||||
return pi.teamwork;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} //Addon::isSharedDocument
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Publish an event from an external source to subscribers
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace speckle::environment {
|
||||
@return The localised string
|
||||
*/
|
||||
speckle::utility::String getLocalString(short itemIndex, short resourceIndex) const;
|
||||
/*!
|
||||
Determine if the active document is shared (in collaborative environments)
|
||||
@return True if the active document is shared
|
||||
*/
|
||||
bool isSharedDocument() const;
|
||||
|
||||
// MARK: - Functions (mutating)
|
||||
|
||||
|
||||
@@ -102,8 +102,8 @@ namespace speckle::interfac::browser {
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename FunctionBinding>
|
||||
bool JSPortal<FunctionBinding>::install(std::shared_ptr<JSObject<FunctionBinding>> object) {
|
||||
#ifdef ARCHICAD
|
||||
try {
|
||||
#ifdef ARCHICAD
|
||||
auto engine = getJSEngine();
|
||||
if (!engine)
|
||||
return false;
|
||||
@@ -127,10 +127,10 @@ namespace speckle::interfac::browser {
|
||||
object->setPortal(*this);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
} catch(...) {
|
||||
///TODO: Need to discuss the best course of action to notify of a failure
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
} //JSPortal<FunctionBinding>::install
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ namespace speckle::utility {
|
||||
// MARK: - Constructors
|
||||
|
||||
using base::base;
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
@param source The guid to copy
|
||||
*/
|
||||
Guid(const active::utility::Guid& source) : base{source} {}
|
||||
|
||||
#ifdef ARCHICAD
|
||||
/*!
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD542C890B1C0077E104 /* ServerMigration.h */; };
|
||||
21D0BD592C8910400077E104 /* UserInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD572C8910400077E104 /* UserInfo.cpp */; };
|
||||
21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD582C8910400077E104 /* UserInfo.h */; };
|
||||
21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDAC2C8F8AB60077E104 /* DocumentStoreCore.cpp */; };
|
||||
21D0BDB42C8F8AB60077E104 /* DocumentStoreCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BDAD2C8F8AB60077E104 /* DocumentStoreCore.h */; };
|
||||
21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BDAE2C8F8AB60077E104 /* DocumentStoreEngine.h */; };
|
||||
21F69F3B2C6B880C008B6A06 /* JSBaseTransport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69F382C6B880B008B6A06 /* JSBaseTransport.cpp */; };
|
||||
21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69F4A2C6CCC25008B6A06 /* BrowserBridge.cpp */; };
|
||||
21F69F612C6D0286008B6A06 /* GetBindingsMethodNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69F602C6D0286008B6A06 /* GetBindingsMethodNames.cpp */; };
|
||||
@@ -132,6 +135,9 @@
|
||||
21D0BD542C890B1C0077E104 /* ServerMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerMigration.h; sourceTree = "<group>"; };
|
||||
21D0BD572C8910400077E104 /* UserInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserInfo.cpp; sourceTree = "<group>"; };
|
||||
21D0BD582C8910400077E104 /* UserInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserInfo.h; sourceTree = "<group>"; };
|
||||
21D0BDAC2C8F8AB60077E104 /* DocumentStoreCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentStoreCore.cpp; sourceTree = "<group>"; };
|
||||
21D0BDAD2C8F8AB60077E104 /* DocumentStoreCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentStoreCore.h; sourceTree = "<group>"; };
|
||||
21D0BDAE2C8F8AB60077E104 /* DocumentStoreEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentStoreEngine.h; sourceTree = "<group>"; };
|
||||
21F69F012C66C229008B6A06 /* Doxyfile */ = {isa = PBXFileReference; lastKnownFileType = text; name = Doxyfile; path = Documentation/Doxyfile; sourceTree = "<group>"; };
|
||||
21F69F192C6A0FE2008B6A06 /* JSBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBinding.h; sourceTree = "<group>"; };
|
||||
21F69F352C6AA9B3008B6A06 /* JSFunction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSFunction.h; sourceTree = "<group>"; };
|
||||
@@ -293,8 +299,9 @@
|
||||
children = (
|
||||
21D0BD1D2C86F0280077E104 /* AccountDatabase.cpp */,
|
||||
21D0BD1E2C86F0280077E104 /* AccountDatabase.h */,
|
||||
21D0BD302C86FE090077E104 /* Identity */,
|
||||
21D0BD272C86FC350077E104 /* Content */,
|
||||
21D0BD302C86FE090077E104 /* Identity */,
|
||||
21D0BDB02C8F8AB60077E104 /* Storage */,
|
||||
);
|
||||
path = Database;
|
||||
sourceTree = "<group>";
|
||||
@@ -318,6 +325,24 @@
|
||||
path = Identity;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
21D0BDAF2C8F8AB60077E104 /* DocumentStore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
21D0BDAC2C8F8AB60077E104 /* DocumentStoreCore.cpp */,
|
||||
21D0BDAD2C8F8AB60077E104 /* DocumentStoreCore.h */,
|
||||
21D0BDAE2C8F8AB60077E104 /* DocumentStoreEngine.h */,
|
||||
);
|
||||
path = DocumentStore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
21D0BDB02C8F8AB60077E104 /* Storage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
21D0BDAF2C8F8AB60077E104 /* DocumentStore */,
|
||||
);
|
||||
path = Storage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
21F69F1A2C6A0FE2008B6A06 /* Browser */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -447,8 +472,10 @@
|
||||
210CC88F2C81A98500610F58 /* Guid64.h in Headers */,
|
||||
21B67D002C7CE15100FD64FC /* Exception.h in Headers */,
|
||||
21D0BD2C2C86FC350077E104 /* Record.h in Headers */,
|
||||
21D0BDB42C8F8AB60077E104 /* DocumentStoreCore.h in Headers */,
|
||||
210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */,
|
||||
21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */,
|
||||
21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */,
|
||||
2193518C2C62655700E5A69C /* MenuEvent.h in Headers */,
|
||||
21D0BD312C86FE090077E104 /* Index.h in Headers */,
|
||||
);
|
||||
@@ -581,6 +608,7 @@
|
||||
21F69F812C6FF3B0008B6A06 /* BridgeArgumentWrap.cpp in Sources */,
|
||||
2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */,
|
||||
21F69F612C6D0286008B6A06 /* GetBindingsMethodNames.cpp in Sources */,
|
||||
21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */,
|
||||
21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */,
|
||||
21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */,
|
||||
21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */,
|
||||
|
||||
Reference in New Issue
Block a user