Query API

The query API allows for finding an ink data object in a list. If you find yourself creating data structures that are a simple mapping from an identifier to an ink data handle, using the query API may be a simpler option.

Example#

This is a function from a hypothetical chat room user interface that has a list of participants and shows feedback if they are currently typing. Rather than maintaining a data structure mapping from username to an associated inkd, it uses ink_query to find the inkd that needs updated.

#include <ink_query.h>

void update_typing_state(const char* username, bool is_typing) {
    inkd chatroom = ink_source(0, I_chatroom);

    // Initialize a query object on the stack
    ink_query q;
    ink_query_init(&q);

    // We want to find an inkd with a given username
    ink_query_charp(&q, I_username, username);

    // Execute the query
    inkd user = ink_query_get(&q, chatroom, I_participants);

    // Release any resources held by the query object
    ink_query_deinit(&q);

    // Update the typing state
    inkd_bool(user, I_is_typing, is_typing);
}
#include <ink.hpp>

void update_typing_state(Ink& ink_ctx, std::string username, bool is_typing) {
    uiink::Data chatroom = ink_ctx.source(I_chatroom);

    // Initialize a query object on the stack
    uiink::Query q;

    // We want to find an inkd with a given username
    q.match_string(username);

    // Execute the query
    uiink::Data user = q.get(chatroom, I_participants);

    // Update the typing state
    user.set_bool(I_is_typing, is_typing);
}

def update_typing_state(username, is_typing):
    chatroom = ink.source(I.chatroom)
    q = Query(username=username)
    user = q.get(chatroom, I.participants)
    user.set(I.is_typing, is_typing)
void updateTypingState(Ink ink, String username, boolean isTyping) {
    Data chatroom = ink.source(I.chatroom);
    Query q = new Query();
    q.matchString(I.username, username);
    Data user = q.get(chatroom, I.participants)
    user.setBoolean(I.is_typing, isTyping);
}
void UpdateTypingState(Ink ink, string username, bool isTyping) {
    Data chatroom = ink.Source(I.chatroom);
    Query q = new Query();
    q.MatchString(I.username, username);
    Data user = q.Get(chatroom, I.participants)
    user.SetBool(I.is_typing, isTyping);
}

Matching Fields#

You can match against the fields of an inkd with the following functions:

void ink_query_int(ink_query* q, ink_ident field, int value);
void ink_query_bool(ink_query* q, ink_ident field, char value);
void ink_query_string(ink_query* q, ink_ident field, ink_str value);
void ink_query_ident(ink_query* q, ink_ident field, ink_ident value);
void ink_query_color(ink_query* q, ink_ident field, uint32_t value);
void ink_query_charp(ink_query* q, ink_ident field, const char* value);
void Query::match_int(ink_ident field, int value);
void Query::match_bool(ink_ident field, bool value);
void Query::match_string(ink_ident field, const String& value);
void Query::match_string(ink_ident field, ink_str value);
void Query::match_string(ink_ident field, const char* value);
void Query::match_string(ink_ident field, const std::string& value);
void Query::match_ident(ink_ident field, ink_ident value);
void Query::match_color(ink_ident field, uint32_t value);
void Query.matchInt(Ident field, int v);
void Query.matchBoolean(Ident field, boolean v);
void Query.matchString(Ident field, String v);
void Query.matchIdent(Ident field, Ident v);
void Query.matchColor(Ident field, int v);
void Query.MatchInt(Ident field, int v);
void Query.MatchBool(Ident field, bool v);
void Query.MatchString(Ident field, string v);
void Query.MatchIdent(Ident field, ulong v);
void Query.MatchColor(Ident field, uint v);

Note

The field types that can be queried is a subset of the types that can be set on a data object. You cannot match against an ink_image or a float.

If multiple fields are set on a query, an inkd will only match if all of the fields match.

A note on ink_query_charp: The ink_query may (or may not) continue to use the memory pointed to by the value argument. Therefore, any string pointed to by ink_query_charp must not be modified or deallocated until after ink_query_deinit is called. (This also applies to the C++ overload of Query::match_string that takes a const char*.)

Executing the query#

After setting fields on your query, you may use Get, Maybe Get, or Remove.

inkd ink_query_get(ink_query* q, inkd parent, ink_ident list_field);
inkd ink_query_maybe_get(ink_query* q, inkd parent, ink_ident list_field);
void ink_query_remove(ink_query* q, inkd parent, ink_ident list_field);
Data Query::get(Data parent, ink_ident list_field);
Data Query::maybe_get(Data parent, ink_ident list_field);
void Query::remove(Data parent, ink_ident list_field);
Data Query.get(Data parent, Ident listField);
Data Query.maybeGet(Data parent, Ident listField);
void Query.remove(Data parent, Ident listField);
Data Query.Get(Data parent, Ident listField);
Data Query.MaybeGet(Data parent, Ident listField);
void Query.Remove(Data parent, Ident listField);

Get#

Return the first matching data entry in the given list.

If there is no match, a new one entry will be appended to the list. It will be initialized with fields set so that it matches the query.

Maybe Get#

Maybe Get is identical to get except that it will not append a new data entry.

Remove#

Remove all matching data objects from a list.

This is essentially the same as calling inkd_remove on the result of ink_query_maybe_get for as long as the result is not null. (Or the equivalent calls in your language of choice.)

Initialize / Deinitialize#

To reduce heap allocations ink_query is stored on the stack. Call ink_query_init to initialize the memory.

The ink_query may make allocations or increment reference counts internally. Therefore, ink_query_deinit must be called after the ink_query is no longer needed.

ink_query q;
ink_query_init(&q);
// Do stuff
ink_query_deinit(&q);

(For C++ and other language bindings, this is handled automatically.)