implement remaining logic
Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
parent
e1bf97704a
commit
1ce811d566
41 changed files with 1393 additions and 408 deletions
|
|
@ -1,4 +1,33 @@
|
|||
#include "number_property.hpp"
|
||||
|
||||
#include <cppbase/result.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property.h>
|
||||
|
||||
#include <objects/properties/property_source.hpp>
|
||||
#include <objects/properties/util.hpp>
|
||||
#include <values/value.hpp>
|
||||
|
||||
IkarusNumberProperty::IkarusNumberProperty(IkarusProject * project, IkarusId id):
|
||||
IkarusProperty{project, id, this} {}
|
||||
|
||||
IkarusNumberProperty * ikarus_number_property_create(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
struct IkarusPropertySource * property_source,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
return ikarus::util::create_property<IkarusNumberProperty>(project, name, property_source, error_out);
|
||||
}
|
||||
|
||||
IkarusNumberValue * ikarus_number_property_get_default_value(IkarusNumberProperty * property, IkarusErrorData * error_out) {
|
||||
return ikarus::util::get_default_value<IkarusNumberProperty>(property, error_out);
|
||||
}
|
||||
|
||||
void ikarus_number_property_set_default_value(
|
||||
IkarusNumberProperty * property,
|
||||
IkarusNumberValue * new_default_value,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
ikarus::util::set_default_value<IkarusNumberProperty>(property, new_default_value, error_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <ikarus/objects/properties/property_type.h>
|
||||
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <values/number_value.hpp>
|
||||
|
||||
struct IkarusNumberProperty : IkarusProperty {
|
||||
public:
|
||||
using value_type = IkarusNumberValue;
|
||||
constexpr auto static PropertyType = IkarusPropertyType_Number;
|
||||
|
||||
struct IkarusNumberProperty final : IkarusProperty {
|
||||
public:
|
||||
IkarusNumberProperty(struct IkarusProject * project, IkarusId id);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
#include <cppbase/logger.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property.h>
|
||||
#include <ikarus/objects/properties/property_type.h>
|
||||
|
||||
#include <errors.hpp>
|
||||
#include <objects/properties/property_source.hpp>
|
||||
#include <persistence/project.hpp>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -11,101 +13,66 @@
|
|||
|
||||
IkarusProperty::IkarusProperty(IkarusProject * project, IkarusId id, Data data):
|
||||
IkarusObject{project, id},
|
||||
_data{data} {}
|
||||
data{data} {}
|
||||
|
||||
IkarusProperty::Data & IkarusProperty::get_data() {
|
||||
return _data;
|
||||
}
|
||||
IKA_API void ikarus_property_delete(IkarusProperty * property, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(property, );
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, );
|
||||
|
||||
IkarusProperty::Data const & IkarusProperty::get_data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
cppbase::Result<IkarusPropertyType, sqlitecpp::SingleQueryError> IkarusProperty::get_property_type(IkarusProject * project, IkarusId id) {
|
||||
VTRY(
|
||||
auto const type,
|
||||
project->db->query_one<int>("SELECT `type` FROM `properties` WHERE `id` = ?", id).on_error([project](auto const & err) {
|
||||
project->set_error(
|
||||
fmt::format("failed to fetch unboxed property type: {}", err),
|
||||
true,
|
||||
IkarusErrorInfo_Source_SubSystem,
|
||||
IkarusErrorInfo_Type_SubSystem_Database
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
return cppbase::ok(static_cast<IkarusPropertyType>(type));
|
||||
}
|
||||
|
||||
IKA_API void ikarus_property_delete(IkarusProperty * property) {
|
||||
TRYRV(
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
,
|
||||
property->project->db->execute("DELETE FROM `objects` WHERE `id` = ?", property->id).on_error([property](auto const & err) {
|
||||
property->project->set_error(
|
||||
fmt::format("failed to delete property from objects table: {}", err),
|
||||
true,
|
||||
IkarusErrorInfo_Source_SubSystem,
|
||||
IkarusErrorInfo_Type_SubSystem_Database
|
||||
);
|
||||
})
|
||||
"unable to delete property: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
property->project->db->execute("DELETE FROM `objects` WHERE `id` = ?", property->id)
|
||||
);
|
||||
|
||||
property->project->uncache(property);
|
||||
}
|
||||
|
||||
IkarusPropertyType ikarus_property_get_type(IkarusProperty const * property) {
|
||||
return IkarusProperty::get_property_type(property->project, property->id).unwrap_value_or(IkarusPropertyType_Toggle);
|
||||
IkarusPropertyType ikarus_property_get_type(IkarusProperty const * property, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(property, IkarusPropertyType_Toggle);
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, IkarusPropertyType_Toggle);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto const ret,
|
||||
IkarusPropertyType_Toggle,
|
||||
"unable to fetch property type from database: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
property->project->db->query_one<int>("SELECT `type` FROM `properties` WHERE `id` = ?", property->id)
|
||||
);
|
||||
|
||||
return static_cast<IkarusPropertyType>(ret);
|
||||
}
|
||||
|
||||
IkarusPropertySource const * ikarus_property_get_source(IkarusProperty const * property) {
|
||||
VTRYRV(
|
||||
IkarusPropertySource const * ikarus_property_get_source(IkarusProperty const * property, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(property, nullptr);
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, nullptr);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto const source,
|
||||
nullptr,
|
||||
property->project->db
|
||||
->query_one<int>("SELECT `source` FROM `properties` WHERE `id` = ?", property->id)
|
||||
.on_error([property](auto const & err) {
|
||||
property->project->set_error(
|
||||
fmt::format("failed to fetch property's source: {}", err),
|
||||
true,
|
||||
IkarusErrorInfo_Source_SubSystem,
|
||||
IkarusErrorInfo_Type_SubSystem_Database
|
||||
);
|
||||
})
|
||||
"unable to fetch property source from database: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
property->project->db->query_one<IkarusId>("SELECT `source` FROM `properties` WHERE `id` = ?", property->id)
|
||||
);
|
||||
|
||||
switch (ikarus_id_get_object_type(source)) {
|
||||
case IkarusObjectType_Blueprint: return new IkarusPropertySource{property->project->get_blueprint(source)};
|
||||
case IkarusObjectType_Entity: return new IkarusPropertySource{property->project->get_entity(source)};
|
||||
default: {
|
||||
property->project->set_error(
|
||||
fmt::format("PropertySource is neither blueprint nor entity"),
|
||||
true,
|
||||
IkarusErrorInfo_Source_LibIkarus,
|
||||
IkarusErrorInfo_Type_LibIkarus_InvalidState
|
||||
default:
|
||||
IKARUS_FAIL(
|
||||
nullptr,
|
||||
fmt::format("invalid property source type: {}", ikarus_object_type_to_string(ikarus_id_get_object_type(source))),
|
||||
IkarusErrorInfo_LibIkarus_InvalidState
|
||||
);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IkarusValue * ikarus_property_get_default_value(IkarusProperty const * property) {
|
||||
VTRYRV(
|
||||
auto const value,
|
||||
nullptr,
|
||||
property->project->db
|
||||
->query_one<int>("SELECT `default_value` FROM `properties` WHERE `id` = ?", property->id)
|
||||
.on_error([property](auto const & err) {
|
||||
property->project->set_error(
|
||||
fmt::format("failed to fetch property's default value: {}", err),
|
||||
true,
|
||||
IkarusErrorInfo_Source_SubSystem,
|
||||
IkarusErrorInfo_Type_SubSystem_Database
|
||||
);
|
||||
})
|
||||
);
|
||||
IkarusValue * ikarus_property_get_default_value(IkarusProperty const * property, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(property, nullptr);
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, nullptr);
|
||||
|
||||
return IkarusValue::from_json(value).unwrap_value_or(nullptr);
|
||||
return fetch_value_from_db(property->project, error_out, "SELECT `default_value` FROM `properties` WHERE `id` = ?", property->id);
|
||||
}
|
||||
|
||||
void ikarus_property_visit(
|
||||
|
|
@ -113,15 +80,19 @@ void ikarus_property_visit(
|
|||
void (*toggle_property_visitor)(struct IkarusToggleProperty *, void *),
|
||||
void (*number_property_visitor)(struct IkarusNumberProperty *, void *),
|
||||
void (*text_property_visitor)(struct IkarusTextProperty *, void *),
|
||||
void * data
|
||||
void * data,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(property, );
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, );
|
||||
|
||||
std::visit(
|
||||
cppbase::overloaded{
|
||||
[toggle_property_visitor, data](IkarusToggleProperty * property) { toggle_property_visitor(property, data); },
|
||||
[number_property_visitor, data](IkarusNumberProperty * property) { number_property_visitor(property, data); },
|
||||
[text_property_visitor, data](IkarusTextProperty * property) { text_property_visitor(property, data); }
|
||||
},
|
||||
property->get_data()
|
||||
property->data
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -130,18 +101,24 @@ void ikarus_property_visit_const(
|
|||
void (*toggle_property_visitor)(struct IkarusToggleProperty const *, void *),
|
||||
void (*number_property_visitor)(struct IkarusNumberProperty const *, void *),
|
||||
void (*text_property_visitor)(struct IkarusTextProperty const *, void *),
|
||||
void * data
|
||||
void * data,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(property, );
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, );
|
||||
|
||||
std::visit(
|
||||
cppbase::overloaded{
|
||||
[toggle_property_visitor, data](IkarusToggleProperty const * property) { toggle_property_visitor(property, data); },
|
||||
[number_property_visitor, data](IkarusNumberProperty const * property) { number_property_visitor(property, data); },
|
||||
[text_property_visitor, data](IkarusTextProperty const * property) { text_property_visitor(property, data); }
|
||||
},
|
||||
property->get_data()
|
||||
property->data
|
||||
);
|
||||
}
|
||||
|
||||
// No existence checks here for performance reasons. All methods on IkarusObject perform this check anyway.
|
||||
|
||||
IkarusObject * ikarus_property_to_object(IkarusProperty * property) {
|
||||
return static_cast<IkarusObject *>(property);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,23 +2,12 @@
|
|||
|
||||
#include <variant>
|
||||
|
||||
#include <cppbase/result.hpp>
|
||||
|
||||
#include <sqlitecpp/errors.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property_type.h>
|
||||
|
||||
#include <objects/object.hpp>
|
||||
|
||||
struct IkarusProperty : IkarusObject {
|
||||
public:
|
||||
using Data = std::variant<struct IkarusToggleProperty *, struct IkarusNumberProperty *, struct IkarusTextProperty *>;
|
||||
|
||||
public:
|
||||
/// \brief Helper to fetch a type for a property that isn't yet wrapped in an object
|
||||
[[nodiscard]] static cppbase::Result<IkarusPropertyType, sqlitecpp::SingleQueryError>
|
||||
get_property_type(struct IkarusProject * project, IkarusId id);
|
||||
|
||||
public:
|
||||
IkarusProperty(struct IkarusProject * project, IkarusId id, Data data);
|
||||
|
||||
|
|
@ -31,9 +20,5 @@ public:
|
|||
~IkarusProperty() override = default;
|
||||
|
||||
public:
|
||||
[[nodiscard]] Data & get_data();
|
||||
[[nodiscard]] Data const & get_data() const;
|
||||
|
||||
private:
|
||||
Data _data;
|
||||
Data data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,10 +3,22 @@
|
|||
#include <boost/functional/overloaded_function.hpp>
|
||||
|
||||
#include <objects/blueprint.hpp>
|
||||
#include <objects/entity.hpp>
|
||||
#include <cppbase/templates.hpp>
|
||||
|
||||
IkarusPropertySource::IkarusPropertySource(Data data):
|
||||
data{data} {}
|
||||
|
||||
IkarusId IkarusPropertySource::get_id() const {
|
||||
return boost::variant2::visit(
|
||||
cppbase::overloaded {
|
||||
[](IkarusBlueprint const * blueprint) { return blueprint->id; },
|
||||
[](IkarusEntity const * entity) { return entity->id; }
|
||||
},
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
IkarusPropertySource * ikarus_property_source_create_blueprint(IkarusBlueprint * blueprint) {
|
||||
return new IkarusPropertySource{blueprint};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/variant2.hpp>
|
||||
|
||||
#include <ikarus/id.h>
|
||||
#include <ikarus/objects/properties/property_source.h>
|
||||
|
||||
struct IkarusPropertySource {
|
||||
|
|
@ -19,6 +19,9 @@ public:
|
|||
|
||||
virtual ~IkarusPropertySource() = default;
|
||||
|
||||
public:
|
||||
[[nodiscard]] IkarusId get_id() const;
|
||||
|
||||
public:
|
||||
Data data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,33 @@
|
|||
#include "text_property.hpp"
|
||||
|
||||
#include <cppbase/result.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property.h>
|
||||
|
||||
#include <objects/properties/property_source.hpp>
|
||||
#include <objects/properties/util.hpp>
|
||||
#include <values/value.hpp>
|
||||
|
||||
IkarusTextProperty::IkarusTextProperty(IkarusProject * project, IkarusId id):
|
||||
IkarusProperty{project, id, this} {}
|
||||
|
||||
IkarusTextProperty * ikarus_text_property_create(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
struct IkarusPropertySource * property_source,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
return ikarus::util::create_property<IkarusTextProperty>(project, name, property_source, error_out);
|
||||
}
|
||||
|
||||
IkarusTextValue * ikarus_text_property_get_default_value(IkarusTextProperty * property, IkarusErrorData * error_out) {
|
||||
return ikarus::util::get_default_value<IkarusTextProperty>(property, error_out);
|
||||
}
|
||||
|
||||
void ikarus_text_property_set_default_value(
|
||||
IkarusTextProperty * property,
|
||||
IkarusTextValue * new_default_value,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
ikarus::util::set_default_value<IkarusTextProperty>(property, new_default_value, error_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <ikarus/objects/properties/property_type.h>
|
||||
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <values/text_value.hpp>
|
||||
|
||||
struct IkarusTextProperty : IkarusProperty {
|
||||
public:
|
||||
using value_type = IkarusTextValue;
|
||||
constexpr auto static PropertyType = IkarusPropertyType_Text;
|
||||
|
||||
struct IkarusTextProperty final : IkarusProperty {
|
||||
public:
|
||||
IkarusTextProperty(struct IkarusProject * project, IkarusId id);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,33 @@
|
|||
#include "toggle_property.hpp"
|
||||
|
||||
#include <cppbase/result.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property.h>
|
||||
|
||||
#include <objects/properties/property_source.hpp>
|
||||
#include <objects/properties/util.hpp>
|
||||
#include <values/value.hpp>
|
||||
|
||||
IkarusToggleProperty::IkarusToggleProperty(IkarusProject * project, IkarusId id):
|
||||
IkarusProperty{project, id, this} {}
|
||||
|
||||
IkarusToggleProperty *
|
||||
ikarus_toggle_property_create(struct IkarusProject * project, char const * name, struct IkarusPropertySource * property_source) {}
|
||||
IkarusToggleProperty * ikarus_toggle_property_create(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
struct IkarusPropertySource * property_source,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
return ikarus::util::create_property<IkarusToggleProperty>(project, name, property_source, error_out);
|
||||
}
|
||||
|
||||
IkarusToggleValue * ikarus_toggle_property_get_default_value(struct IkarusToggleProperty * property, IkarusErrorData * error_out) {
|
||||
return ikarus::util::get_default_value<IkarusToggleProperty>(property, error_out);
|
||||
}
|
||||
|
||||
void ikarus_toggle_property_set_default_value(
|
||||
struct IkarusToggleProperty * property,
|
||||
struct IkarusToggleValue * new_default_value,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
ikarus::util::set_default_value<IkarusToggleProperty>(property, new_default_value, error_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <ikarus/objects/properties/property_type.h>
|
||||
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <values/toggle_value.hpp>
|
||||
|
||||
struct IkarusToggleProperty : IkarusProperty {
|
||||
public:
|
||||
using value_type = IkarusToggleValue;
|
||||
constexpr auto static PropertyType = IkarusPropertyType_Toggle;
|
||||
|
||||
public:
|
||||
IkarusToggleProperty(struct IkarusProject * project, IkarusId id);
|
||||
};
|
||||
|
|
|
|||
100
src/objects/properties/util.hpp
Normal file
100
src/objects/properties/util.hpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
#include <cppbase/strings.hpp>
|
||||
|
||||
#include <ikarus/objects/properties/property.h>
|
||||
|
||||
#include <errors.hpp>
|
||||
#include <objects/properties/property.hpp>
|
||||
#include <objects/properties/property_source.hpp>
|
||||
#include <persistence/project.hpp>
|
||||
#include <values/value.hpp>
|
||||
|
||||
namespace ikarus::util {
|
||||
template<typename T>
|
||||
T * create_property(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
struct IkarusPropertySource * property_source,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(project, nullptr);
|
||||
IKARUS_FAIL_IF_NULL(name, nullptr);
|
||||
IKARUS_FAIL_IF_NULL(property_source, nullptr);
|
||||
IKARUS_FAIL_IF(
|
||||
cppbase::is_empty_or_blank(name),
|
||||
nullptr,
|
||||
fmt::format("{} name cannot be empty or blank", boost::typeindex::type_id<T>().pretty_name()),
|
||||
IkarusErrorInfo_Client_InvalidInput
|
||||
)
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
IkarusId const id,
|
||||
nullptr,
|
||||
"failed to create property: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
project->db->transact([name, property_source](auto * db) -> cppbase::Result<IkarusId, sqlitecpp::TransactionError> {
|
||||
TRY(db->execute("INSERT INTO `objects`(`type`, `name`) VALUES(?, ?, ?)", IkarusObjectType_Property, name));
|
||||
auto id = ikarus_id_from_data_and_type(db->last_insert_rowid(), IkarusObjectType_Property);
|
||||
TRY(db->execute(
|
||||
"INSERT INTO `properties`(`id`, `type`, `source`) VALUES(?, ?, ?)",
|
||||
id,
|
||||
T::PropertyType,
|
||||
property_source->get_id()
|
||||
));
|
||||
return cppbase::ok(id);
|
||||
})
|
||||
);
|
||||
|
||||
auto * ret = dynamic_cast<T *>(project->get_property(id, T::PropertyType));
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
ret == nullptr,
|
||||
nullptr,
|
||||
fmt::format("created {} cannot be casted down from IkarusProject", boost::typeindex::type_id<T>().pretty_name()),
|
||||
IkarusErrorInfo_LibIkarus_InvalidState
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename T::value_type * get_default_value(IkarusProperty const * property, IkarusErrorData * error_out) {
|
||||
auto * value = ikarus_property_get_default_value(property, error_out);
|
||||
IKARUS_FAIL_IF_ERROR(nullptr);
|
||||
|
||||
auto * ret = boost::variant2::get_if<typename T::value_type *>(&value->data);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
ret == nullptr,
|
||||
nullptr,
|
||||
fmt::format(
|
||||
"{} default value is not a(n) {}",
|
||||
boost::typeindex::type_id<T>().pretty_name(),
|
||||
boost::typeindex::type_id<typename T::value_type>().pretty_name()
|
||||
),
|
||||
IkarusErrorInfo_Database_InvalidState
|
||||
);
|
||||
|
||||
return *ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_default_value(T * property, typename T::value_type * new_default_value, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(property, );
|
||||
IKARUS_FAIL_IF_OBJECT_MISSING(property, );
|
||||
IKARUS_FAIL_IF_NULL(new_default_value, );
|
||||
|
||||
auto value_json_str = boost::json::serialize(new_default_value->to_json());
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
,
|
||||
"unable to set property default value: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
property->project->db->execute("UPDATE `properties` SET `default_value` = ? WHERE `id` = ?", value_json_str, property->id)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace ikarus::util
|
||||
Loading…
Add table
Add a link
Reference in a new issue