Files
rmodb/src/modb_metadata.c
2020-10-09 13:27:05 +01:00

756 lines
20 KiB
C

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "modb_metadata.h"
#include "modb_objects.h"
#include "modb_metadata_ext.h"
#include "modb_users.h"
#include "modb_groups.h"
#include "modb_p.h"
// ##### PRIVATE
int tableRowsToMetadataList(column_data **col_data, size_t n_cols,
struct metadata_t ***metadata_list, size_t *n_metadatas)
{
column_data *col_id, *col_title, *col_owner_id, *col_created, *col_updated, *col_deleted;
size_t n_rows, idx;
struct metadata_t *metadata;
n_rows = (*col_data)->n_values;
if (n_rows == 0) {
return 0;
}
col_id = findColumnByName(col_data, n_cols, "mdo_id");
col_title = findColumnByName(col_data, n_cols, "title");
col_owner_id = findColumnByName(col_data, n_cols, "owner_id");
col_created = findColumnByName(col_data, n_cols, "created");
col_updated = findColumnByName(col_data, n_cols, "updated");
col_deleted = findColumnByName(col_data, n_cols, "deleted");
*metadata_list = (struct metadata_t **)malloc(sizeof(struct metadata_t *) * n_rows);
if (*metadata_list == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return -errno;
}
memset(*metadata_list, 0, sizeof(struct metadata_t *) * n_rows);
for (idx = 0; idx < n_rows; idx++) {
metadata = allocMetadata();
if (metadata == 0) {
freeMetadataList(metadata_list, idx - 1);
return -1;
}
metadata->id = *(col_id->data.ptr_uint32 + idx);
if (!moveColumnStrPointer(col_title, idx, 1, &metadata->title, &metadata->title_len)) {
freeMetadataList(metadata_list, idx);
return -1;
}
metadata->owner_id = *(col_owner_id->data.ptr_uint32 + idx);
metadata->created_on = *(col_created->data.ptr_int64 + idx);
if (!columnRowIsNull(col_updated, idx)) {
metadata->updated_on = *(col_updated->data.ptr_int64 + idx);
}
if (!columnRowIsNull(col_deleted, idx)) {
metadata->deleted_on = *(col_deleted->data.ptr_int64 + idx);
}
*(*metadata_list + idx) = metadata;
}
*n_metadatas = n_rows;
return 1;
}
int doMetadataListQuery(stored_conn *sconn, modb_ref *modb, where_builder *wb,
struct metadata_t ***metadata_list, size_t *n_metadatas)
{
char *table;
size_t table_len;
char *qry;
size_t qry_len;
uint64_t qry_ret;
int res;
str_builder *sb;
column_data **col_data;
size_t n_cols;
if ((sb = strbld_create()) == 0) {
return -1;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, strlen(METADATA_TABLE));
strbld_str(sb, "SELECT * FROM ", 0);
escapeTableName_sb(sb, table, table_len);
if (wb != 0) {
compileWhereBuilder_sb(sb, wb, 0);
}
strbld_str(sb, " ORDER BY `updated` DESC, `created` DESC", 0);
modbFreeTableName(&table);
if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) {
return -1;
}
qry_ret = tableQuery(sconn, qry, qry_len, 0, &col_data, &n_cols);
free(qry);
// Query failed
if (qry_ret == (uint64_t)-1) {
return -1;
}
// Zero row result
if (qry_ret == 0) {
freeColumns(col_data, n_cols);
return 0;
}
res = tableRowsToMetadataList(col_data, n_cols, metadata_list, n_metadatas);
freeColumns(col_data, n_cols);
if (res <= 0) {
return res;
}
return (int)qry_ret;
}
int doScalarMetadataListQuery(stored_conn *sconn, modb_ref *modb,
where_builder *wb, struct metadata_t **metadata)
{
int res;
struct metadata_t **metadata_list;
size_t n_metadatas;
res = doMetadataListQuery(sconn, modb, wb, &metadata_list, &n_metadatas);
if (res <= 0) {
return res;
}
*metadata = *(metadata_list + 0);
*(metadata_list + 0) = 0;
freeMetadataList(&metadata_list, n_metadatas);
return res;
}
// ##### PUBLIC
struct metadata_t *allocMetadata(void)
{
struct metadata_t *metadata;
metadata = malloc(sizeof(struct metadata_t));
if (metadata == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
}
memset(metadata, 0, sizeof(struct metadata_t));
return metadata;
}
struct metadata_t **allocMetadataList(size_t n_metadatas)
{
struct metadata_t **metadatas;
metadatas = (struct metadata_t **)malloc(sizeof(struct metadata_t *) * n_metadatas);
if (metadatas == 0) {
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
return 0;
}
memset(metadatas, 0, sizeof(struct metadata_t *) * n_metadatas);
return metadatas;
}
void freeMetadata(struct metadata_t **metadata_ptr)
{
struct metadata_t *metadata = *metadata_ptr;
if (metadata->ext != 0) {
freeMetadataExt(&metadata->ext);
}
if (metadata->object != 0) {
freeObject(&metadata->object);
}
if (metadata->n_groups > 0) {
if (metadata->group_ids != 0) {
free(metadata->group_ids);
metadata->group_ids = 0;
}
if (metadata->groups != 0) {
freeGroups(&metadata->groups, metadata->n_groups);
}
metadata->n_groups = 0;
}
if (metadata->owner != 0) {
freeUser(&metadata->owner);
}
if (metadata->title != 0) {
free(metadata->title);
metadata->title = 0;
}
free(metadata);
*metadata_ptr = 0;
}
void freeMetadataList(struct metadata_t ***metadata_list_ptr, size_t n_metadatas)
{
size_t idx;
struct metadata_t **metadatas_list= *metadata_list_ptr;
for (idx = 0; idx < n_metadatas; idx++) {
if (*(metadatas_list + idx) != 0) {
freeMetadata((metadatas_list + idx));
}
}
free(metadatas_list);
*metadata_list_ptr = 0;
}
int modbMetadataById(stored_conn *sconn, modb_ref *modb, unsigned int id,
struct metadata_t **metadata)
{
where_builder *wb = 0;
int res;
wb = where(0, "mdo_id", EQ, TYPE_ID, 1, id);
res = doScalarMetadataListQuery(sconn, modb, wb, metadata);
freeWhereBuilder(&wb);
return res;
}
int modbMetadataListByOwnerId(stored_conn *sconn, modb_ref *modb, unsigned int owner_id,
int with_deleted,
struct metadata_t ***metadata_list, size_t *n_metadatas)
{
where_builder *wb = 0;
int res;
wb = where(0, "owner_id", EQ, TYPE_ID, owner_id);
if (with_deleted == 0) {
wb = whereAnd(wb, where(0, "deleted_on", IS_NULL, TYPE_RAW, 0, 0));
}
res = doMetadataListQuery(sconn, modb, wb, metadata_list, n_metadatas);
if (wb != 0) {
freeWhereBuilder(&wb);
}
return res;
}
int modbMetadataListByGroupId(stored_conn *sconn, modb_ref *modb, unsigned int group_id,
int with_deleted,
struct metadata_t ***metadata_list, size_t *n_metadatas)
{
unsigned int *ids = 0;
size_t n_ids;
size_t idx;
where_builder *wb = 0;
int res;
if (modbFetchGroupMetadataIds(sconn, modb, group_id, with_deleted, &ids, &n_ids) < 0) {
return -1;
}
if (ids == 0) {
return 0;
}
*metadata_list = (struct metadata_t **)malloc(sizeof(struct metadata_t *) * n_ids);
if (*metadata_list == 0) {
return -1;
}
wb = whereIn(0, 0, "mdo_id", TYPE_ID, 0);
for (idx = 0; idx < n_ids; idx++) {
setWhereValue(wb, TYPE_ID, 1, *(ids + idx));
}
res = doMetadataListQuery(sconn, modb, wb, metadata_list, n_metadatas);
if (wb != 0) {
freeWhereBuilder(&wb);
}
return res;
}
int modbMetadataList(stored_conn *sconn, modb_ref *modb, int with_deleted,
struct metadata_t ***metadata_list, size_t *n_metadatas)
{
where_builder *wb = 0;
int res;
if (with_deleted == 0) {
wb = where(0, "deleted_on", IS_NULL, TYPE_RAW, 0, 0);
}
res = doMetadataListQuery(sconn, modb, wb, metadata_list, n_metadatas);
if (wb != 0) {
freeWhereBuilder(&wb);
}
return res;
}
int64_t modbMetadataCreate(stored_conn *sconn, modb_ref *modb,
const struct metadata_t *const metadata)
{
str_builder *sb;
char *table;
size_t table_len;
char *qry;
size_t qry_len;
uint64_t qry_ret;
if ((sb = strbld_create()) == 0) {
return -1;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, strlen(METADATA_TABLE));
strbld_str(sb, "INSERT INTO ", 0);
escapeTableName_sb(sb, table, table_len);
strbld_str(sb, " (`mdo_id`, `type`, `title`, `owner_id`) VALUES (", 0);
db_value_sb(sb, TYPE_ID, 1, metadata->id);
strbld_char(sb, ',');
db_value_sb(sb, TYPE_STRING, 2, metadata->type, metadata->type_len);
strbld_char(sb, ',');
db_value_sb(sb, TYPE_STRING, 2, metadata->title, metadata->title_len);
strbld_char(sb, ',');
if (metadata->owner != 0) {
db_value_sb(sb, TYPE_ID, 1, metadata->owner->id);
} else {
db_value_sb(sb, TYPE_ID, 1, metadata->owner_id);
}
strbld_char(sb, ')');
modbFreeTableName(&table);
if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) {
return -1;
}
qry_ret = simpleQuery(sconn, qry, qry_len);
free(qry);
return (int64_t)qry_ret;
}
int64_t modbMetadataReplace(stored_conn *sconn, modb_ref *modb, unsigned int id,
const struct metadata_t *const metadata)
{
str_builder *sb;
char *table, *set;
size_t table_len, set_len;
int64_t qry_ret;
if ((sb = strbld_create()) == 0) {
return 0;
}
if (metadata->id != 0 && metadata->id != id) {
strbld_char(sb, ',');
columnSetValueStr_sb(sb, "mdo_id", TYPE_ID, 1, metadata->id);
}
if (metadata->type != 0) {
strbld_char(sb, ',');
columnSetValueStr_sb(sb, "type", TYPE_STRING, 2, metadata->type, metadata->type_len);
}
if (metadata->title != 0) {
strbld_char(sb, ',');
columnSetValueStr_sb(sb, "title", TYPE_STRING, 2, metadata->title, metadata->title_len);
}
if (metadata->owner != 0) {
strbld_char(sb, ',');
columnSetValueStr_sb(sb, "owner_id", TYPE_ID, 1, metadata->owner->id);
} else if (metadata->owner_id != 0) {
strbld_char(sb, ',');
columnSetValueStr_sb(sb, "owner_id", TYPE_ID, 1, metadata->owner_id);
}
if (strbld_finalize_or_destroy(&sb, &set, &set_len) != 0) {
return 0;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = updateQuery(
sconn, table, table_len, set, set_len, where(0, "mdo_id", EQ, TYPE_ID, 1, id)
);
modbFreeTableName(&table);
free(set);
return qry_ret;
}
int64_t modbMetadataUpdateType(stored_conn *sconn, modb_ref *modb, unsigned int id,
const char *type, size_t type_len)
{
str_builder *sb;
char *table, *set;
size_t table_len, set_len;
int64_t qry_ret;
if ((sb = strbld_create()) == 0) {
return 0;
}
columnSetValueStr_sb(sb, "mdo_id", TYPE_ID, 1, id);
strbld_char(sb, ',');
columnSetValueStr(&set, &set_len, "type", TYPE_STRING, 2, type, type_len);
if (strbld_finalize_or_destroy(&sb, &set, &set_len) != 0) {
return 0;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = updateQuery(
sconn, table, table_len, set, set_len, where(0, "mdo_id", EQ, TYPE_ID, 1, id)
);
modbFreeTableName(&table);
free(set);
return qry_ret;
}
int64_t modbMetadataUpdateTitle(stored_conn *sconn, modb_ref *modb, unsigned int id,
const char *title, size_t title_len)
{
str_builder *sb;
char *table, *set;
size_t table_len, set_len;
int64_t qry_ret;
if ((sb = strbld_create()) == 0) {
return 0;
}
columnSetValueStr_sb(sb, "mdo_id", TYPE_ID, 1, id);
strbld_char(sb, ',');
columnSetValueStr(&set, &set_len, "title", TYPE_STRING, 2, title, title_len);
if (strbld_finalize_or_destroy(&sb, &set, &set_len) != 0) {
return 0;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = updateQuery(
sconn, table, table_len, set, set_len, where(0, "mdo_id", EQ, TYPE_ID, 1, id)
);
modbFreeTableName(&table);
free(set);
return qry_ret;
}
int64_t modbMetadataUpdateOwner(stored_conn *sconn, modb_ref *modb, unsigned int id,
struct user_t *owner)
{
return modbMetadataUpdateOwnerId(sconn, modb, id, owner->id);
}
int64_t modbMetadataUpdateOwnerId(stored_conn *sconn, modb_ref *modb, unsigned int id,
unsigned int owner_id)
{
str_builder *sb;
char *table, *set;
size_t table_len, set_len;
int64_t qry_ret;
if ((sb = strbld_create()) == 0) {
return 0;
}
columnSetValueStr_sb(sb, "mdo_id", TYPE_ID, 1, id);
strbld_char(sb, ',');
columnSetValueStr(&set, &set_len, "owner_id", TYPE_ID, 1, owner_id);
if (strbld_finalize_or_destroy(&sb, &set, &set_len) != 0) {
return 0;
}
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = updateQuery(
sconn, table, table_len, set, set_len, where(0, "mdo_id", EQ, TYPE_ID, 1, id)
);
modbFreeTableName(&table);
free(set);
return qry_ret;
}
int modbMetadataDelete(stored_conn *sconn, modb_ref *modb, unsigned int id)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = softDeleteByIdQuery(sconn, table, table_len, "id", id);
modbFreeTableName(&table);
return (int)qry_ret;
}
int modbMetadataDestroy(stored_conn *sconn, modb_ref *modb, unsigned int id)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
qry_ret = deleteByIdQuery(sconn, table, table_len, "id", id);
modbFreeTableName(&table);
return (int)qry_ret;
}
// MODB Metadata -> Owner
int64_t modbFetchMetadataOwner(stored_conn *sconn, modb_ref *modb, struct metadata_t *metadata)
{
return modbUserById(sconn, modb, metadata->owner_id, 0, &metadata->owner);
}
// MODB Metadata -> Object
int64_t modbFetchMetadataObject(stored_conn *sconn, modb_ref *modb, struct metadata_t *metadata)
{
return modbObjectById(sconn, modb, metadata->id, &metadata->object);
}
// MODB Metadata -> MetadataExtended
int64_t modbFetchMetadataExtended(stored_conn *sconn, modb_ref *modb, struct metadata_t *metadata)
{
// TODO: implement
return -1;
}
// MODB Metadata -> Groups
int modbFetchMetadataGroupIds(stored_conn *sconn, modb_ref *modb,
struct metadata_t *metadata, int with_deleted)
{
char *g_table, *mg_table;
size_t g_len, mg_len;
char *qry;
size_t qry_len;
uint64_t qry_ret;
str_builder *sb;
where_builder *wb;
column_data **col_data;
size_t n_cols;
if ((sb = strbld_create()) == 0) {
return -1;
}
modbTableName(&g_table, &g_len, modb, GROUPS_TABLE, STR_LEN(GROUPS_TABLE));
modbTableName(&mg_table, &mg_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
strbld_str(sb, "SELECT ", 0);
escapeColumnName_sb(sb, 0, 0, "group_id", 0);
strbld_str(sb, " FROM ", 0);
escapeTableName_sb(sb, mg_table, mg_len);
joinStr_sb(sb, " LEFT", 5, 1, g_table, g_len, "id", 2, mg_table, mg_len, "group_id", 8);
wb = where(0, "mdo_id", EQ, TYPE_ID, 1, metadata->id);
if (!with_deleted) {
wb = whereAnd(wb, where(g_table, "deleted", IS_NULL, TYPE_RAW, 0));
}
compileWhereBuilder_sb(sb, wb, 1);
modbFreeTableName(&g_table);
modbFreeTableName(&mg_table);
if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) {
return -1;
}
qry_ret = tableQuery(sconn, qry, qry_len, 0, &col_data, &n_cols);
free(qry);
// Query failed
if (qry_ret == (uint64_t)-1) {
return -1;
}
// Zero row result
if (qry_ret == 0) {
freeColumns(col_data, n_cols);
return 0;
}
metadata->group_ids = (*col_data)->data.ptr_uint32;
metadata->n_groups = (*col_data)->n_values;
(*col_data)->data.ptr_uint32 = 0;
freeColumns(col_data, n_cols);
return 1;
}
int modbFetchMetadataGroups(stored_conn *sconn, modb_ref *modb, struct metadata_t *metadata,
int with_deleted)
{
int ret;
size_t idx;
ret = modbFetchMetadataGroupIds(sconn, modb, metadata, with_deleted);
if (ret != 1) {
return ret;
}
metadata->groups = allocGroups(metadata->n_groups);
if (metadata->groups == 0) {
return -1;
}
for (idx = 0; idx < metadata->n_groups; idx++) {
if (modbGroupById(
sconn, modb, *(metadata->group_ids + idx), 0, (metadata->groups + idx)
) != 1) {
freeGroups(&metadata->groups, metadata->n_groups);
return -1;
}
}
return ret;
}
int modbSyncMetadataGroups(stored_conn *sconn, modb_ref *modb,
unsigned int metadata_id, size_t n_groups, unsigned int *group_ids)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
qry_ret = syncIdMap(
sconn, table, table_len, "mdo_id", "group_id", metadata_id, n_groups, group_ids
);
modbFreeTableName(&table);
return (int)qry_ret;
}
int modbSyncMetadataGroups_va(stored_conn *sconn, modb_ref *modb,
unsigned int metadata_id, size_t n_groups, ...)
{
va_list args;
char *table;
size_t table_len;
int64_t qry_ret;
va_start(args, n_groups);
modbTableName(&table, &table_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
qry_ret = syncIdMap_va(
sconn, table, table_len, "mdo_id", "group_id", metadata_id, n_groups, args
);
modbFreeTableName(&table);
va_end(args);
return (int)qry_ret;
}
int modbIsLinked_Metadata_Group(stored_conn *sconn, modb_ref *modb,
unsigned int metadata_id, unsigned int group_id)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
qry_ret = hasIdMap(sconn, table, table_len, "mdo_id", "group_id", metadata_id, group_id);
modbFreeTableName(&table);
return (int)qry_ret;
}
int modbLink_Metadata_Group(stored_conn *sconn, modb_ref *modb,
unsigned int metadata_id, unsigned int group_id)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
qry_ret = addIdMap(sconn, table, table_len, "mdo_id", "group_id", metadata_id, group_id);
modbFreeTableName(&table);
return (int)qry_ret;
}
int modbUnlink_Metadata_Group(stored_conn *sconn, modb_ref *modb,
unsigned int metadata_id, unsigned int group_id)
{
char *table;
size_t table_len;
int64_t qry_ret;
modbTableName(&table, &table_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
qry_ret = removeIdMap(sconn, table, table_len, "mdo_id", "group_id", metadata_id, group_id);
modbFreeTableName(&table);
return (int)qry_ret;
}
// MODB Group -> Metadatas
int modbFetchGroupMetadataIds(stored_conn *sconn, modb_ref *modb,
unsigned int group_id, int with_deleted,
unsigned int **metadata_ids, size_t *n_ids)
{
char *mg_table, *m_table;
size_t mg_len, m_len;
char *qry;
size_t qry_len;
uint64_t qry_ret;
str_builder *sb;
where_builder *wb;
column_data **col_data;
size_t n_cols;
if ((sb = strbld_create()) == 0) {
return -1;
}
modbTableName(&m_table, &m_len, modb, METADATA_TABLE, STR_LEN(METADATA_TABLE));
modbTableName(&mg_table, &mg_len, modb, MDO_GROUPS_TABLE, STR_LEN(MDO_GROUPS_TABLE));
strbld_str(sb, "SELECT ", 7);
escapeColumnName_sb(sb, mg_table, mg_len, "mdo_id", 6);
strbld_str(sb, " FROM ", 6);
escapeTableName_sb(sb, mg_table, mg_len);
joinStr_sb(sb, " LEFT", 5, 1, m_table, m_len, "mdo_id", 6, mg_table, mg_len, "mdo_id", 6);
wb = where(0, "group_id", EQ, TYPE_ID, 1, group_id);
if (!with_deleted) {
wb = whereAnd(wb, where(m_table, "deleted", IS_NULL, TYPE_RAW, 0));
}
compileWhereBuilder_sb(sb, wb, 1);
modbFreeTableName(&mg_table);
modbFreeTableName(&m_table);
if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) {
return -1;
}
qry_ret = tableQuery(sconn, qry, qry_len, 0, &col_data, &n_cols);
free(qry);
// Query failed
if (qry_ret == (uint64_t)-1) {
return -1;
}
// Zero row result
if (qry_ret == 0) {
freeColumns(col_data, n_cols);
return 0;
}
*metadata_ids = (*col_data)->data.ptr_uint32;
*n_ids = (*col_data)->n_values;
(*col_data)->data.ptr_uint32 = 0;
freeColumns(col_data, n_cols);
return 1;
}