diff --git a/src/plmustache.c b/src/plmustache.c index cafcb1f..2550da7 100644 --- a/src/plmustache.c +++ b/src/plmustache.c @@ -17,8 +17,9 @@ PG_MODULE_MAGIC; typedef struct { - char *prm_name; - char *prm_value; + char *prm_name; + char *prm_value; + bool enters_section; } plmustache_param; typedef struct { @@ -34,12 +35,22 @@ typedef struct { char** argnames; } plmustache_call_info; -// TODO these are used to handle sections, they're mandatory otherwise mustach segfaults static int -plmustache_enter(void *closure, const char *value){ - return MUSTACH_OK; +plmustache_enter_section(void *userdata, const char *name){ + plmustache_ctx *ctx = (plmustache_ctx *)userdata; + + for(size_t i = 0; i < ctx->num_params; i++){ + plmustache_param* prm = &ctx->params[i]; + + if(strcmp(prm->prm_name, name) == 0){ + return prm->enters_section; + } + } + + return 0; } +// TODO these are used to handle sections, they're mandatory otherwise mustach segfaults static int plmustache_next(void *closure){ return MUSTACH_OK; } @@ -49,9 +60,8 @@ plmustache_leave(void *closure){ return MUSTACH_OK; } -// handles mustache variables static int -plmustache_get(void *userdata, const char *name, struct mustach_sbuf *sbuf){ +plmustache_get_variable(void *userdata, const char *name, struct mustach_sbuf *sbuf){ plmustache_ctx *ctx = (plmustache_ctx *)userdata; for(size_t i = 0; i < ctx->num_params; i++){ @@ -133,10 +143,10 @@ Datum plmustache_handler(PG_FUNCTION_ARGS) int mustach_code; size_t mustache_result_size; struct mustach_itf itf = { - .enter = plmustache_enter, + .enter = plmustache_enter_section, .next = plmustache_next, .leave = plmustache_leave, - .get = plmustache_get, + .get = plmustache_get_variable, }; plmustache_call_info call_info = validate_build_call_info(function_oid, fcinfo); @@ -149,7 +159,17 @@ Datum plmustache_handler(PG_FUNCTION_ARGS) for(size_t i = 0; i < call_info.numargs; i++){ params[i].prm_name = call_info.argnames[i]; - params[i].prm_value = datum_to_cstring(fcinfo->args[i].value, call_info.argtypes[i]); + NullableDatum arg = fcinfo->args[i]; + if(arg.isnull){ + params[i].prm_value = NULL; + params[i].enters_section = false; + }else{ + params[i].prm_value = datum_to_cstring(arg.value, call_info.argtypes[i]); + if(call_info.argtypes[i] == BOOLOID) + params[i].enters_section = DatumGetBool(arg.value); + else + params[i].enters_section = true; + } } mustach_code = mustach_mem(template, 0, &itf, &ctx, 0, &mustache_result, &mustache_result_size); diff --git a/test/expected/sections.out b/test/expected/sections.out new file mode 100644 index 0000000..be5512b --- /dev/null +++ b/test/expected/sections.out @@ -0,0 +1,81 @@ +create extension if not exists plmustache; +NOTICE: extension "plmustache" already exists, skipping +\echo + +create or replace function bool_section(x1 text, x2 bool) returns text as $$ +Section: {{#x2}}Show {{x1}}{{/x2}} +$$ language plmustache; +\echo + +select bool_section('Something', true); + bool_section +------------------------- + Section: Show Something +(1 row) + +select bool_section('Something', false); + bool_section +-------------- + Section: +(1 row) + +create or replace function bool_section_inverted(x1 text, x2 bool) returns text as $$ +Section: Show {{#x2}}{{x1}}{{/x2}}{{^x2}}Nothing{{/x2}} +$$ language plmustache; +\echo + +select bool_section_inverted('Something', true); + bool_section_inverted +------------------------- + Section: Show Something +(1 row) + +select bool_section_inverted('Something', false); + bool_section_inverted +----------------------- + Section: Show Nothing +(1 row) + +create or replace function foo_test(foo text) returns text as $$ +{{#foo}}foo is {{foo}}{{/foo}} +$$ language plmustache; +\echo + +select foo_test('bar'); + foo_test +------------ + foo is bar +(1 row) + +create or replace function foo_test(foo bool) returns text as $$ +foo is {{#foo}}{{foo}}{{/foo}}{{^foo}}{{foo}}{{/foo}} +$$ language plmustache; +\echo + +select foo_test(true); + foo_test +---------- + foo is t +(1 row) + +select foo_test(false); + foo_test +---------- + foo is f +(1 row) + +create or replace function foo_null_test(foo bool) returns text as $$ +foo is {{#foo}}full{{/foo}}{{^foo}}null{{/foo}} +$$ language plmustache; +select foo_null_test(null); + foo_null_test +--------------- + foo is null +(1 row) + +select foo_null_test(true); + foo_null_test +--------------- + foo is full +(1 row) + diff --git a/test/sql/sections.sql b/test/sql/sections.sql new file mode 100644 index 0000000..6aa892e --- /dev/null +++ b/test/sql/sections.sql @@ -0,0 +1,44 @@ +create extension if not exists plmustache; +\echo + +create or replace function bool_section(x1 text, x2 bool) returns text as $$ +Section: {{#x2}}Show {{x1}}{{/x2}} +$$ language plmustache; +\echo + +select bool_section('Something', true); + +select bool_section('Something', false); + +create or replace function bool_section_inverted(x1 text, x2 bool) returns text as $$ +Section: Show {{#x2}}{{x1}}{{/x2}}{{^x2}}Nothing{{/x2}} +$$ language plmustache; +\echo + +select bool_section_inverted('Something', true); + +select bool_section_inverted('Something', false); + +create or replace function foo_test(foo text) returns text as $$ +{{#foo}}foo is {{foo}}{{/foo}} +$$ language plmustache; +\echo + +select foo_test('bar'); + +create or replace function foo_test(foo bool) returns text as $$ +foo is {{#foo}}{{foo}}{{/foo}}{{^foo}}{{foo}}{{/foo}} +$$ language plmustache; +\echo + +select foo_test(true); + +select foo_test(false); + +create or replace function foo_null_test(foo bool) returns text as $$ +foo is {{#foo}}full{{/foo}}{{^foo}}null{{/foo}} +$$ language plmustache; + +select foo_null_test(null); + +select foo_null_test(true);