Module accessor.lua

Module to access arbitrary depth table keys.

Example:

local t = {
  some = {
    arbitrary = {
      key = "hello world",
    }
  }
}
local key = "some.arbitrary.key"
local accessor = Accessor(t)
local value = accessor:get("some.arbitrary.key")
assert(value == "hello world")

For each key a function will be generated. The function will be cached so the 2nd lookup will be faster.

Warning: make sure to protect yourself from unlimited cache growth! Check lua_cache.

Design use case: looking up user provided keys in json http bodies. The keys are the same for each request, the bodies different.

Info:

  • Copyright: (c) 2020-2020 Thijs Schreijer
  • License: see LICENSE file

Functions

Accessor.lua_cache () Returns a new table based cache.
Accessor.new (options) Constructor, creates a new accessor object.
Accessor:create_index (source_table) Adds an __index meta-method for automatic lookups.
Accessor:create_proxy (source_table) Creates a proxy table for automatic lookups.
Accessor:get (element, source_table) Gets a value from the table.
Accessor:get_source () Returns the source table.
Accessor:validate_key (element) Validate a user provided key.


Functions

Accessor.lua_cache ()

Returns a new table based cache. Minimal cache implementation interface compatible with resty-lru caches. This cache is table based and will allow unlimited growth. If used with OpenResty then use the compatible OpenResty LRU cache when calling new.

A cache should implement the following methods:

 ok = cache:set(key, value)
 value = cache(key)

Returns:

    a new cache object
Accessor.new (options)

Constructor, creates a new accessor object. The options table supports the following fields:

  • source (optional, defaults to an empty table) a table in which the keys will be looked up by default by the newly created accessor object
  • cache (optional, defaults to a new lua_cache instance) a cache object to store the generated lookup functions, see lua_cache for the required interface

Parameters:

  • options (optional) options table

Returns:

    accessor object
Accessor:create_index (source_table)
Adds an __index meta-method for automatic lookups. Returns the source table. The table will have its metatable replaced by a new one with only an __index method. So if a lookup fails, it will retry with an 'accessor' lookup.

This modifies the original table, but is more performant than a proxy table (see create_proxy as an alternative).

NOTE: where a regular get call would return a nil+error, this table will only return nil. This is because the __index metamethod only has a single return value, and hence will drop the error string.

Parameters:

  • source_table (optional table, defaults to the accessor default table)

Returns:

    the source table, with a new meta-table (existing one will be replaced)

Usage:

    local t = { hello = { world = "tieske" } }
    local p = Accessor({ source = t }):create_proxy()
    assert(t == p)  -- they are the same tables
    
    print("regular: ", p.hello.world)       --> "regular: tieske"
    print("accessor: ", p["hello.world"]    --> "accessor: tieske"
Accessor:create_proxy (source_table)
Creates a proxy table for automatic lookups. A proxy table is a new (empty) table with an __index meta-method that will first do a regular lookup in the source table, and if that fails, it will retry with an 'accessor' lookup.

Because this creates a new proxy table, it will not alter the original metatable or methods (see also create_index as an alternative).

NOTE: where a regular get call would return a nil+error, this proxy will only return nil. This is because the __index metamethod only has a single return value, and hence will drop the error string.

Parameters:

  • source_table (optional table, defaults to the accessor default table)

Returns:

    a new proxy table

Usage:

    local t = { hello = { world = "tieske" } }
    local p = Accessor({ source = t }):create_proxy()
    assert(t ~= p)  -- they are different tables
    
    print("regular: ", p.hello.world)       --> "regular: tieske"
    print("accessor: ", p["hello.world"]    --> "accessor: tieske"
Accessor:get (element, source_table)
Gets a value from the table.

Parameters:

  • element (string) the key to lookup (if not a string, then the return value will be nil)
  • source_table (optional table, defaults to the accessor default table)

Returns:

    the value or nil+error

Usage:

    local t = { hello = { world = "tieske" } }
    local accessor = Accessor({ source = t })
    print(accessor:get("hello.world"))          --> "tieske"
    print(t.does_not_exist.world)               --> error!
    print(accessor:get("does_not_exist.world")) --> "nil, a lookup error"
    
    local t2 = { hello = { world = "someone" } }
    print(accessor:get("hello.world", t2))      --> "someone"
    
    -- NOTE: when doing the lookup in t2, the same 'accessor' is used, which means
    -- it uses the same functions cache, so the 2nd lookup uses the function generated
    -- by the first lookup, despite it being used on a different table.
    -- So there is no need to create accessor objects for each table.
Accessor:get_source ()
Returns the source table. This is the table provided as options.source to new.

Returns:

    source table
Accessor:validate_key (element)
Validate a user provided key. Checks whether the key generates a proper function.

Parameters:

  • element (string) the key to validate

Returns:

    true or nil+error

Usage:

    assert(accessor:("this[2].is.valid['as a key'].right"))  -- ok
    assert(accessor:("this is not"))                         -- fails
generated by LDoc 1.4.6 Last updated 2020-07-14 09:29:11