From 130782a91dc415b5f4856a97c7087e56e3cc5cc6 Mon Sep 17 00:00:00 2001 From: thedonkified Date: Sun, 22 Sep 2024 01:06:54 -0700 Subject: [PATCH] ndatabase refactor --- code/__DEFINES/db_defs.dm | 133 ------- code/__DEFINES/ndatabase.dm | 359 ++++++++++++++++++ code/datums/_ndatabase/code/brsql_adapter.dm | 110 +++--- .../code/brsql_persistent_connection.dm | 10 +- .../datums/_ndatabase/code/entity/db_field.dm | 7 + .../_ndatabase/code/entity/db_field_type.dm | 45 +++ code/datums/_ndatabase/code/entity/entity.dm | 1 + .../_ndatabase/code/entity/entity_meta.dm | 9 +- code/datums/_ndatabase/code/entity/link.dm | 19 +- .../_ndatabase/code/interfaces/adapter.dm | 38 +- .../subsystems/database_query_manager.dm | 108 +++--- .../_ndatabase/subsystems/entity_manager.dm | 18 +- code/datums/entities/clans.dm | 4 +- code/datums/entities/discord_link.dm | 2 +- code/datums/entities/player.dm | 4 +- code/datums/entities/player_job_ban.dm | 4 +- code/datums/entities/player_note.dm | 4 +- code/datums/entities/player_stat.dm | 2 +- code/datums/entities/player_sticky_ban.dm | 2 +- code/datums/entities/player_times.dm | 2 +- colonialmarines.dme | 4 +- 21 files changed, 594 insertions(+), 291 deletions(-) delete mode 100644 code/__DEFINES/db_defs.dm create mode 100644 code/__DEFINES/ndatabase.dm create mode 100644 code/datums/_ndatabase/code/entity/db_field.dm create mode 100644 code/datums/_ndatabase/code/entity/db_field_type.dm diff --git a/code/__DEFINES/db_defs.dm b/code/__DEFINES/db_defs.dm deleted file mode 100644 index 6665e83a2bca..000000000000 --- a/code/__DEFINES/db_defs.dm +++ /dev/null @@ -1,133 +0,0 @@ -// MIT License - -// Copyright (c) 2020 Neth Iafin - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#define DB_ENTITY SSentity_manager.select -#define DB_EKEY SSentity_manager.select_by_key -#define DB_FILTER SSentity_manager.filter_then -#define DB_FILTER_LOCAL SSentity_manager.filter_local -#define DB_META SSentity_manager.tables -#define DB_VIEW SSentity_manager.view_meta -#define WAIT_DB_READY while(!SSentity_manager.ready) {stoplag();} - -// MODIFY THESE TO ENABLE OR DISABLE DB ENGINES -#define NDATABASE_BSQL_SUPPORT TRUE -#define NDATABASE_RUSTG_BRSQL_SUPPORT TRUE - - -#define DB_LOCK_TIMEOUT 5 SECONDS -#define DB_RECHECK_TIMEOUT 1 SECONDS -#define DB_ENTITY_RECHECK_TIMEOUT 10 -#define DB_ENTITY_MAX_CONNECTIONS 30 -#define DB_ENTITY_USUAL_CONNECTIONS 20 -#define DB_QUERY_RECHECK_TIMEOUT 1 //yes, just 0.1 of a second - -#define DB_DEFAULT_ID_FIELD "id" - -#define DB_ORDER_BY_DEFAULT 0 -#define DB_ORDER_BY_ASC 1 -#define DB_ORDER_BY_DESC 2 - -#define DB_CONNECTION_NOT_CONNECTED 0 -#define DB_CONNECTION_BROKEN 1 -#define DB_CONNECTION_READY 2 -#define DB_CONNECTION_DELETED 3 - -#define DB_QUERY_STARTED 0 -#define DB_QUERY_READING 1 -#define DB_QUERY_FINISHED 2 -#define DB_QUERY_BROKEN 3 - -//DB Entity State -//this CANNOT be bit-flag - -// Something is wrong or entry is dead -#define DB_ENTITY_STATE_BROKEN -1 -// We just requested this object from the pool and we didn't specify its ID, -// or we want to change only some fields (not recommended) -// this status is set when you try to select datum from DB -// if we set to this status from Synced, We suspect that outside forces changed this record. -// We want to discard any changes WE made -#define DB_ENTITY_STATE_DETACHED 0 -// We properly requested this record, it was received from DB -// In this status we EXPECT that this datum is equivalent to whatever we have in database -#define DB_ENTITY_STATE_SYNCED 1 -// We want to add this record to database. -// Record won't be added if datum has ID set to something other than null -#define DB_ENTITY_STATE_ADDED 2 -// We want to update the record and move it to the database -#define DB_ENTITY_STATE_UPDATED 3 -// We want to delete this record -#define DB_ENTITY_STATE_DELETED 4 -// We are reading/writing about this record right now -#define DB_ENTITY_STATE_PROCESSING 5 -// We want to add this record to database. -// But then we want to detach from this record -#define DB_ENTITY_STATE_ADD_DETACH 7 -// We are unsure what is this animal. Does it exist? If it does, we add it. In any case, it should be handled somewhere else (in entity manager) -// Since this status is bigger than SYNCED, this means sync() will wait till someone handles it, which is exactly what we need -#define DB_ENTITY_STATE_ADD_OR_SELECT 8 -// This is here because Neth is bad -// Basically new item, waiting for it to be read -#define DB_ENTITY_STATE_FRESH 9 - -//field types -#define DB_FIELDTYPE_INT 1 -#define DB_FIELDTYPE_BIGINT 2 -#define DB_FIELDTYPE_CHAR 3 // 1 symbol -#define DB_FIELDTYPE_STRING_SMALL 4 // 16 symbols -#define DB_FIELDTYPE_STRING_MEDIUM 5 // 64 symbols -#define DB_FIELDTYPE_STRING_LARGE 6 // 256 symbols -#define DB_FIELDTYPE_STRING_MAX 7 // 4000 symbols -#define DB_FIELDTYPE_DATE 8 -#define DB_FIELDTYPE_TEXT 9 // any amount of symbols but really inefficient -#define DB_FIELDTYPE_BLOB 10 -#define DB_FIELDTYPE_DECIMAL 11 - -#define DB_EQUALS 0 -#define DB_NOTEQUAL 1 -#define DB_GREATER 2 -#define DB_LESS 3 -#define DB_GREATER_EQUAL 4 -#define DB_LESS_EQUAL 5 -#define DB_IS 6 // is null -#define DB_ISNOT 7 // is not null -#define DB_IN 8 -#define DB_NOTIN 9 - -// list of hints for indexes - -// this is cluster index. This means that this index sets the default order of the table -// if there are more than one cluster index on the table, you won't be able to start the app -#define DB_INDEXHINT_CLUSTER 1 - -// this is unique index. This means that if you try to add a record with same values for this set of fields -// it will fail -#define DB_INDEXHINT_UNIQUE 2 - -// list of hints for tables - -// This table is for local filtering only. Use for logs that you want to query this round -#define DB_TABLEHINT_LOCAL 1 - -#define DB_AND new /datum/db/filter/and -#define DB_OR new /datum/db/filter/or -#define DB_COMP new /datum/db/filter/comparison -#define DB_COMP2 new /datum/db/filter/compare_two diff --git a/code/__DEFINES/ndatabase.dm b/code/__DEFINES/ndatabase.dm new file mode 100644 index 000000000000..9c4f031516e8 --- /dev/null +++ b/code/__DEFINES/ndatabase.dm @@ -0,0 +1,359 @@ +// MIT License + +// Copyright (c) 2020 Neth Iafin + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#define DB_ENTITY SSentity_manager.select +#define DB_EKEY SSentity_manager.select_by_key +#define DB_FILTER SSentity_manager.filter_then +#define DB_FILTER_LOCAL SSentity_manager.filter_local +#define DB_META SSentity_manager.tables +#define DB_VIEW SSentity_manager.view_meta +#define WAIT_DB_READY while(!SSentity_manager.ready) {stoplag();} + +// MODIFY THESE TO ENABLE OR DISABLE DB ENGINES +#define NDATABASE_BSQL_SUPPORT TRUE +#define NDATABASE_RUSTG_BRSQL_SUPPORT TRUE + + +#define DB_LOCK_TIMEOUT 5 SECONDS +#define DB_RECHECK_TIMEOUT 1 SECONDS +#define DB_ENTITY_RECHECK_TIMEOUT 10 +#define DB_ENTITY_MAX_CONNECTIONS 30 +#define DB_ENTITY_USUAL_CONNECTIONS 20 +#define DB_QUERY_RECHECK_TIMEOUT 1 //yes, just 0.1 of a second + +#define DB_DEFAULT_ID_FIELD "id" + +#define DB_ORDER_BY_DEFAULT 0 +#define DB_ORDER_BY_ASC 1 +#define DB_ORDER_BY_DESC 2 + +#define DB_CONNECTION_NOT_CONNECTED 0 +#define DB_CONNECTION_BROKEN 1 +#define DB_CONNECTION_READY 2 +#define DB_CONNECTION_DELETED 3 + +#define DB_QUERY_STARTED 0 +#define DB_QUERY_READING 1 +#define DB_QUERY_FINISHED 2 +#define DB_QUERY_BROKEN 3 + +//DB Entity State +//this CANNOT be bit-flag + +// Something is wrong or entry is dead +#define DB_ENTITY_STATE_BROKEN -1 +// We just requested this object from the pool and we didn't specify its ID, +// or we want to change only some fields (not recommended) +// this status is set when you try to select datum from DB +// if we set to this status from Synced, We suspect that outside forces changed this record. +// We want to discard any changes WE made +#define DB_ENTITY_STATE_DETACHED 0 +// We properly requested this record, it was received from DB +// In this status we EXPECT that this datum is equivalent to whatever we have in database +#define DB_ENTITY_STATE_SYNCED 1 +// We want to add this record to database. +// Record won't be added if datum has ID set to something other than null +#define DB_ENTITY_STATE_ADDED 2 +// We want to update the record and move it to the database +#define DB_ENTITY_STATE_UPDATED 3 +// We want to delete this record +#define DB_ENTITY_STATE_DELETED 4 +// We are reading/writing about this record right now +#define DB_ENTITY_STATE_PROCESSING 5 +// We want to add this record to database. +// But then we want to detach from this record +#define DB_ENTITY_STATE_ADD_DETACH 7 +// We are unsure what is this animal. Does it exist? If it does, we add it. In any case, it should be handled somewhere else (in entity manager) +// Since this status is bigger than SYNCED, this means sync() will wait till someone handles it, which is exactly what we need +#define DB_ENTITY_STATE_ADD_OR_SELECT 8 +// This is here because Neth is bad +// Basically new item, waiting for it to be read +#define DB_ENTITY_STATE_FRESH 9 + +//field types +#define DB_FIELDTYPE_INT /datum/db_field_type/int +#define DB_FIELDTYPE_BIGINT /datum/db_field_type/bigint +#define DB_FIELDTYPE_CHAR /datum/db_field_type/char +#define DB_FIELDTYPE_STRING_SMALL /datum/db_field_type/string/small +#define DB_FIELDTYPE_STRING_MEDIUM /datum/db_field_type/string/medium +#define DB_FIELDTYPE_STRING_LARGE /datum/db_field_type/string/large +#define DB_FIELDTYPE_STRING_MAX /datum/db_field_type/string/max +#define DB_FIELDTYPE_DATE /datum/db_field_type/date +#define DB_FIELDTYPE_TEXT /datum/db_field_type/text +#define DB_FIELDTYPE_BLOB /datum/db_field_type/blob +#define DB_FIELDTYPE_DECIMAL /datum/db_field_type/decimal + +#define DB_EQUALS 0 +#define DB_NOTEQUAL 1 +#define DB_GREATER 2 +#define DB_LESS 3 +#define DB_GREATER_EQUAL 4 +#define DB_LESS_EQUAL 5 +#define DB_IS 6 // is null +#define DB_ISNOT 7 // is not null +#define DB_IN 8 +#define DB_NOTIN 9 + +// list of hints for indexes + +// this is cluster index. This means that this index sets the default order of the table +// if there are more than one cluster index on the table, you won't be able to start the app +#define DB_INDEXHINT_CLUSTER 1 + +// this is unique index. This means that if you try to add a record with same values for this set of fields +// it will fail +#define DB_INDEXHINT_UNIQUE 2 + +// list of hints for tables + +// This table is for local filtering only. Use for logs that you want to query this round +#define DB_TABLEHINT_LOCAL 1 + +#define DB_AND new /datum/db/filter/and +#define DB_OR new /datum/db/filter/or +#define DB_COMP new /datum/db/filter/comparison +#define DB_COMP2 new /datum/db/filter/compare_two + +// Interface for setting up entities to replace the boilerplate +/// Define an entity in database and corresponding table to store them in. +/// Can also define not part of DB-schema here (akin to SUBSYSTEM_DEF define). +#define DEFINE_ENTITY(entity, table_name) \ +/datum/db_field/##entity; \ +/datum/entity/##entity/field_type = /datum/db_field/##name; \ +/datum/entity_meta/##entity/entity_type = /datum/entity/##name; \ +/datum/entity_meta/##entity/table_name = table_name; \ +/datum/entity/##entity + +/** + * FIELD_{TYPE}(entity, field) \ + * Defines a field of type TYPE on the entity passed to the define + * + * First add the field as a variable on the entity object. + * Then add the field and its type to the entity schema stored in the + * entity's associated metadata singleton. + */ + +/** + * FIELD_DEFAULT_VALUE_{TYPE}(entity, field, default) \ + * Same as corresponding FIELD_{TYPE} define, but passes a default value + * to the entity's field on the field's initialization. Occurs on initialization + * to allow for runtime-calculated values to be passed to the field. + */ + +#define FIELD_INT(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_INT; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_INT(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_INT; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_BIGINT(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_BIGINT; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_BIGINT(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_BIGINT; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_CHAR(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_CHAR; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_CHAR(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_CHAR; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_STRING_SMALL(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_SMALL; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_STRING_SMALL(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_SMALL; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_STRING_MEDIUM(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_MEDIUM; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_STRING_MEDIUM(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_MEDIUM; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_STRING_LARGE(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_LARGE; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_STRING_LARGE(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_LARGE; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_STRING_MAX(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_MAX; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_STRING_MAX(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_STRING_MAX; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_DATE(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DATE; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_DATE(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DATE; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_DATE(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DATE; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_DATE(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DATE; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_TEXT(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_TEXT; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_TEXT(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_TEXT; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_BLOB(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_BLOB; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_BLOB(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_BLOB; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +#define FIELD_DECIMAL(entity, field) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DECIMAL; }; \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} +#define FIELD_DEFAULT_VALUE_DECIMAL(entity, field, default) \ +/datum/db_field/##entity/##field{ name = #field; field_type = DB_FIELDTYPE_DECIMAL; }; \ +/datum/db_field/##entity/##field/New() { . = ..(); value = default; } \ +/datum/entity/##entity/var/datum/db_field/##entity/##field/##field; \ +/datum/entity_meta/##entity/setup_field_types() { \ + ..(); \ + LAZYSET(field_types, #field, /datum/db_field/##entity/##field); \ +} + +/// Defines an entity link where `child_entity` refers to `parent_entity` through its column `foreign_key`. +/// `foreign_key` should NOT be a string but instead the actual foreign key field name. +#define DEFINE_ENTITY_LINK(parent_entity, child_entity, foreign_key) \ +/datum/controller/subsytem/entity_manager/get_entity_links(list/datum/entity_link/entity_links) { \ + ..(); \ + entity_links += new /datum/entity_link(parent_entity, child_entity, #foreign_key); \ +} diff --git a/code/datums/_ndatabase/code/brsql_adapter.dm b/code/datums/_ndatabase/code/brsql_adapter.dm index 2362572f588a..44824ac5a520 100644 --- a/code/datums/_ndatabase/code/brsql_adapter.dm +++ b/code/datums/_ndatabase/code/brsql_adapter.dm @@ -48,9 +48,9 @@ var/post_filter // casts, because our query is already mapped to internal `T_n` structure, while whatever the hell we get is not var/list/casts = list() - // list of pre pflds + // list of pre parameters var/list/pre_pflds - // list of post pflds + // list of post parameters var/list/post_pflds @@ -62,13 +62,13 @@ pre_pflds = _pre_pflds post_pflds = _post_pflds -// maybe pflds can be changed to named parameters? but that might take time. The contract is set, so changes here shouldn't affect your code besides performance -/datum/db/brsql_cached_query/proc/spawn_query(datum/db/filter/F, list/pflds) +// maybe parameters can be changed to named parameters? but that might take time. The contract is set, so changes here shouldn't affect your code besides performance +/datum/db/brsql_cached_query/proc/spawn_query(datum/db/filter/F, list/parameters) for(var/i in pre_pflds) - pflds.Add(i) - var/query = "[pre_filter] [adapter.get_filter(F, casts, pflds)] [post_filter]" + parameters.Add(i) + var/query = "[pre_filter] [adapter.get_filter(F, casts, parameters)] [post_filter]" for(var/i in post_pflds) - pflds.Add(i) + parameters.Add(i) return query /datum/db/adapter/brsql_adapter/sync_table_meta() @@ -93,24 +93,24 @@ SSdatabase.create_query(query_gettable, CB) /datum/db/adapter/brsql_adapter/update_table(table_name, list/values, datum/callback/CB, sync = FALSE) - var/list/qpars = list() - var/query_updatetable = getquery_update_table(table_name, values, qpars) + var/list/query_parameters = list() + var/query_updatetable = getquery_update_table(table_name, values, query_parameters) if(sync) - SSdatabase.create_parametric_query_sync(query_updatetable, qpars, CB) + SSdatabase.create_parametric_query_sync(query_updatetable, query_parameters, CB) else - SSdatabase.create_parametric_query(query_updatetable, qpars, CB) + SSdatabase.create_parametric_query(query_updatetable, query_parameters, CB) /datum/db/adapter/brsql_adapter/insert_table(table_name, list/values, datum/callback/CB, sync = FALSE) set waitfor = FALSE var/length = length(values) - var/list/qpars = list() - var/query_inserttable = getquery_insert_table(table_name, values, qpars) + var/list/query_parameters = list() + var/query_inserttable = getquery_insert_table(table_name, values, query_parameters) var/datum/callback/callback = CALLBACK(src, TYPE_PROC_REF(/datum/db/adapter/brsql_adapter, after_insert_table), CB, length, table_name) if(sync) - SSdatabase.create_parametric_query_sync(query_inserttable, qpars, callback) + SSdatabase.create_parametric_query_sync(query_inserttable, query_parameters, callback) else - SSdatabase.create_parametric_query(query_inserttable, qpars, callback) + SSdatabase.create_parametric_query(query_inserttable, query_parameters, callback) /datum/db/adapter/brsql_adapter/proc/after_insert_table(datum/callback/CB, length, table_name, uid, list/results, datum/db/query/brsql/query) CB.Invoke(query.last_insert_id) @@ -124,29 +124,29 @@ SSdatabase.create_query(query_deletetable, CB) /datum/db/adapter/brsql_adapter/read_filter(table_name, datum/db/filter, datum/callback/CB, sync = FALSE) - var/list/qpars = list() - var/query_gettable = getquery_filter_table(table_name, filter, qpars) + var/list/query_parameters = list() + var/query_gettable = getquery_filter_table(table_name, filter, query_parameters) if(sync) - SSdatabase.create_parametric_query_sync(query_gettable, qpars, CB) + SSdatabase.create_parametric_query_sync(query_gettable, query_parameters, CB) else - SSdatabase.create_parametric_query(query_gettable, qpars, CB) + SSdatabase.create_parametric_query(query_gettable, query_parameters, CB) /datum/db/adapter/brsql_adapter/read_view(datum/entity_view_meta/view, datum/db/filter/filter, datum/callback/CB, sync=FALSE) var/v_key = "v_[view.type]" - var/list/qpars = list() + var/list/query_parameters = list() var/datum/db/brsql_cached_query/cached_view = cached_queries[v_key] if(!istype(cached_view)) return null - var/query_getview = cached_view.spawn_query(filter, qpars) + var/query_getview = cached_view.spawn_query(filter, query_parameters) if(sync) - SSdatabase.create_parametric_query_sync(query_getview, qpars, CB) + SSdatabase.create_parametric_query_sync(query_getview, query_parameters, CB) else - SSdatabase.create_parametric_query(query_getview, qpars, CB) + SSdatabase.create_parametric_query(query_getview, query_parameters, CB) /datum/db/adapter/brsql_adapter/sync_table(type_name, table_name, list/field_types) - var/list/qpars = list() - var/query_gettable = getquery_systable_gettable(table_name, qpars) - var/datum/db/query_response/table_meta = SSdatabase.create_parametric_query_sync(query_gettable, qpars) + var/list/query_parameters = list() + var/query_gettable = getquery_systable_gettable(table_name, query_parameters) + var/datum/db/query_response/table_meta = SSdatabase.create_parametric_query_sync(query_gettable, query_parameters) if(table_meta.status != DB_QUERY_FINISHED) issue_log += "Unable to access system table, error: '[table_meta.error]'" return FALSE // OH SHIT OH FUCK @@ -172,9 +172,9 @@ internal_update_table(table_name, field_types, old_fields) && internal_record_table_in_sys(type_name, table_name, field_types, id) /datum/db/adapter/brsql_adapter/sync_index(index_name, table_name, list/fields, unique, cluster) - var/list/qpars = list() - var/query_getindex = getquery_sysindex_getindex(index_name, table_name, qpars) - var/datum/db/query_response/index_meta = SSdatabase.create_parametric_query_sync(query_getindex, qpars) + var/list/query_parameters = list() + var/query_getindex = getquery_sysindex_getindex(index_name, table_name, query_parameters) + var/datum/db/query_response/index_meta = SSdatabase.create_parametric_query_sync(query_getindex, query_parameters) if(index_meta.status != DB_QUERY_FINISHED) issue_log += "Unable to access system index table, error: '[index_meta.error]'" return FALSE // OH SHIT OH FUCK @@ -201,9 +201,9 @@ return TRUE /datum/db/adapter/brsql_adapter/proc/internal_record_table_in_sys(type_name, table_name, field_types, id) - var/list/qpars = list() - var/query = getquery_systable_recordtable(type_name, table_name, field_types, qpars, id) - var/datum/db/query_response/sit_check = SSdatabase.create_parametric_query_sync(query, qpars) + var/list/query_parameters = list() + var/query = getquery_systable_recordtable(type_name, table_name, field_types, query_parameters, id) + var/datum/db/query_response/sit_check = SSdatabase.create_parametric_query_sync(query, query_parameters) if(sit_check.status != DB_QUERY_FINISHED) issue_log += "Unable to record meta for table [table_name], error: '[sit_check.error]'" return FALSE // OH SHIT OH FUCK @@ -218,9 +218,9 @@ return TRUE /datum/db/adapter/brsql_adapter/proc/internal_record_index_in_sys(index_name, table_name, fields, id) - var/list/qpars = list() - var/query = getquery_sysindex_recordindex(index_name, table_name, fields, qpars, id) - var/datum/db/query_response/sit_check = SSdatabase.create_parametric_query_sync(query, qpars) + var/list/query_parameters = list() + var/query = getquery_sysindex_recordindex(index_name, table_name, fields, query_parameters, id) + var/datum/db/query_response/sit_check = SSdatabase.create_parametric_query_sync(query, query_parameters) if(sit_check.status != DB_QUERY_FINISHED) issue_log += "Unable to record meta for index [index_name], error: '[sit_check.error]'" return FALSE // OH SHIT OH FUCK @@ -443,12 +443,12 @@ SELECT [fields?(""+jointext(fields,",")+""):"*"] FROM `[connection.database]`.`[table_name]` WHERE id in ([id_text]) "} -/datum/db/adapter/brsql_adapter/proc/getquery_filter_table(table_name, datum/db/filter, list/pflds, list/fields) +/datum/db/adapter/brsql_adapter/proc/getquery_filter_table(table_name, datum/db/filter, list/parameters, list/fields) return {" - SELECT [fields?(""+jointext(fields,",")+""):"*"] FROM `[connection.database]`.`[table_name]` WHERE [get_filter(filter, null, pflds)] + SELECT [fields?(""+jointext(fields,",")+""):"*"] FROM `[connection.database]`.`[table_name]` WHERE [get_filter(filter, null, parameters)] "} -/datum/db/adapter/brsql_adapter/proc/getquery_insert_table(table_name, list/values, list/pflds) +/datum/db/adapter/brsql_adapter/proc/getquery_insert_table(table_name, list/values, list/parameters) var/calltext = "" var/insert_items = "" var/first = TRUE @@ -465,7 +465,7 @@ if(fields[field] == null) local_text += "NULL" else - pflds.Add("[fields[field]]") + parameters.Add("[fields[field]]") local_text += " ? " if(first) if(!local_first) @@ -479,7 +479,7 @@ INSERT INTO `[connection.database]`.`[table_name]` ([insert_items]) VALUES [calltext]; "} -/datum/db/adapter/brsql_adapter/proc/getquery_update_row(table_name, list/values, list/pflds) +/datum/db/adapter/brsql_adapter/proc/getquery_update_row(table_name, list/values, list/parameters) var/calltext = "" var/first = TRUE var/id = 0 @@ -493,7 +493,7 @@ continue if(values[field]) calltext+="[esfield]=?" - pflds.Add("[values[field]]") + parameters.Add("[values[field]]") else calltext+="[esfield]=NULL" first = FALSE @@ -640,18 +640,18 @@ internal_generate_view_query(view, shared_options, meta_to_load, meta_to_table, join_conditions, field_alias) -/datum/db/adapter/brsql_adapter/proc/internal_proc_to_text(datum/db/native_function/NF, list/field_alias, list/pflds) - switch(NF.type) +/datum/db/adapter/brsql_adapter/proc/internal_proc_to_text(datum/db/native_function/native_function, list/field_alias, list/parameters) + switch(native_function.type) if(/datum/db/native_function/case) - var/datum/db/native_function/case/case_f = NF + var/datum/db/native_function/case/case_f = native_function var/result_true = case_f.result_true var/result_false = case_f.result_false - var/condition_text = get_filter(case_f.condition, field_alias, pflds) + var/condition_text = get_filter(case_f.condition, field_alias, parameters) var/true_text if(result_true) var/datum/db/native_function/native_true = result_true if(istype(native_true)) - true_text = internal_proc_to_text(native_true, field_alias, pflds) + true_text = internal_proc_to_text(native_true, field_alias, parameters) else var/field_cast = "[result_true]" if(field_alias && field_alias[field_cast]) @@ -661,7 +661,7 @@ if(result_false) var/datum/db/native_function/native_false = result_false if(istype(native_false)) - false_text = internal_proc_to_text(native_false, field_alias, pflds) + false_text = internal_proc_to_text(native_false, field_alias, parameters) else var/field_cast = "[result_false]" if(field_alias && field_alias[field_cast]) @@ -671,17 +671,17 @@ false_text = "ELSE ([false_text]) " return "CASE WHEN [condition_text] THEN ([true_text]) [false_text] END" else - return NF.default_to_string(field_alias, pflds) + return native_function.default_to_string(field_alias, parameters) /datum/db/adapter/brsql_adapter/proc/internal_generate_view_query(datum/entity_view_meta/view, list/shared_options, list/datum/entity_meta/meta_to_load, list/meta_to_table, list/datum/db/filter/join_conditions, list/field_alias) var/list/pre_pflds = list() var/query_text = "SELECT " for(var/fld in view.fields) var/field = field_alias[fld] - var/datum/db/native_function/NF = field + var/datum/db/native_function/native_function = field // this is a function? - if(istype(NF)) - field = internal_proc_to_text(NF, field_alias, pre_pflds) + if(istype(native_function)) + field = internal_proc_to_text(native_function, field_alias, pre_pflds) query_text += "[field] as `[fld]`, " query_text += "1 as is_view " query_text += "FROM `[connection.database]`.`[meta_to_load[BRSQL_ROOT_NAME].table_name]` as `[meta_to_table[BRSQL_ROOT_NAME]]` " @@ -744,15 +744,15 @@ /datum/db/adapter/brsql_adapter/proc/internal_parse_column(field, field_value, datum/entity_view_meta/view, list/shared_options, list/datum/entity_meta/meta_to_load, list/meta_to_table, list/datum/db/filter/join_conditions, list/field_alias) - var/datum/db/native_function/NF = field_value + var/datum/db/native_function/native_function = field_value // this is a function? - if(istype(NF)) - var/list/field_list = NF.get_columns() + if(istype(native_function)) + var/list/field_list = native_function.get_columns() for(var/sub_field in field_list) internal_parse_column(sub_field, sub_field, view, shared_options, meta_to_load, meta_to_table, join_conditions, field_alias) if(field) - field_alias[field] = NF + field_alias[field] = native_function return // no, this is a normal field diff --git a/code/datums/_ndatabase/code/brsql_persistent_connection.dm b/code/datums/_ndatabase/code/brsql_persistent_connection.dm index 9d098de2c61a..524c99eecc1f 100644 --- a/code/datums/_ndatabase/code/brsql_persistent_connection.dm +++ b/code/datums/_ndatabase/code/brsql_persistent_connection.dm @@ -91,16 +91,16 @@ /datum/db/connection/brsql_connection/query() if(connection_ready()) - var/datum/db/query/brsql/pq = new() + var/datum/db/query/brsql/parameterized_query = new() var/query_text = args[1] var/query_parameters = (length(args) > 1) ? args.Copy(2) : list() - pq.parameters = query_parameters + parameterized_query.parameters = query_parameters var/text = json_encode(query_parameters) - pq.job_id = rustg_sql_query_async(connection_handle, query_text, text) + parameterized_query.job_id = rustg_sql_query_async(connection_handle, query_text, text) query_number++ - return pq + return parameterized_query return null - + /datum/db/connection/brsql_connection/get_adapter() var/datum/db/adapter/brsql_adapter/adapter = new() adapter.connection = src diff --git a/code/datums/_ndatabase/code/entity/db_field.dm b/code/datums/_ndatabase/code/entity/db_field.dm new file mode 100644 index 000000000000..158580272b6b --- /dev/null +++ b/code/datums/_ndatabase/code/entity/db_field.dm @@ -0,0 +1,7 @@ +/datum/db_field + /// The type on the DB, should be a subtype of /datum/db_field_type (see: `__DEFINES/ndatabase.dm`). + var/field_type + /// The name of the field on the DB, should only contain lowercase letters and underscores. + var/name + /// The actual value of the field (not necessarily persisted to DB) + var/value diff --git a/code/datums/_ndatabase/code/entity/db_field_type.dm b/code/datums/_ndatabase/code/entity/db_field_type.dm new file mode 100644 index 000000000000..b854f532187f --- /dev/null +++ b/code/datums/_ndatabase/code/entity/db_field_type.dm @@ -0,0 +1,45 @@ +/// Should be TRUE for everything but interface parent types +/datum/db_field_type + var/valid = FALSE + +/datum/db_field_type/int + valid = TRUE + +/datum/db_field_type/bigint + valid = TRUE + +/// Field that allows only 1 symbol +/datum/db_field_type/char + valid = TRUE + +/datum/db_field_type/string + valid = FALSE + +/// Field that allows 16 symbols +/datum/db_field_type/string/small + valid = TRUE + +/// Field that allows 64 symbols +/datum/db_field_type/string/medium + valid = TRUE + +/// Field that allows 256 symbols +/datum/db_field_type/string/large + valid = TRUE + +/// Field that allows 4000 symbols +/datum/db_field_type/string/max + valid = TRUE + +/datum/db_field_type/date + valid = TRUE + +/// Field that allows any amount of symbols but really inefficient +/datum/db_field_type/text + valid = TRUE + +/datum/db_field_type/blob + valid = TRUE + +/datum/db_field_type/decimal + valid = TRUE diff --git a/code/datums/_ndatabase/code/entity/entity.dm b/code/datums/_ndatabase/code/entity/entity.dm index ef592d4535d5..59a85ebf466d 100644 --- a/code/datums/_ndatabase/code/entity/entity.dm +++ b/code/datums/_ndatabase/code/entity/entity.dm @@ -22,6 +22,7 @@ /datum/entity var/id var/status + var/datum/db_field_type/field_type var/datum/entity_meta/metadata var/__key_synced = FALSE diff --git a/code/datums/_ndatabase/code/entity/entity_meta.dm b/code/datums/_ndatabase/code/entity/entity_meta.dm index 49cf97edcb9f..8f8b58ac3f63 100644 --- a/code/datums/_ndatabase/code/entity/entity_meta.dm +++ b/code/datums/_ndatabase/code/entity/entity_meta.dm @@ -22,7 +22,7 @@ /datum/entity_meta var/entity_type var/table_name - var/list/field_types + var/list/datum/db_field/field_types var/active_entity = TRUE var/key_field = null @@ -52,6 +52,13 @@ key_managed = list() inbound_links = list() outbound_links = list() + setup_field_types() + +/// Proc to populate field_types list, mainly used for the no-boiler plate entity definitions +/datum/entity_meta/proc/setup_field_types() + // Should always be calling other overrides of the proc, entities are final classes any way + SHOULD_CALL_PARENT(TRUE) + return // redefine this for faster operations /datum/entity_meta/proc/map(datum/entity/ET, list/values) diff --git a/code/datums/_ndatabase/code/entity/link.dm b/code/datums/_ndatabase/code/entity/link.dm index d64fea053f54..1be23ffb9959 100644 --- a/code/datums/_ndatabase/code/entity/link.dm +++ b/code/datums/_ndatabase/code/entity/link.dm @@ -19,13 +19,17 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. + +/// Datum to represent a relation between two entities in the DB. +/// Should not have any child types, all entity links should be queued for creation by +/// overriding the `get_entity_links` proc. /datum/entity_link + /// Entity that is being referenced var/parent_entity + /// Entity that is referencing a different entity var/child_entity - var/child_field - - var/parent_name - var/child_name + /// Column on child entity to reference parent entity + var/child_foreign_key var/datum/entity_meta/parent_meta var/datum/entity_meta/child_meta @@ -34,5 +38,10 @@ var/list/child_requests +/datum/entity_link/New(parent_entity, child_entity, child_foreign_key) + src.parent_entity = parent_entity + src.child_entity = child_entity + src.child_foreign_key = child_foreign_key + /datum/entity_link/proc/get_filter(parent_alias, child_alias) - return new /datum/db/filter/link(parent_alias, DB_DEFAULT_ID_FIELD, child_alias, child_field) + return new /datum/db/filter/link(parent_alias, DB_DEFAULT_ID_FIELD, child_alias, child_foreign_key) diff --git a/code/datums/_ndatabase/code/interfaces/adapter.dm b/code/datums/_ndatabase/code/interfaces/adapter.dm index e41bd0fc9cba..33270fe5de41 100644 --- a/code/datums/_ndatabase/code/interfaces/adapter.dm +++ b/code/datums/_ndatabase/code/interfaces/adapter.dm @@ -55,28 +55,28 @@ // DEFAULT IMPLEMENTATIONS // DO NOT USE EXCEPT IN ADAPTER CODE -/datum/db/adapter/proc/get_filter_comparison(datum/db/filter/comparison/filter, list/casts, list/pflds) +/datum/db/adapter/proc/get_filter_comparison(datum/db/filter/comparison/filter, list/casts, list/parameters) var/field_cast = "[filter.field]" if(casts && casts[field_cast]) field_cast = casts[field_cast] switch(filter.operator) if(DB_EQUALS) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] = ?" if(DB_NOTEQUAL) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] <> ?" if(DB_GREATER) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] > ?" if(DB_LESS) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] < ?" if(DB_GREATER_EQUAL) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] >= ?" if(DB_LESS_EQUAL) - pflds.Add("[filter.value]") + parameters.Add("[filter.value]") return "[field_cast] <= ?" if(DB_IS) return "[field_cast] IS NULL" @@ -88,7 +88,7 @@ for(var/item in filter.value) if(!first) text += "," - pflds.Add("[item]") + parameters.Add("[item]") text += "?" first = FALSE return "[field_cast] IN ([text])" @@ -98,13 +98,13 @@ for(var/item in filter.value) if(!first) text += "," - pflds.Add("[item]") + parameters.Add("[item]") text += "?" first = FALSE return "[field_cast] NOTIN ([text])" return "1=1" // shunt -/datum/db/adapter/proc/get_filter_comparetwo(datum/db/filter/compare_two/filter, list/casts, list/pflds) +/datum/db/adapter/proc/get_filter_comparetwo(datum/db/filter/compare_two/filter, list/casts, list/parameters) var/field1_cast = "[filter.field1]" if(casts && casts[field1_cast]) field1_cast = casts[field1_cast] @@ -126,7 +126,7 @@ return "[field1_cast] <= [field2_cast]" return "1=1" // shunt -/datum/db/adapter/proc/get_filter_and(datum/db/filter/and/filter, list/casts, list/pflds) +/datum/db/adapter/proc/get_filter_and(datum/db/filter/and/filter, list/casts, list/parameters) var/first = TRUE var/text = "" for(var/item in filter.subfilters) @@ -134,12 +134,12 @@ first = FALSE else text += " AND " - text += "([get_filter(item, casts, pflds)])" + text += "([get_filter(item, casts, parameters)])" if(!text) text = "(1=1)" return text -/datum/db/adapter/proc/get_filter_or(datum/db/filter/or/filter, list/casts, list/pflds) +/datum/db/adapter/proc/get_filter_or(datum/db/filter/or/filter, list/casts, list/parameters) var/first = TRUE var/text = "" for(var/item in filter.subfilters) @@ -147,7 +147,7 @@ first = FALSE else text += " OR " - text += "([get_filter(item, casts, pflds)])" + text += "([get_filter(item, casts, parameters)])" if(!text) text = "(1=1)" return text @@ -155,15 +155,15 @@ /datum/db/adapter/proc/get_filter_link(datum/db/filter/link/filter) return "([filter.a_table].[filter.a_field] = [filter.b_table].[filter.b_field])" -/datum/db/adapter/proc/get_filter(datum/db/filter/filter, list/casts, list/pflds) +/datum/db/adapter/proc/get_filter(datum/db/filter/filter, list/casts, list/parameters) if(istype(filter,/datum/db/filter/and)) - return get_filter_and(filter, casts, pflds) + return get_filter_and(filter, casts, parameters) if(istype(filter,/datum/db/filter/or)) - return get_filter_or(filter, casts, pflds) + return get_filter_or(filter, casts, parameters) if(istype(filter,/datum/db/filter/comparison)) - return get_filter_comparison(filter, casts, pflds) + return get_filter_comparison(filter, casts, parameters) if(istype(filter,/datum/db/filter/compare_two)) - return get_filter_comparetwo(filter, casts, pflds) + return get_filter_comparetwo(filter, casts, parameters) if(istype(filter,/datum/db/filter/link)) return get_filter_link(filter) return "1=1" // shunt diff --git a/code/datums/_ndatabase/subsystems/database_query_manager.dm b/code/datums/_ndatabase/subsystems/database_query_manager.dm index 5a68c4e349c1..356644140c2e 100644 --- a/code/datums/_ndatabase/subsystems/database_query_manager.dm +++ b/code/datums/_ndatabase/subsystems/database_query_manager.dm @@ -78,9 +78,9 @@ GLOBAL_REAL(SSdatabase, /datum/controller/subsystem/database_query_manager) // First handle the already running queries while(length(queries_current)) - var/datum/db/query_response/Q = popleft(queries_current) - if(!process_query(Q)) - queries_active -= Q + var/datum/db/query_response/query = popleft(queries_current) + if(!process_query(query)) + queries_active -= query if(MC_TICK_CHECK) return @@ -91,86 +91,86 @@ GLOBAL_REAL(SSdatabase, /datum/controller/subsystem/database_query_manager) queries_new = queries_standby.Copy(1, min(length(queries_standby), max_concurrent_queries) + 1) while(length(queries_new) && length(queries_active) < max_concurrent_queries) - var/datum/db/query_response/Q = queries_new[1] - var/list/ar = queries_new[Q] - queries_standby.Remove(Q) - queries_new.Remove(Q) - create_queued_query(Q, ar) + var/datum/db/query_response/query = queries_new[1] + var/list/ar = queries_new[query] + queries_standby.Remove(query) + queries_new.Remove(query) + create_queued_query(query, ar) if(MC_TICK_CHECK) return /// Helper proc for query processing used in fire() - returns TRUE if not done yet -/datum/controller/subsystem/database_query_manager/proc/process_query(datum/db/query_response/Q) +/datum/controller/subsystem/database_query_manager/proc/process_query(datum/db/query_response/query) PRIVATE_PROC(TRUE) SHOULD_NOT_SLEEP(TRUE) - if(QDELETED(Q)) + if(QDELETED(query)) return FALSE - if(Q.process(world.tick_lag)) - queries_active -= Q + if(query.process(world.tick_lag)) + queries_active -= query return FALSE return TRUE /// Helper proc for handling queued new queries -/datum/controller/subsystem/database_query_manager/proc/create_queued_query(datum/db/query_response/Q, qtargs) +/datum/controller/subsystem/database_query_manager/proc/create_queued_query(datum/db/query_response/query, query_parameters) PRIVATE_PROC(TRUE) SHOULD_NOT_SLEEP(TRUE) RETURN_TYPE(/datum/db/query) - if(!Q.unique_query_id) - Q.unique_query_id = last_query_id++ - var/datum/db/query/RQ - if(islist(qtargs)) - RQ = connection.query(arglist(qtargs)) + if(!query.unique_query_id) + query.unique_query_id = last_query_id++ + var/datum/db/query/query_actual + if(islist(query_parameters)) + query_actual = connection.query(arglist(query_parameters)) else - RQ = connection.query(qtargs) - Q.query = RQ - queries_active += Q - return RQ + query_actual = connection.query(query_parameters) + query.query = query_actual + queries_active += query + return query_actual /datum/controller/subsystem/database_query_manager/proc/create_query(query_text, success_callback, fail_callback, unique_query_id) - var/datum/db/query_response/qr = new() - qr.query_text = query_text - qr.success_callback = success_callback - qr.fail_callback = fail_callback + var/datum/db/query_response/query_response = new() + query_response.query_text = query_text + query_response.success_callback = success_callback + query_response.fail_callback = fail_callback if(unique_query_id) - qr.unique_query_id = unique_query_id - queries_standby[qr] = query_text + query_response.unique_query_id = unique_query_id + queries_standby[query_response] = query_text // if DB supports this /datum/controller/subsystem/database_query_manager/proc/create_parametric_query(query_text, parameters, success_callback, fail_callback, unique_query_id) - var/datum/db/query_response/qr = new() - var/list/prs = list() - prs.Add(query_text) + var/datum/db/query_response/query_response = new() + var/list/query_parameters = list() + query_parameters.Add(query_text) if(parameters) - prs.Add(parameters) - qr.query_text = query_text - qr.success_callback = success_callback - qr.fail_callback = fail_callback + query_parameters.Add(parameters) + query_response.query_text = query_text + query_response.success_callback = success_callback + query_response.fail_callback = fail_callback if(unique_query_id) - qr.unique_query_id = unique_query_id - queries_standby[qr] = prs + query_response.unique_query_id = unique_query_id + queries_standby[query_response] = query_parameters // Do not use this if you don't know why this exists /datum/controller/subsystem/database_query_manager/proc/create_query_sync(query_text, success_callback, fail_callback) - var/datum/db/query_response/qr = new() - qr.query = connection.query(query_text) - qr.query_text = query_text - qr.success_callback = success_callback - qr.fail_callback = fail_callback - UNTIL(qr.process()) - return qr + var/datum/db/query_response/query_response = new() + query_response.query = connection.query(query_text) + query_response.query_text = query_text + query_response.success_callback = success_callback + query_response.fail_callback = fail_callback + UNTIL(query_response.process()) + return query_response /datum/controller/subsystem/database_query_manager/proc/create_parametric_query_sync(query_text, parameters, success_callback, fail_callback) - var/datum/db/query_response/qr = new() - var/list/prs = list() - prs += query_text + var/datum/db/query_response/query_response = new() + var/list/query_parameters = list() + query_parameters += query_text if(parameters) - prs += parameters - qr.query = connection.query(arglist(prs)) - qr.query_text = query_text - qr.success_callback = success_callback - qr.fail_callback = fail_callback - UNTIL(qr.process()) - return qr + query_parameters += parameters + query_response.query = connection.query(arglist(query_parameters)) + query_response.query_text = query_text + query_response.success_callback = success_callback + query_response.fail_callback = fail_callback + UNTIL(query_response.process()) + return query_response /proc/loadsql(filename) var/list/Lines = file2list(filename) diff --git a/code/datums/_ndatabase/subsystems/entity_manager.dm b/code/datums/_ndatabase/subsystems/entity_manager.dm index 2ef5da2b22dd..fa7d42876b67 100644 --- a/code/datums/_ndatabase/subsystems/entity_manager.dm +++ b/code/datums/_ndatabase/subsystems/entity_manager.dm @@ -44,22 +44,22 @@ GLOBAL_REAL(SSentity_manager, /datum/controller/subsystem/entity_manager) /datum/controller/subsystem/entity_manager/New() tables = list() tables_unsorted = list() - var/list/all_entities = typesof(/datum/entity_meta) - list(/datum/entity_meta) + var/list/all_entities = subtypesof(/datum/entity_meta) for(var/entity_meta in all_entities) var/datum/entity_meta/table = new entity_meta() if(table.active_entity) tables[table.entity_type] = table tables_unsorted.Add(table) - var/list/all_links = typesof(/datum/entity_link) - list(/datum/entity_link) - for(var/entity_link in all_links) - var/datum/entity_link/link = new entity_link() + var/list/datum/entity_link/entity_links = list() + get_entity_links(entity_links) + for(var/datum/entity_link/link as anything in entity_links) var/datum/entity_meta/parent = tables[link.parent_entity] var/datum/entity_meta/child = tables[link.child_entity] if(link.child_name) - parent.inbound_links[link.child_name] = link + parent.inbound_links[link.child_entity] = link if(link.parent_name) - child.outbound_links[link.parent_name] = link + child.outbound_links[link.parent_entity] = link link.parent_meta = parent link.child_meta = child @@ -68,6 +68,12 @@ GLOBAL_REAL(SSentity_manager, /datum/controller/subsystem/entity_manager) NEW_SS_GLOBAL(SSentity_manager) +// Override this proc to populate entity_links list that is passed as an argument +/datum/controller/subsystem/entity_manager/proc/get_entity_links(list/datum/entity_link/entity_links) + PRIVATE_PROC(TRUE) + SHOULD_CALL_PARENT(TRUE) + return + /datum/controller/subsystem/entity_manager/proc/start_up() set waitfor=0 UNTIL(SSdatabase.connection.connection_ready()) diff --git a/code/datums/entities/clans.dm b/code/datums/entities/clans.dm index 916afd18c178..0471257d2b2c 100644 --- a/code/datums/entities/clans.dm +++ b/code/datums/entities/clans.dm @@ -54,7 +54,7 @@ BSQL_PROTECT_DATUM(/datum/entity/clan) /datum/entity_link/player_to_clan_player parent_entity = /datum/entity/player child_entity = /datum/entity/clan_player - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "clan_player" @@ -62,7 +62,7 @@ BSQL_PROTECT_DATUM(/datum/entity/clan) /datum/entity_link/clan_to_player parent_entity = /datum/entity/clan child_entity = /datum/entity/clan_player - child_field = "clan_id" + child_foreign_key = "clan_id" parent_name = "clan" child_name = "clan_player" diff --git a/code/datums/entities/discord_link.dm b/code/datums/entities/discord_link.dm index c11fe15c2f68..8d91c517821b 100644 --- a/code/datums/entities/discord_link.dm +++ b/code/datums/entities/discord_link.dm @@ -30,7 +30,7 @@ /datum/entity_link/player_to_discord parent_entity = /datum/entity/player child_entity = /datum/entity/discord_link - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "discord_link_id" diff --git a/code/datums/entities/player.dm b/code/datums/entities/player.dm index fbdcc11e1037..39f235283f9c 100644 --- a/code/datums/entities/player.dm +++ b/code/datums/entities/player.dm @@ -739,7 +739,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player) /datum/entity_link/player_to_banning_admin parent_entity = /datum/entity/player child_entity = /datum/entity/player - child_field = "time_ban_admin_id" + child_foreign_key = "time_ban_admin_id" parent_name = "banning_admin" @@ -747,7 +747,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player) /datum/entity_link/player_to_permabanning_admin parent_entity = /datum/entity/player child_entity = /datum/entity/player - child_field = "permaban_admin_id" + child_foreign_key = "permaban_admin_id" parent_name = "permabanning_admin" /datum/view_record/players diff --git a/code/datums/entities/player_job_ban.dm b/code/datums/entities/player_job_ban.dm index 63aad95c9bce..7d9b89a8f7b6 100644 --- a/code/datums/entities/player_job_ban.dm +++ b/code/datums/entities/player_job_ban.dm @@ -37,7 +37,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_job_ban) /datum/entity_link/player_to_player_job_bans parent_entity = /datum/entity/player child_entity = /datum/entity/player_job_ban - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "jobbans" @@ -45,6 +45,6 @@ BSQL_PROTECT_DATUM(/datum/entity/player_job_ban) /datum/entity_link/admin_to_player_job_bans parent_entity = /datum/entity/player child_entity = /datum/entity/player_job_ban - child_field = "admin_id" + child_foreign_key = "admin_id" parent_name = "admin" diff --git a/code/datums/entities/player_note.dm b/code/datums/entities/player_note.dm index 216e20b40701..33b6aa1f4938 100644 --- a/code/datums/entities/player_note.dm +++ b/code/datums/entities/player_note.dm @@ -49,7 +49,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_note) /datum/entity_link/player_to_player_notes parent_entity = /datum/entity/player child_entity = /datum/entity/player_note - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "notes" @@ -57,7 +57,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_note) /datum/entity_link/admin_to_player_notes parent_entity = /datum/entity/player child_entity = /datum/entity/player_note - child_field = "admin_id" + child_foreign_key = "admin_id" parent_name = "admin" diff --git a/code/datums/entities/player_stat.dm b/code/datums/entities/player_stat.dm index 9e7924e07266..b0b5b37e1e29 100644 --- a/code/datums/entities/player_stat.dm +++ b/code/datums/entities/player_stat.dm @@ -22,7 +22,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_stat) /datum/entity_link/player_to_stat parent_entity = /datum/entity/player child_entity = /datum/entity/player_stat - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "player_stats" diff --git a/code/datums/entities/player_sticky_ban.dm b/code/datums/entities/player_sticky_ban.dm index 70715d1ce2f0..9cc139df8dd4 100644 --- a/code/datums/entities/player_sticky_ban.dm +++ b/code/datums/entities/player_sticky_ban.dm @@ -45,7 +45,7 @@ BSQL_PROTECT_DATUM(/datum/entity/stickyban) /datum/entity_link/stickyban_to_banning_admin parent_entity = /datum/entity/player child_entity = /datum/entity/stickyban - child_field = "adminid" + child_foreign_key = "adminid" parent_name = "stickybanning_admin" /datum/entity/stickyban_matched_ckey diff --git a/code/datums/entities/player_times.dm b/code/datums/entities/player_times.dm index 4fc28ba2fa5e..43498709806b 100644 --- a/code/datums/entities/player_times.dm +++ b/code/datums/entities/player_times.dm @@ -24,7 +24,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_time) /datum/entity_link/player_to_time parent_entity = /datum/entity/player child_entity = /datum/entity/player_time - child_field = "player_id" + child_foreign_key = "player_id" parent_name = "player" child_name = "player_times" diff --git a/colonialmarines.dme b/colonialmarines.dme index 9fff0d7db91b..ae5bea645e81 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -52,7 +52,6 @@ #include "code\__DEFINES\configuration.dm" #include "code\__DEFINES\conflict.dm" #include "code\__DEFINES\cooldowns.dm" -#include "code\__DEFINES\db_defs.dm" #include "code\__DEFINES\defenses.dm" #include "code\__DEFINES\dropships.dm" #include "code\__DEFINES\emote_panels.dm" @@ -84,6 +83,7 @@ #include "code\__DEFINES\mobs.dm" #include "code\__DEFINES\mode.dm" #include "code\__DEFINES\movement.dm" +#include "code\__DEFINES\ndatabase.dm" #include "code\__DEFINES\nightmare.dm" #include "code\__DEFINES\objects.dm" #include "code\__DEFINES\origins.dm" @@ -368,6 +368,8 @@ #include "code\datums\weakrefs.dm" #include "code\datums\world_topic.dm" #include "code\datums\_ndatabase\include.dm" +#include "code\datums\_ndatabase\code\entity\db_field.dm" +#include "code\datums\_ndatabase\code\entity\db_field_type.dm" #include "code\datums\agents\tools.dm" #include "code\datums\agents\tools\access_tuner.dm" #include "code\datums\agents\tools\badass_kit.dm"