diff --git a/src/R_modb_groups.c b/src/R_modb_groups.c new file mode 100644 index 0000000..eb774d0 --- /dev/null +++ b/src/R_modb_groups.c @@ -0,0 +1,195 @@ +#include + +#include "modb_database.h" +#include "modb_ref.h" +#include "R_helpers_p.h" +#include "R_list_item.h" +#include "R_timestamp.h" +#include "R_modb_groups.h" +#include "R_modb_users.h" + + +SEXP groupToR(struct group_t *group, int with_members) +{ + SEXP r_group; + SEXP r_group_name = R_NilValue; + SEXP r_members = R_NilValue; + SEXP r_attrib_names; + SEXP r_class; + int n_protect = 0; + size_t idx; + + r_group_name = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_group_name, 0, PROTECT(Rf_mkChar(group->name))); + n_protect += 2; + + r_group = PROTECT(Rf_allocVector(VECSXP, 5 + (with_members ? 1 : 0))); + SET_VECTOR_ELT(r_group, 0, PROTECT(Rf_ScalarInteger((int)group->id))); + SET_VECTOR_ELT(r_group, 1, r_group_name); + SET_VECTOR_ELT(r_group, 2, PROTECT(R_Timestamp(group->created_on))); + SET_VECTOR_ELT(r_group, 3, PROTECT(R_Timestamp(group->updated_on))); + SET_VECTOR_ELT(r_group, 4, PROTECT(R_Timestamp(group->deleted_on))); + n_protect += 1 + 4; + + r_attrib_names = PROTECT(Rf_allocVector(STRSXP, 5 + (with_members ? 1 : 0))); + SET_STRING_ELT(r_attrib_names, 0, PROTECT(Rf_mkChar("id"))); + SET_STRING_ELT(r_attrib_names, 1, PROTECT(Rf_mkChar("name"))); + SET_STRING_ELT(r_attrib_names, 2, PROTECT(Rf_mkChar("created_on"))); + SET_STRING_ELT(r_attrib_names, 3, PROTECT(Rf_mkChar("updated_on"))); + SET_STRING_ELT(r_attrib_names, 4, PROTECT(Rf_mkChar("deleted_on"))); + n_protect += 1 + 5; + + if (with_members) { + r_members = PROTECT(Rf_allocVector(VECSXP, (int)group->n_members)); + for (idx = 0; idx < group->n_members; idx++) { + SET_VECTOR_ELT(r_members, (int)idx, PROTECT(userToR(*(group->members + idx), 0))); + } + SET_VECTOR_ELT(r_group, 5, r_members); + n_protect += 1 + (int)group->n_members; + + SET_STRING_ELT(r_attrib_names, 5, PROTECT(Rf_mkChar("members"))); + n_protect++; + } + + Rf_setAttrib(r_group, R_NamesSymbol, r_attrib_names); + + r_class = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_class, 0, PROTECT(Rf_mkChar("list"))); + SET_STRING_ELT(r_class, 1, PROTECT(Rf_mkChar("modb_group"))); + n_protect += 1 + 2; + Rf_setAttrib(r_group, R_ClassSymbol, r_class); + + UNPROTECT(n_protect); + return r_group; +} + +SEXP rmodb_groupId(SEXP r_conn_ref, SEXP r_name) +{ + stored_conn *sconn; + modb_ref modb; + const char *name = 0; + struct group_t *group = 0; + SEXP r_group_id; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + name = Rf_translateCharUTF8(STRING_ELT(r_name, 0)); + if (modbGroupByName(sconn, &modb, name, 0, &group) <= 0) { + return Rf_ScalarInteger(-1); + } + r_group_id = PROTECT(Rf_ScalarInteger((int)group->id)); + freeGroup(&group); + + UNPROTECT(1); + return r_group_id; +} + +SEXP rmodb_groups(SEXP r_conn_ref, SEXP r_with_members, SEXP r_with_deleted) +{ + stored_conn *sconn; + modb_ref modb; + int with_deleted, with_members = 0; + struct group_t **groups = 0; + size_t n_groups = 0; + size_t idx; + SEXP r_groups; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + with_deleted = Rf_asLogical(r_with_deleted); + with_members = Rf_asLogical(r_with_members); + if (modbGroupList(sconn, &modb, with_deleted, with_members, &groups, &n_groups) < 0) { + return R_NilValue; + } + if (n_groups == 0) { + return Rf_allocVector(VECSXP, 0); + } + + r_groups = PROTECT(Rf_allocVector(VECSXP, (int)n_groups)); + for (idx = 0; idx < n_groups; idx++) { + SET_VECTOR_ELT(r_groups, (int)idx, PROTECT(groupToR(*(groups + idx), with_members))); + } + freeGroups(&groups, n_groups); + + UNPROTECT((int)(1 + n_groups)); + return r_groups; +} +SEXP rmodb_group(SEXP r_conn_ref, SEXP r_id, SEXP r_with_members) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int group_id = 0; + int with_members = 0; + struct group_t *group = 0; + SEXP r_group; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + group_id = (unsigned int)Rf_asInteger(r_id); + with_members = Rf_asLogical(r_with_members); + if (modbGroupById(sconn, &modb, group_id, with_members, &group) <= 0) { + return R_NilValue; + } + r_group = PROTECT(groupToR(group, with_members)); + freeGroup(&group); + + UNPROTECT(1); + return r_group; +} + +SEXP rmodb_createGroup(SEXP r_conn_ref, SEXP r_id, SEXP r_name) +{ + stored_conn *sconn; + modb_ref modb; + struct group_t group; + int64_t res; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + bzero(&group, sizeof(struct group_t)); + group.id = (unsigned int)Rf_asInteger(r_id); + group.name_c = Rf_translateCharUTF8(STRING_ELT(r_name, 0)); + res = modbGroupCreate(sconn, &modb, &group); + return Rf_ScalarReal((double)res); +} +SEXP rmodb_deleteGroup(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int group_id = 0; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + group_id = (unsigned int)Rf_asInteger(r_id); + return Rf_ScalarLogical(modbGroupDelete(sconn, &modb, group_id)); +} diff --git a/src/R_modb_groups.h b/src/R_modb_groups.h new file mode 100644 index 0000000..9034aa1 --- /dev/null +++ b/src/R_modb_groups.h @@ -0,0 +1,17 @@ +#ifndef H__R_MODB_GROUPS__ +#define H__R_MODB_GROUPS__ + +#include +#include "modb_groups.h" + +SEXP groupToR(struct group_t *group, int with_members); + +SEXP rmodb_groupId(SEXP r_conn_ref, SEXP r_name); + +SEXP rmodb_groups(SEXP r_conn_ref, SEXP r_with_members, SEXP r_with_deleted); +SEXP rmodb_group(SEXP r_conn_ref, SEXP r_id, SEXP r_with_members); + +SEXP rmodb_createGroup(SEXP r_conn_ref, SEXP r_id, SEXP r_name); +SEXP rmodb_deleteGroup(SEXP r_conn_ref, SEXP r_id); + +#endif // H__R_MODB_GROUPS__ diff --git a/src/R_modb_metaobjects.c b/src/R_modb_metaobjects.c new file mode 100644 index 0000000..533d8a7 --- /dev/null +++ b/src/R_modb_metaobjects.c @@ -0,0 +1,542 @@ +#include +#include + +#include "modb_database.h" +#include "modb_ref.h" +#include "R_helpers_p.h" +#include "R_list_item.h" +#include "R_timestamp.h" +#include "R_modb_metaobjects.h" +#include "R_modb_groups.h" +#include "R_modb_users.h" +#include "R_memory-object.h" +#include "R_magic.h" + + + +SEXP metadataToR(struct metadata_t *metadata) +{ + SEXP r_metadata; + SEXP r_title; + SEXP r_groups = R_NilValue; + SEXP r_attrib_names; + SEXP r_class; + int n_protect = 0, with_ext = 0, with_obj = 0; + size_t idx; + + if (metadata->object) { + with_obj = 1; + } + if (metadata->ext) { + with_ext = 1; + } + + r_title = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_title, 0, PROTECT(Rf_mkChar(metadata->title))); + n_protect += 2; + + r_groups = PROTECT(Rf_allocVector(VECSXP, (int)metadata->n_groups)); + for (idx = 0; idx < metadata->n_groups; idx++) { + SET_VECTOR_ELT(r_groups, (int)idx, PROTECT(groupToR(*(metadata->groups + idx), 0))); + } + n_protect += 1 + (int)metadata->n_groups; + + r_metadata = PROTECT(Rf_allocVector(VECSXP, 7 + with_ext + with_obj)); + SET_VECTOR_ELT(r_metadata, 0, PROTECT(Rf_ScalarInteger((int)metadata->id))); + SET_VECTOR_ELT(r_metadata, 1, r_title); + SET_VECTOR_ELT(r_metadata, 2, PROTECT(userToR(metadata->owner, 0))); + SET_VECTOR_ELT(r_metadata, 3, r_groups); + SET_VECTOR_ELT(r_metadata, 4, PROTECT(R_Timestamp(metadata->created_on))); + SET_VECTOR_ELT(r_metadata, 5, PROTECT(R_Timestamp(metadata->updated_on))); + SET_VECTOR_ELT(r_metadata, 6, PROTECT(R_Timestamp(metadata->deleted_on))); + n_protect += 1 + 5; + + if (with_ext) { + SET_VECTOR_ELT(r_metadata, 7, PROTECT(metadataExtToR(metadata->ext))); + n_protect++; + } + + if (with_obj) { + SET_VECTOR_ELT(r_metadata, 7 + with_ext, PROTECT(objectToR(metadata->object))); + n_protect++; + } + + + r_attrib_names = PROTECT(Rf_allocVector(STRSXP, 7 + with_ext + with_obj)); + SET_STRING_ELT(r_attrib_names, 0, PROTECT(Rf_mkChar("id"))); + SET_STRING_ELT(r_attrib_names, 1, PROTECT(Rf_mkChar("title"))); + SET_STRING_ELT(r_attrib_names, 2, PROTECT(Rf_mkChar("owner"))); + SET_STRING_ELT(r_attrib_names, 3, PROTECT(Rf_mkChar("groups"))); + SET_STRING_ELT(r_attrib_names, 4, PROTECT(Rf_mkChar("created_on"))); + SET_STRING_ELT(r_attrib_names, 5, PROTECT(Rf_mkChar("updated_on"))); + SET_STRING_ELT(r_attrib_names, 6, PROTECT(Rf_mkChar("deleted_on"))); + n_protect += 1 + 7; + + if (with_ext) { + SET_STRING_ELT(r_attrib_names, 7, PROTECT(Rf_mkChar("ext"))); + n_protect++; + } + + if (with_obj) { + SET_STRING_ELT(r_attrib_names, 7 + with_ext, PROTECT(Rf_mkChar("object"))); + n_protect++; + } + + Rf_setAttrib(r_metadata, R_NamesSymbol, r_attrib_names); + + r_class = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_class, 0, PROTECT(Rf_mkChar("list"))); + SET_STRING_ELT(r_class, 1, PROTECT(Rf_mkChar("modb_metaObject"))); + Rf_setAttrib(r_metadata, R_ClassSymbol, r_class); + n_protect += 1 + 2; + + UNPROTECT(n_protect); + return r_metadata; +} +SEXP objectToR(struct object_t *object) +{ + struct r_memoryobject_t mo; + + if (object->data_c == 0) { + object->data_c = object->data; + } + + mo.buf = (char *)object->data_c; + mo.buf_size = object->data_len; + if (R_VERSION >= R_Version(3,0,0)) { + mo.magic = R_MAGIC_XDR_V3; + } else { + mo.magic = R_MAGIC_XDR_V2; + } + + return memoryToRObject(mo); +} +SEXP metadataExtToR(struct meta_ext_t *ext) +{ + SEXP r_ext; + SEXP r_tmp = R_NilValue; + SEXP r_attrib_names; + int n_protect = 0; + size_t idx; + struct meta_ext_value_t *ext_value; + + + r_ext = PROTECT(Rf_allocVector(VECSXP, 1 + (int)ext->n_values)); + n_protect++; + + r_attrib_names = PROTECT(Rf_allocVector(STRSXP, 1 + (int)ext->n_values)); + n_protect++; + + for (idx = 0; idx < ext->n_values; idx++) { + ext_value = *(ext->values + idx); + switch(ext_value->type) { + case VTYPE_RAW: + r_tmp = PROTECT(objectToR(ext_value->value.raw)); + break; + case VTYPE_BOOL: + r_tmp = PROTECT(Rf_ScalarLogical(ext_value->value.bool)); + break; + case VTYPE_INT32: + r_tmp = PROTECT(Rf_ScalarInteger(ext_value->value.int32)); + break; + case VTYPE_DOUBLE: + r_tmp = PROTECT(Rf_ScalarReal(ext_value->value.dbl)); + break; + case VTYPE_STRING: + r_tmp = PROTECT(Rf_allocVector(STRSXP, 1)); + n_protect++; + SET_STRING_ELT(r_tmp, 0, PROTECT(Rf_mkChar(ext_value->value.str))); + break; + case VTYPE_TIMESTAMP: + r_tmp = PROTECT(R_Timestamp(ext_value->value.ts)); + break; + case VTYPE_ID: + r_tmp = PROTECT(Rf_ScalarInteger((int)ext_value->value.id)); + break; + } + SET_VECTOR_ELT(r_ext, 1 + (int)idx, r_tmp); + SET_STRING_ELT(r_attrib_names, 1 + (int)idx, PROTECT(Rf_mkChar(ext_value->key_c))); + n_protect += 2; + } + + Rf_setAttrib(r_ext, R_NamesSymbol, r_attrib_names); + + UNPROTECT(n_protect); + return r_ext; +} + +SEXP rmodb_metaobjectId(SEXP r_conn_ref, SEXP r_query) +{ + return R_NilValue; +} + +SEXP rmodb_metaobject(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int mo_id; + struct metadata_t *metadata; + SEXP r_metadata; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + mo_id = (unsigned int)Rf_asInteger(r_id); + if (modbMetadataById(sconn, &modb, mo_id, &metadata) <= 0) { + return R_NilValue; + } + + if (modbFetchMetadataOwner(sconn, &modb, metadata) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + if (modbFetchMetadataGroups(sconn, &modb, metadata, 0) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + if (modbFetchMetadataExtended(sconn, &modb, metadata) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + if (modbFetchMetadataObject(sconn, &modb, metadata) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + + r_metadata = metadataToR(metadata); + + freeMetadata(&metadata); + + return r_metadata; +} +SEXP rmodb_metadata(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int mo_id; + struct metadata_t *metadata; + SEXP r_metadata; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + mo_id = (unsigned int)Rf_asInteger(r_id); + if (modbMetadataById(sconn, &modb, mo_id, &metadata) <= 0) { + return R_NilValue; + } + if (modbFetchMetadataOwner(sconn, &modb, metadata) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + if (modbFetchMetadataGroups(sconn, &modb, metadata, 0) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + if (modbFetchMetadataExtended(sconn, &modb, metadata) <= 0) { + freeMetadata(&metadata); + return R_NilValue; + } + + r_metadata = metadataToR(metadata); + + freeMetadata(&metadata); + + return r_metadata; +} +SEXP rmodb_object(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int mo_id; + struct object_t *object; + SEXP r_object; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + mo_id = (unsigned int)Rf_asInteger(r_id); + if (modbObjectById(sconn, &modb, mo_id, &object) <= 0) { + return R_NilValue; + } + + r_object = objectToR(object); + + freeObject(&object); + + return r_object; +} + + +SEXP rmodb_metaobjects(SEXP r_conn_ref, SEXP r_with_deleted) +{ + stored_conn *sconn; + modb_ref modb; + int with_deleted = 0; + struct metadata_t **metadata_list = 0, *metadata; + size_t n_metadatas = 0; + size_t idx; + SEXP r_metadatas; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + with_deleted = Rf_asLogical(r_with_deleted); + if (modbMetadataList(sconn, &modb, with_deleted, &metadata_list, &n_metadatas) <= 0) { + return R_NilValue; + } + + r_metadatas = PROTECT(Rf_allocVector(VECSXP, (int)n_metadatas)); + for (idx = 0; idx < n_metadatas; idx++) { + metadata = *(metadata_list + idx); + + if (modbFetchMetadataOwner(sconn, &modb, metadata) < 0) { + freeMetadata(&metadata); + UNPROTECT(1 + (int)idx); + printf("FAILED"); + return R_NilValue; + } + if (modbFetchMetadataGroups(sconn, &modb, metadata, 0) < 0) { + freeMetadataList(&metadata_list, n_metadatas); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + if (modbFetchMetadataExtended(sconn, &modb, metadata) < 0) { + freeMetadataList(&metadata_list, n_metadatas); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + if (modbFetchMetadataObject(sconn, &modb, metadata) < 0) { + freeMetadataList(&metadata_list, n_metadatas); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + + SET_VECTOR_ELT(r_metadatas, (int)idx, PROTECT(metadataToR(metadata))); + } + freeMetadataList(&metadata_list, n_metadatas); + + UNPROTECT(1 + (int)n_metadatas); + return r_metadatas; +} +SEXP rmodb_metadatas(SEXP r_conn_ref, SEXP r_with_deleted) +{ + stored_conn *sconn; + modb_ref modb; + int with_deleted = 0; + struct metadata_t **metadata_list = 0, *metadata; + size_t n_metadatas = 0; + size_t idx; + SEXP r_metadatas; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + with_deleted = Rf_asLogical(r_with_deleted); + if (modbMetadataList(sconn, &modb, with_deleted, &metadata_list, &n_metadatas) <= 0) { + return R_NilValue; + } + + r_metadatas = PROTECT(Rf_allocVector(VECSXP, (int)n_metadatas)); + for (idx = 0; idx < n_metadatas; idx++) { + metadata = *(metadata_list + idx); + + if (modbFetchMetadataOwner(sconn, &modb, metadata) < 0) { + freeMetadata(&metadata); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + if (modbFetchMetadataGroups(sconn, &modb, metadata, 0) < 0) { + freeMetadataList(&metadata_list, n_metadatas); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + if (modbFetchMetadataExtended(sconn, &modb, metadata) < 0) { + freeMetadataList(&metadata_list, n_metadatas); + UNPROTECT(1 + (int)idx); + return R_NilValue; + } + + SET_VECTOR_ELT(r_metadatas, (int)idx, PROTECT(metadataToR(metadata))); + } + freeMetadataList(&metadata_list, n_metadatas); + + UNPROTECT((int)(1 + n_metadatas)); + return r_metadatas; +} + +SEXP rmodb_createMetaobject(SEXP r_conn_ref, SEXP r_id, + SEXP r_metadata, SEXP r_object, SEXP r_extendedMeta) +{ + stored_conn *sconn; + modb_ref modb; + struct metadata_t metadata; + struct object_t object; + struct meta_ext_t *metadata_ext; + struct meta_ext_value_t *ext_value; + struct r_memoryobject_t *memObj; + SEXP r_tmp, r_names; + int i; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + memset(&metadata, 0, sizeof(struct metadata_t)); + + metadata.id = (unsigned int)Rf_asInteger(r_id); + metadata.title_c = Rf_translateCharUTF8(STRING_ELT(R_listItem(r_metadata, "title"), 0)); + metadata.owner_id = (unsigned int)Rf_asInteger(R_listItem(r_metadata, "owner_id")); + + if ((metadata.id = modbMetadataCreate(sconn, &modb, &metadata)) <= 0) { + return Rf_ScalarLogical(FALSE); + } + + r_tmp = R_listItem(r_metadata, "group_ids"); + if (r_tmp != R_NilValue) { + if (LENGTH(r_tmp) == 1) { + if (modbLink_Metadata_Group( + sconn, &modb, metadata.id, + (unsigned int)Rf_asInteger(r_tmp)) <= 0) { + modbMetadataDestroy(sconn, &modb, metadata.id); + return Rf_ScalarLogical(FALSE); + } + } else { + for (i = 0; i < LENGTH(r_tmp); i++) { + if (modbLink_Metadata_Group( + sconn, &modb, metadata.id, + (unsigned int)Rf_asInteger(VECTOR_ELT(r_tmp, i))) <= 0) { + modbMetadataDestroy(sconn, &modb, metadata.id); + modbSyncMetadataGroups(sconn, &modb, metadata.id, 0, 0); + return Rf_ScalarLogical(FALSE); + } + } + } + } + + memObj = robjectToMemory(r_object, R_MAGIC_XDR_V3); + object.id = metadata.id; + object.data_c = memObj->buf; + object.data_len = memObj->buf_size; + if (modbObjectCreate(sconn, &modb, &object) <= 0) { + free(memObj->buf); + free(memObj); + modbSyncMetadataGroups(sconn, &modb, metadata.id, 0, 0); + modbMetadataDestroy(sconn, &modb, metadata.id); + return Rf_ScalarLogical(FALSE); + } + free(memObj->buf); + free(memObj); + + if (LENGTH(r_extendedMeta) > 0) { + if ((metadata_ext = allocMetaExt()) == 0) { + modbObjectDestroy(sconn, &modb, metadata.id); + modbSyncMetadataGroups(sconn, &modb, metadata.id, 0, 0); + modbMetadataDestroy(sconn, &modb, metadata.id); + return Rf_ScalarLogical(FALSE); + } + metadata_ext->id = metadata.id; + metadata_ext->n_values = (size_t)LENGTH(r_extendedMeta); + metadata_ext->values = allocMetaExtValues(metadata_ext->n_values, 1); + if (metadata_ext->values == 0) { + freeMetaExt(&metadata_ext); + modbObjectDestroy(sconn, &modb, metadata.id); + modbSyncMetadataGroups(sconn, &modb, metadata.id, 0, 0); + modbMetadataDestroy(sconn, &modb, metadata.id); + return Rf_ScalarLogical(FALSE); + } + r_names = Rf_getAttrib(r_extendedMeta, R_NamesSymbol); + for (i = 0; i < LENGTH(r_extendedMeta); i++) { + ext_value = *(metadata_ext->values + i); + ext_value->key_c = Rf_translateCharUTF8(STRING_ELT(r_names, i)); + r_tmp = VECTOR_ELT(r_extendedMeta, i); + if (Rf_isNull(r_tmp)) { + ext_value->type = VTYPE_RAW; + ext_value->is_null = 1; + } else { + switch(TYPEOF(r_tmp)) { + case LGLSXP:/* logical vectors */ + ext_value->type = VTYPE_BOOL; + ext_value->value.bool = Rf_asLogical(r_tmp); + break; + case INTSXP:/* integer vectors */ + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = Rf_asInteger(r_tmp); + break; + case REALSXP:/* real variables */ + ext_value->type = VTYPE_DOUBLE; + ext_value->value.dbl = Rf_asReal(r_tmp); + break; + case STRSXP:/* string vectors */ + ext_value->type = VTYPE_STRING; + ext_value->value.str_c = Rf_translateCharUTF8(STRING_ELT(r_tmp, 0)); + ext_value->is_const = 1; + break; + case VECSXP:/* generic vectors */ + break; + default: + break; + // Screwed if I know how to handle this... + } + } + } + if (modbMetaExtCreate(sconn, &modb, metadata_ext) <= 0) { + freeMetaExt(&metadata_ext); + modbObjectDestroy(sconn, &modb, metadata.id); + modbSyncMetadataGroups(sconn, &modb, metadata.id, 0, 0); + modbMetadataDestroy(sconn, &modb, metadata.id); + return Rf_ScalarLogical(FALSE); + } + } + + return Rf_ScalarReal((double)metadata.id); +} +SEXP rmodb_updateMetaobject(SEXP r_conn_ref, SEXP r_id, SEXP r_metaobject) +{ + return R_NilValue; +} +SEXP rmodb_deleteMetaobject(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int mdo_id = 0; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + mdo_id = (unsigned int)Rf_asInteger(r_id); + return Rf_ScalarLogical(modbMetadataDelete(sconn, &modb, mdo_id)); +} diff --git a/src/R_modb_metaobjects.h b/src/R_modb_metaobjects.h new file mode 100644 index 0000000..1349161 --- /dev/null +++ b/src/R_modb_metaobjects.h @@ -0,0 +1,28 @@ +#ifndef H__R_MODB_METAOBJECT__ +#define H__R_MODB_METAOBJECT__ + +#include +#include "modb_metadata.h" +#include "modb_objects.h" +#include "modb_metadata_ext.h" + +SEXP metadataToR(struct metadata_t *metadata); +SEXP objectToR(struct object_t *object); +SEXP metadataExtToR(struct meta_ext_t *ext); + +SEXP rmodb_metaobjectId(SEXP r_conn_ref, SEXP r_query); + +SEXP rmodb_metaobject(SEXP r_conn_ref, SEXP r_id); +SEXP rmodb_metadata(SEXP r_conn_ref, SEXP r_id); +SEXP rmodb_object(SEXP r_conn_ref, SEXP r_id); + +SEXP rmodb_metaobjects(SEXP r_conn_ref, SEXP r_with_deleted); +SEXP rmodb_metadatas(SEXP r_conn_ref, SEXP r_with_deleted); + +SEXP rmodb_createMetaobject(SEXP r_conn_ref, SEXP r_id, + SEXP r_metadata, SEXP r_object, SEXP r_extendedMeta); +SEXP rmodb_updateMetaobject(SEXP r_conn_ref, SEXP r_id, SEXP r_metaobject); +SEXP rmodb_deleteMetaobject(SEXP r_conn_ref, SEXP r_id); + + +#endif // H__R_MODB_METAOBJECT__ diff --git a/src/R_modb_user_groups.c b/src/R_modb_user_groups.c new file mode 100644 index 0000000..8d3fe26 --- /dev/null +++ b/src/R_modb_user_groups.c @@ -0,0 +1,54 @@ +#include +#include + +#include "modb_database.h" +#include "modb_ref.h" +#include "R_modb_users.h" +#include "R_helpers_p.h" +#include "R_modb_user_groups.h" + +SEXP rmodb_userAddGroup(SEXP r_conn_ref, SEXP r_user_id, SEXP r_group_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int user_id, group_id; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + user_id = (unsigned int)Rf_asInteger(r_user_id); + group_id = (unsigned int)Rf_asInteger(r_group_id); + if (modbLink_User_Group(sconn, &modb, user_id, group_id) <= 0) { + return Rf_ScalarLogical(FALSE); + } + + return Rf_ScalarLogical(TRUE); +} + +SEXP rmodb_userRemoveGroup(SEXP r_conn_ref, SEXP r_user_id, SEXP r_group_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int user_id, group_id; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + user_id = (unsigned int)Rf_asInteger(r_user_id); + group_id = (unsigned int)Rf_asInteger(r_group_id); + if (modbUnlink_User_Group(sconn, &modb, user_id, group_id) <= 0) { + return Rf_ScalarLogical(FALSE); + } + + return Rf_ScalarLogical(TRUE); +} diff --git a/src/R_modb_user_groups.h b/src/R_modb_user_groups.h new file mode 100644 index 0000000..7de5504 --- /dev/null +++ b/src/R_modb_user_groups.h @@ -0,0 +1,9 @@ +#ifndef H__R_MODB_USER_GROUPS__ +#define H__R_MODB_USER_GROUPS__ + +#include + +SEXP rmodb_userAddGroup(SEXP r_conn_ref, SEXP r_user_id, SEXP r_group_id); +SEXP rmodb_userRemoveGroup(SEXP r_conn_ref, SEXP r_user_id, SEXP r_group_id); + +#endif // H__R_MODB_USER_GROUPS__ diff --git a/src/R_modb_users.c b/src/R_modb_users.c new file mode 100644 index 0000000..f888f75 --- /dev/null +++ b/src/R_modb_users.c @@ -0,0 +1,209 @@ +#include + +#include "R_helpers_p.h" +#include "R_list_item.h" +#include "R_timestamp.h" +#include "modb_database.h" +#include "modb_ref.h" +#include "R_modb_users.h" +#include "R_modb_groups.h" + + +SEXP userToR(struct user_t *user, int with_groups) +{ + SEXP r_user; + SEXP r_username; + SEXP r_email; + SEXP r_groups = R_NilValue; + SEXP r_attrib_names; + SEXP r_class; + int n_protect = 0; + size_t idx; + + r_username = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_username, 0, PROTECT(Rf_mkChar(user->username_c))); + n_protect += 2; + + r_email = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_email, 0, PROTECT(Rf_mkChar(user->email_c))); + n_protect += 2; + + r_user = PROTECT(Rf_allocVector(VECSXP, 6 + (with_groups ? 1 : 0))); + SET_VECTOR_ELT(r_user, 0, PROTECT(Rf_ScalarInteger((int)user->id))); + SET_VECTOR_ELT(r_user, 1, r_username); + SET_VECTOR_ELT(r_user, 2, r_email); + SET_VECTOR_ELT(r_user, 3, PROTECT(R_Timestamp(user->created_on))); + SET_VECTOR_ELT(r_user, 4, PROTECT(R_Timestamp(user->updated_on))); + SET_VECTOR_ELT(r_user, 5, PROTECT(R_Timestamp(user->deleted_on))); + n_protect += 1 + 4; + + r_attrib_names = PROTECT(Rf_allocVector(STRSXP, 6 + (with_groups ? 1 : 0))); + SET_STRING_ELT(r_attrib_names, 0, PROTECT(Rf_mkChar("id"))); + SET_STRING_ELT(r_attrib_names, 1, PROTECT(Rf_mkChar("username"))); + SET_STRING_ELT(r_attrib_names, 2, PROTECT(Rf_mkChar("email"))); + SET_STRING_ELT(r_attrib_names, 3, PROTECT(Rf_mkChar("created_on"))); + SET_STRING_ELT(r_attrib_names, 4, PROTECT(Rf_mkChar("updated_on"))); + SET_STRING_ELT(r_attrib_names, 5, PROTECT(Rf_mkChar("deleted_on"))); + n_protect += 1 + 6; + + if (with_groups) { + r_groups = PROTECT(Rf_allocVector(VECSXP, (int)user->n_groups)); + for (idx = 0; idx < user->n_groups; idx++) { + SET_VECTOR_ELT(r_groups, (int)idx, PROTECT(groupToR(*(user->groups + idx), 0))); + } + SET_VECTOR_ELT(r_user, 6, r_groups); + n_protect += 1 + (int)user->n_groups; + + SET_STRING_ELT(r_attrib_names, 6, PROTECT(Rf_mkChar("groups"))); + n_protect++; + } + Rf_setAttrib(r_user, R_NamesSymbol, r_attrib_names); + + r_class = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_class, 0, PROTECT(Rf_mkChar("list"))); + SET_STRING_ELT(r_class, 1, PROTECT(Rf_mkChar("modb_user"))); + Rf_setAttrib(r_user, R_ClassSymbol, r_class); + n_protect += 1 + 2; + + UNPROTECT(n_protect); + return r_user; +} + +SEXP rmodb_userId(SEXP r_conn_ref, SEXP r_name_or_email) +{ + stored_conn *sconn; + modb_ref modb; + const char *search = 0; + int is_email = 0; + size_t idx = 0; + struct user_t *user = 0; + SEXP r_user_id; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + search = Rf_translateCharUTF8(STRING_ELT(r_name_or_email, 0)); + for (idx = 0; idx < strlen(search); idx++) { + if (*(search + idx) == '@') { + is_email = 1; + } + } + if (!is_email && modbUserByName(sconn, &modb, search, 0, &user) <= 0) { + return Rf_ScalarInteger(-1); + } + if (is_email && modbUserByEmail(sconn, &modb, search, 0, &user) <= 0) { + return Rf_ScalarInteger(-1); + } + r_user_id = PROTECT(Rf_ScalarInteger((int)user->id)); + freeUser(&user); + + UNPROTECT(1); + return r_user_id; +} + +SEXP rmodb_users(SEXP r_conn_ref, SEXP r_with_groups, SEXP r_with_deleted) +{ + stored_conn *sconn; + modb_ref modb; + int with_deleted = 0, with_groups = 0; + struct user_t **users = 0; + size_t n_users = 0; + size_t idx; + SEXP r_users; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + with_deleted = Rf_asLogical(r_with_deleted); + with_groups = Rf_asLogical(r_with_groups); + if (modbUserList(sconn, &modb, with_deleted, with_groups, &users, &n_users) <= 0) { + return R_NilValue; + } + r_users = PROTECT(Rf_allocVector(VECSXP, (int)n_users)); + for (idx = 0; idx < n_users; idx++) { + SET_VECTOR_ELT(r_users, (int)idx, PROTECT(userToR(*(users + idx), with_groups))); + } + freeUsers(&users, n_users); + + UNPROTECT((int)(1 + n_users)); + return r_users; +} +SEXP rmodb_user(SEXP r_conn_ref, SEXP r_id, SEXP r_with_groups) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int user_id = 0; + int with_groups = 0; + struct user_t *user = 0; + SEXP r_user; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + user_id = (unsigned int)Rf_asInteger(r_id); + with_groups = Rf_asLogical(r_with_groups); + if (modbUserById(sconn, &modb, user_id, with_groups, &user) <= 0) { + return R_NilValue; + } + r_user = PROTECT(userToR(user, with_groups)); + freeUser(&user); + + UNPROTECT(1); + return r_user; +} + +SEXP rmodb_createUser(SEXP r_conn_ref, SEXP r_id, SEXP r_name, SEXP r_email) +{ + stored_conn *sconn; + modb_ref modb; + struct user_t user; + int64_t res; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + bzero(&user, sizeof(struct user_t)); + user.id = (unsigned int)Rf_asInteger(r_id); + user.username_c = Rf_translateCharUTF8(STRING_ELT(r_name, 0)); + user.email_c = Rf_translateCharUTF8(STRING_ELT(r_email, 0)); + res = modbUserCreate(sconn, &modb, &user); + + return Rf_ScalarReal((double)res); +} +SEXP rmodb_deleteUser(SEXP r_conn_ref, SEXP r_id) +{ + stored_conn *sconn; + modb_ref modb; + unsigned int user_id = 0; + + if ((sconn = getConnectionByRef(r_conn_ref)) == 0) { + Rf_error("invalid connection reference\n"); + } + + if (!modbFindUse(sconn, &modb)) { + Rf_error("invalid modb reference\n"); + } + + user_id = (unsigned int)Rf_asInteger(r_id); + return Rf_ScalarLogical(modbUserDelete(sconn, &modb, user_id)); +} diff --git a/src/R_modb_users.h b/src/R_modb_users.h new file mode 100644 index 0000000..3ef8aa3 --- /dev/null +++ b/src/R_modb_users.h @@ -0,0 +1,17 @@ +#ifndef H__R_MODB_USERS__ +#define H__R_MODB_USERS__ + +#include +#include "modb_users.h" + +SEXP userToR(struct user_t *user, int with_groups); + +SEXP rmodb_userId(SEXP r_conn_ref, SEXP r_name_or_email); + +SEXP rmodb_users(SEXP r_conn_ref, SEXP r_with_groups, SEXP r_with_deleted); +SEXP rmodb_user(SEXP r_conn_ref, SEXP r_id, SEXP r_with_groups); + +SEXP rmodb_createUser(SEXP r_conn_ref, SEXP r_id, SEXP r_name, SEXP r_email); +SEXP rmodb_deleteUser(SEXP r_conn_ref, SEXP r_id); + +#endif // H__R_MODB_USERS__ diff --git a/src/R_timestamp.c b/src/R_timestamp.c new file mode 100644 index 0000000..d5f22ab --- /dev/null +++ b/src/R_timestamp.c @@ -0,0 +1,115 @@ +#define __USE_MISC +#include + +#include "R_timestamp.h" + + +SEXP R_Timestamp(int64_t ts) +{ + SEXP r_ts; + SEXP r_class; + SEXP r_tzone; + + if (ts == 0) { + return(Rf_ScalarReal(R_NaReal)); + } + + r_ts = PROTECT(Rf_ScalarReal((double)ts)); + + r_class = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_class, 0, PROTECT(Rf_mkChar("POSIXct"))); + SET_STRING_ELT(r_class, 1, PROTECT(Rf_mkChar("POSIXt"))); + + r_tzone = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_tzone, 0, PROTECT(Rf_mkChar(""))); + + Rf_setAttrib(r_ts, R_ClassSymbol, r_class); + Rf_setAttrib(r_ts, Rf_install("tzone"), r_tzone); + + UNPROTECT(1 + 3 + 2); + return r_ts; +} + +SEXP R_TimestampExt(int64_t ts) +{ + SEXP r_ts; + SEXP r_names; + SEXP r_zone; + SEXP r_class; + SEXP r_tzone; + struct tm *tmval; + + tmval = localtime((time_t *)&ts); + + r_zone = PROTECT(Rf_allocVector(STRSXP, 1)); + SET_STRING_ELT(r_zone, 0, PROTECT(Rf_mkChar(tmval->tm_zone))); + + r_ts = PROTECT(Rf_allocVector(VECSXP, 11)); + SET_VECTOR_ELT(r_ts, 0, PROTECT(Rf_ScalarInteger(tmval->tm_sec))); + SET_VECTOR_ELT(r_ts, 1, PROTECT(Rf_ScalarInteger(tmval->tm_min))); + SET_VECTOR_ELT(r_ts, 2, PROTECT(Rf_ScalarInteger(tmval->tm_hour))); + SET_VECTOR_ELT(r_ts, 3, PROTECT(Rf_ScalarInteger(tmval->tm_mday))); + SET_VECTOR_ELT(r_ts, 4, PROTECT(Rf_ScalarInteger(tmval->tm_mon))); + SET_VECTOR_ELT(r_ts, 5, PROTECT(Rf_ScalarInteger(tmval->tm_year))); + SET_VECTOR_ELT(r_ts, 6, PROTECT(Rf_ScalarInteger(tmval->tm_wday))); + SET_VECTOR_ELT(r_ts, 7, PROTECT(Rf_ScalarInteger(tmval->tm_yday))); + SET_VECTOR_ELT(r_ts, 8, PROTECT(Rf_ScalarInteger(tmval->tm_isdst))); + SET_VECTOR_ELT(r_ts, 9, r_zone); + SET_VECTOR_ELT(r_ts, 10, PROTECT(Rf_ScalarInteger((int)tmval->tm_gmtoff))); + + r_names = PROTECT(Rf_allocVector(STRSXP, 11)); + SET_STRING_ELT(r_names, 0, PROTECT(Rf_mkChar("sec"))); + SET_STRING_ELT(r_names, 1, PROTECT(Rf_mkChar("min"))); + SET_STRING_ELT(r_names, 2, PROTECT(Rf_mkChar("hour"))); + SET_STRING_ELT(r_names, 3, PROTECT(Rf_mkChar("mday"))); + SET_STRING_ELT(r_names, 4, PROTECT(Rf_mkChar("mon"))); + SET_STRING_ELT(r_names, 5, PROTECT(Rf_mkChar("year"))); + SET_STRING_ELT(r_names, 6, PROTECT(Rf_mkChar("wday"))); + SET_STRING_ELT(r_names, 7, PROTECT(Rf_mkChar("yday"))); + SET_STRING_ELT(r_names, 8, PROTECT(Rf_mkChar("isdst"))); + SET_STRING_ELT(r_names, 9, PROTECT(Rf_mkChar("zone"))); + SET_STRING_ELT(r_names, 10, PROTECT(Rf_mkChar("gmtoff"))); + + r_class = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_class, 0, PROTECT(Rf_mkChar("POSIXlt"))); + SET_STRING_ELT(r_class, 1, PROTECT(Rf_mkChar("POSIXt"))); + + r_tzone = PROTECT(Rf_allocVector(STRSXP, 2)); + SET_STRING_ELT(r_tzone, 0, PROTECT(Rf_mkChar(""))); + SET_STRING_ELT(r_tzone, 1, PROTECT(Rf_mkChar(tmval->tm_zone))); + + Rf_setAttrib(r_ts, R_NamesSymbol, r_names); + Rf_setAttrib(r_ts, R_ClassSymbol, r_class); + Rf_setAttrib(r_ts, Rf_install("tzone"), r_tzone); + + UNPROTECT(2 + 11 + 12 + 3 + 3); + return r_ts; +} + + +int64_t R_TimestampUnix(SEXP r_ts) +{ + return (int64_t)(Rf_asReal(VECTOR_ELT(r_ts, 0)) / 1); +} + +int64_t R_TimestampExtUnix(SEXP r_ts) +{ + time_t tunix; + struct tm tmval; + + tmval.tm_sec = Rf_asInteger(VECTOR_ELT(r_ts, 0)); + tmval.tm_min = Rf_asInteger(VECTOR_ELT(r_ts, 1)); + tmval.tm_hour = Rf_asInteger(VECTOR_ELT(r_ts, 2)); + tmval.tm_mday = Rf_asInteger(VECTOR_ELT(r_ts, 3)); + tmval.tm_mon = Rf_asInteger(VECTOR_ELT(r_ts, 4)); + tmval.tm_year = Rf_asInteger(VECTOR_ELT(r_ts, 5)); + tmval.tm_wday = Rf_asInteger(VECTOR_ELT(r_ts, 6)); + tmval.tm_yday = Rf_asInteger(VECTOR_ELT(r_ts, 7)); + tmval.tm_isdst = Rf_asInteger(VECTOR_ELT(r_ts, 8)); + tmval.tm_zone = Rf_translateCharUTF8(STRING_ELT(VECTOR_ELT(r_ts, 9), 0)); + tmval.tm_gmtoff = Rf_asInteger(VECTOR_ELT(r_ts, 10)); + + tunix = mktime(&tmval); + + return tunix; +} diff --git a/src/R_timestamp.h b/src/R_timestamp.h new file mode 100644 index 0000000..ec34660 --- /dev/null +++ b/src/R_timestamp.h @@ -0,0 +1,13 @@ +#ifndef H__R_TIMESTAMP__ +#define H__R_TIMESTAMP__ + +#include +#include + +SEXP R_Timestamp(int64_t ts); +SEXP R_TimestampExt(int64_t ts); + +int64_t R_TimestampUnix(SEXP r_ts); +int64_t R_TimestampExtUnix(SEXP r_ts); + +#endif // H__R_TIMESTAMP__