Query API

The ink_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 inkd, using the query API may be a simpler option.

Overview#

The general steps for using an ink_query with the C API is as follows:

  1. Initialize on the stack with ink_query_init.

  2. Set one or more fields on the query.

  3. Get a matching inkd with ink_query_get.

  4. Release any internal resources with ink_query_deinit.

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);

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);

(Note that this is a subset of the field types that can be set on an inkd. 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.

Executing the query#

After setting fields on the ink_query, perform an action with one of ink_query_get, ink_query_maybe_get, or ink_query_remove.

ink_query_get#

    inkd ink_query_get(ink_query* q, inkd parent, ink_ident list_field);

ink_query_get will return the first matching inkd in the given list.

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

ink_query_maybe_get#

    inkd ink_query_maybe_get(ink_query* q, inkd parent, ink_ident list_field);

ink_query_maybe_get is identical to ink_query_get except that it will not append a new inkd. If no match is found, a null inkd will be returned.

ink_query_remove#

    void ink_query_remove(ink_query* q, inkd parent, ink_ident list_field);

ink_query_remove will 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.

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_global_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);
}
void update_typing_state(const char* username, bool is_typing) {
    ink::Data chatroom = ink_global_source(0, I_chatroom);

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

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

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

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

def update_typing_state(username, is_typing):
    chatroom = ink.global_source(I.chatroom)
    q = Query(username=username)
    user = q.get(chatroom, I.participants)
    user.set(I.is_typing, is_typing)
void updateTypingState(String username, boolean isTyping) {
    Ink.D chatroom = Ink.globalSource(I.chatroom);
    Ink.Query q = new Ink.Query();
    q.match(I.username, username);
    Ink.D user = q.get(chatroom, I.participants)
    user.set(I.is_typing, isTyping);
}