Skip to content

Commit

Permalink
Add option to entity JSON serializer to serialize incoming edges
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Aug 3, 2023
1 parent ff10198 commit bc3ec54
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 7 deletions.
77 changes: 75 additions & 2 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -35078,7 +35078,7 @@ int flecs_json_serialize_children_alerts(
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter(ECS_CONST_CAST(ecs_world_t*, world), {
.storage = &f,
.terms = {{ ecs_pair(EcsChildOf, entity) }}
.terms = {{ .id = ecs_pair(EcsChildOf, entity) }}
});

ecs_iter_t it = ecs_filter_iter(world, &f);
Expand Down Expand Up @@ -35138,6 +35138,63 @@ int flecs_json_serialize_alerts(
return 0;
}

static
int flecs_json_serialize_refs_idr(
const ecs_world_t *world,
ecs_strbuf_t *buf,
ecs_id_record_t *idr)
{
char *id_str = ecs_id_str(world, ecs_pair_first(world, idr->id));

flecs_json_member(buf, id_str);
ecs_os_free(id_str);

flecs_json_array_push(buf);

ecs_table_cache_iter_t it;
if (idr && flecs_table_cache_all_iter((ecs_table_cache_t*)idr, &it)) {
const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&it, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
int32_t i, count = ecs_table_count(table);
ecs_entity_t *entities = ecs_vec_first(&table->data.entities);
for (i = 0; i < count; i ++) {
ecs_entity_t e = entities[i];
flecs_json_next(buf);
flecs_json_path(buf, world, e);
}
}
}

flecs_json_array_pop(buf);

return 0;
}

static
int flecs_json_serialize_refs(
const ecs_world_t *world,
ecs_strbuf_t *buf,
ecs_entity_t entity,
ecs_entity_t relationship)
{
ecs_id_record_t *idr = flecs_id_record_get(world,
ecs_pair(relationship, entity));

if (idr) {
if (relationship == EcsWildcard) {
ecs_id_record_t *cur = idr;
while ((cur = cur->second.next)) {
flecs_json_serialize_refs_idr(world, buf, cur);
}
} else {
flecs_json_serialize_refs_idr(world, buf, idr);
}
}

return 0;
}

int ecs_entity_to_json_buf(
const ecs_world_t *world,
ecs_entity_t entity,
Expand Down Expand Up @@ -35231,6 +35288,15 @@ int ecs_entity_to_json_buf(
}
}

if (desc && desc->serialize_refs) {
flecs_json_memberl(buf, "refs");
flecs_json_object_push(buf);
if (flecs_json_serialize_refs(world, buf, entity, desc->serialize_refs)) {
goto error;
}
flecs_json_object_pop(buf);
}

flecs_json_object_pop(buf);

return 0;
Expand Down Expand Up @@ -37725,6 +37791,7 @@ void flecs_rest_string_param(

static
void flecs_rest_parse_json_ser_entity_params(
ecs_world_t *world,
ecs_entity_to_json_desc_t *desc,
const ecs_http_request_t *req)
{
Expand All @@ -37739,6 +37806,12 @@ void flecs_rest_parse_json_ser_entity_params(
flecs_rest_bool_param(req, "private", &desc->serialize_private);
flecs_rest_bool_param(req, "type_info", &desc->serialize_type_info);
flecs_rest_bool_param(req, "alerts", &desc->serialize_alerts);

char *rel = NULL;
flecs_rest_string_param(req, "refs", &rel);
if (rel) {
desc->serialize_refs = ecs_lookup_fullpath(world, rel);
}
}

static
Expand Down Expand Up @@ -37784,7 +37857,7 @@ bool flecs_rest_reply_entity(
}

ecs_entity_to_json_desc_t desc = ECS_ENTITY_TO_JSON_INIT;
flecs_rest_parse_json_ser_entity_params(&desc, req);
flecs_rest_parse_json_ser_entity_params(world, &desc, req);
if (ecs_entity_to_json_buf(world, e, &reply->body, &desc) != 0) {
ecs_strbuf_reset(&reply->body);
reply->code = 500;
Expand Down
3 changes: 2 additions & 1 deletion flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -12352,10 +12352,11 @@ typedef struct ecs_entity_to_json_desc_t {
bool serialize_values; /**< Serialize component values */
bool serialize_type_info; /**< Serialize type info (requires serialize_values) */
bool serialize_alerts; /**< Serialize active alerts for entity */
ecs_entity_t serialize_refs; /**< Serialize references (incoming edges) for relationship */
} ecs_entity_to_json_desc_t;

#define ECS_ENTITY_TO_JSON_INIT (ecs_entity_to_json_desc_t){true, false,\
false, false, false, false, false, true, false, false, false, false, false }
false, false, false, false, false, true, false, false, false, false, false, false }

/** Serialize entity into JSON string.
* This creates a JSON object with the entity's (path) name, which components
Expand Down
3 changes: 2 additions & 1 deletion include/flecs/addons/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,11 @@ typedef struct ecs_entity_to_json_desc_t {
bool serialize_values; /**< Serialize component values */
bool serialize_type_info; /**< Serialize type info (requires serialize_values) */
bool serialize_alerts; /**< Serialize active alerts for entity */
ecs_entity_t serialize_refs; /**< Serialize references (incoming edges) for relationship */
} ecs_entity_to_json_desc_t;

#define ECS_ENTITY_TO_JSON_INIT (ecs_entity_to_json_desc_t){true, false,\
false, false, false, false, false, true, false, false, false, false, false }
false, false, false, false, false, true, false, false, false, false, false, false }

/** Serialize entity into JSON string.
* This creates a JSON object with the entity's (path) name, which components
Expand Down
68 changes: 67 additions & 1 deletion src/addons/json/serialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@ int flecs_json_serialize_children_alerts(
ecs_filter_t f = ECS_FILTER_INIT;
ecs_filter(ECS_CONST_CAST(ecs_world_t*, world), {
.storage = &f,
.terms = {{ ecs_pair(EcsChildOf, entity) }}
.terms = {{ .id = ecs_pair(EcsChildOf, entity) }}
});

ecs_iter_t it = ecs_filter_iter(world, &f);
Expand Down Expand Up @@ -1079,6 +1079,63 @@ int flecs_json_serialize_alerts(
return 0;
}

static
int flecs_json_serialize_refs_idr(
const ecs_world_t *world,
ecs_strbuf_t *buf,
ecs_id_record_t *idr)
{
char *id_str = ecs_id_str(world, ecs_pair_first(world, idr->id));

flecs_json_member(buf, id_str);
ecs_os_free(id_str);

flecs_json_array_push(buf);

ecs_table_cache_iter_t it;
if (idr && flecs_table_cache_all_iter((ecs_table_cache_t*)idr, &it)) {
const ecs_table_record_t *tr;
while ((tr = flecs_table_cache_next(&it, ecs_table_record_t))) {
ecs_table_t *table = tr->hdr.table;
int32_t i, count = ecs_table_count(table);
ecs_entity_t *entities = ecs_vec_first(&table->data.entities);
for (i = 0; i < count; i ++) {
ecs_entity_t e = entities[i];
flecs_json_next(buf);
flecs_json_path(buf, world, e);
}
}
}

flecs_json_array_pop(buf);

return 0;
}

static
int flecs_json_serialize_refs(
const ecs_world_t *world,
ecs_strbuf_t *buf,
ecs_entity_t entity,
ecs_entity_t relationship)
{
ecs_id_record_t *idr = flecs_id_record_get(world,
ecs_pair(relationship, entity));

if (idr) {
if (relationship == EcsWildcard) {
ecs_id_record_t *cur = idr;
while ((cur = cur->second.next)) {
flecs_json_serialize_refs_idr(world, buf, cur);
}
} else {
flecs_json_serialize_refs_idr(world, buf, idr);
}
}

return 0;
}

int ecs_entity_to_json_buf(
const ecs_world_t *world,
ecs_entity_t entity,
Expand Down Expand Up @@ -1172,6 +1229,15 @@ int ecs_entity_to_json_buf(
}
}

if (desc && desc->serialize_refs) {
flecs_json_memberl(buf, "refs");
flecs_json_object_push(buf);
if (flecs_json_serialize_refs(world, buf, entity, desc->serialize_refs)) {
goto error;
}
flecs_json_object_pop(buf);
}

flecs_json_object_pop(buf);

return 0;
Expand Down
9 changes: 8 additions & 1 deletion src/addons/rest.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ void flecs_rest_string_param(

static
void flecs_rest_parse_json_ser_entity_params(
ecs_world_t *world,
ecs_entity_to_json_desc_t *desc,
const ecs_http_request_t *req)
{
Expand All @@ -173,6 +174,12 @@ void flecs_rest_parse_json_ser_entity_params(
flecs_rest_bool_param(req, "private", &desc->serialize_private);
flecs_rest_bool_param(req, "type_info", &desc->serialize_type_info);
flecs_rest_bool_param(req, "alerts", &desc->serialize_alerts);

char *rel = NULL;
flecs_rest_string_param(req, "refs", &rel);
if (rel) {
desc->serialize_refs = ecs_lookup_fullpath(world, rel);
}
}

static
Expand Down Expand Up @@ -218,7 +225,7 @@ bool flecs_rest_reply_entity(
}

ecs_entity_to_json_desc_t desc = ECS_ENTITY_TO_JSON_INIT;
flecs_rest_parse_json_ser_entity_params(&desc, req);
flecs_rest_parse_json_ser_entity_params(world, &desc, req);
if (ecs_entity_to_json_buf(world, e, &reply->body, &desc) != 0) {
ecs_strbuf_reset(&reply->body);
reply->code = 500;
Expand Down
3 changes: 3 additions & 0 deletions test/meta/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,9 @@
"serialize_entity_w_2_alerts",
"serialize_entity_w_child_alerts",
"serialize_entity_w_severity_filter_alert",
"serialize_entity_refs_childof",
"serialize_entity_refs_custom",
"serialize_entity_refs_wildcard",
"serialize_iterator_1_comps_empty",
"serialize_iterator_1_comps_2_ents_same_table",
"serialize_iterator_1_tag_2_ents_same_table",
Expand Down
111 changes: 111 additions & 0 deletions test/meta/src/SerializeToJson.c
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,117 @@ void SerializeToJson_serialize_entity_w_severity_filter_alert() {
ecs_fini(world);
}

void SerializeToJson_serialize_entity_refs_childof() {
ecs_world_t *world = ecs_init();

ECS_TAG(world, Rel);

ecs_entity_t e1 = ecs_new_entity(world, "e1");

ecs_entity_t child_1 = ecs_new_entity(world, "child1");
ecs_add_pair(world, child_1, EcsChildOf, e1);

ecs_entity_t child_2 = ecs_new_entity(world, "child2");
ecs_add_pair(world, child_2, EcsChildOf, e1);

ecs_entity_t child_3 = ecs_new_entity(world, "child3");
ecs_add_pair(world, child_3, Rel, e1);

ecs_entity_to_json_desc_t desc = ECS_ENTITY_TO_JSON_INIT;
desc.serialize_refs = EcsChildOf;
char *json = ecs_entity_to_json(world, e1, &desc);
test_assert(json != NULL);

test_str(json, "{"
"\"path\":\"e1\", "
"\"ids\":[], "
"\"refs\":{"
"\"ChildOf\":["
"\"e1.child1\", "
"\"e1.child2\""
"]"
"}"
"}");
ecs_os_free(json);

ecs_fini(world);
}

void SerializeToJson_serialize_entity_refs_custom() {
ecs_world_t *world = ecs_init();

ECS_TAG(world, Rel);

ecs_entity_t e1 = ecs_new_entity(world, "e1");

ecs_entity_t child_1 = ecs_new_entity(world, "child1");
ecs_add_pair(world, child_1, Rel, e1);

ecs_entity_t child_2 = ecs_new_entity(world, "child2");
ecs_add_pair(world, child_2, Rel, e1);

ecs_entity_t child_3 = ecs_new_entity(world, "child3");
ecs_add_pair(world, child_3, EcsChildOf, e1);

ecs_entity_to_json_desc_t desc = ECS_ENTITY_TO_JSON_INIT;
desc.serialize_refs = Rel;
char *json = ecs_entity_to_json(world, e1, &desc);
test_assert(json != NULL);

test_str(json, "{"
"\"path\":\"e1\", "
"\"ids\":[], "
"\"refs\":{"
"\"Rel\":["
"\"child1\", "
"\"child2\""
"]"
"}"
"}");
ecs_os_free(json);

ecs_fini(world);
}

void SerializeToJson_serialize_entity_refs_wildcard() {
ecs_world_t *world = ecs_init();

ECS_TAG(world, Rel);

ecs_entity_t e1 = ecs_new_entity(world, "e1");

ecs_entity_t child_1 = ecs_new_entity(world, "child1");
ecs_add_pair(world, child_1, Rel, e1);

ecs_entity_t child_2 = ecs_new_entity(world, "child2");
ecs_add_pair(world, child_2, Rel, e1);

ecs_entity_t child_3 = ecs_new_entity(world, "child3");
ecs_add_pair(world, child_3, EcsChildOf, e1);

ecs_entity_to_json_desc_t desc = ECS_ENTITY_TO_JSON_INIT;
desc.serialize_refs = EcsWildcard;
char *json = ecs_entity_to_json(world, e1, &desc);
test_assert(json != NULL);

test_str(json, "{"
"\"path\":\"e1\", "
"\"ids\":[], "
"\"refs\":{"
"\"ChildOf\":["
"\"e1.child3\""
"], "
"\"Rel\":["
"\"child1\", "
"\"child2\""
"]"
"}"
"}");
ecs_os_free(json);

ecs_fini(world);
}

void SerializeToJson_serialize_iterator_1_comps_empty() {
ecs_world_t *world = ecs_init();

Expand Down
Loading

0 comments on commit bc3ec54

Please sign in to comment.