| 2869 | /* ── Binding virtual variables (for WITH clause) ──────────────── */ |
| 2870 | |
| 2871 | static const char *binding_get_virtual(binding_t *b, const char *var, const char *prop) { |
| 2872 | if (!var) { |
| 2873 | return ""; |
| 2874 | } |
| 2875 | /* Check virtual vars first (from WITH projection) */ |
| 2876 | char full[CBM_SZ_256]; |
| 2877 | if (prop) { |
| 2878 | snprintf(full, sizeof(full), "%s.%s", var, prop); |
| 2879 | } else { |
| 2880 | snprintf(full, sizeof(full), "%s", var); |
| 2881 | } |
| 2882 | for (int i = 0; i < b->var_count; i++) { |
| 2883 | if (strcmp(b->var_names[i], full) == 0) { |
| 2884 | return b->var_nodes[i].name ? b->var_nodes[i].name : ""; |
| 2885 | } |
| 2886 | } |
| 2887 | /* Fall through to normal lookup */ |
| 2888 | cbm_edge_t *e = binding_get_edge(b, var); |
| 2889 | if (e) { |
| 2890 | /* Bare `RETURN r` on an edge: surface the full properties JSON |
| 2891 | * (or "{}" if none) so callers can inspect timestamps, weights, |
| 2892 | * etc. without naming each property. */ |
| 2893 | return prop ? edge_prop(e, prop) : (e->properties_json ? e->properties_json : "{}"); |
| 2894 | } |
| 2895 | cbm_node_t *n = binding_get(b, var); |
| 2896 | if (n) { |
| 2897 | if (prop) { |
| 2898 | return node_prop(n, prop, b->store); |
| 2899 | } |
| 2900 | return n->name ? n->name : ""; |
| 2901 | } |
| 2902 | return ""; |
| 2903 | } |
| 2904 | |
| 2905 | /* ── String function application ──────────────────────────────── */ |
| 2906 |
no test coverage detected