# Tables

## Table Flat

Access and write tables using dot "." notation, also known as "flat path". Similar to TweakDB Flat logic but for any kind of LUA table.

#### Definitions

```lua
tFlat.get(obj: table, path: string, opt default: any) -> value/default
```

```lua
tFlat.has(obj: table, path: string) -> boolean
```

```lua
tFlat.set(obj: table, path: string, value: any) -> table
```

```lua
tFlat.insert(obj: table, path: string, value: any) -> table
```

```lua
tFlat.delete(obj: table, path: string) -> table
```

#### Usage examples

All code examples below use this predefined table data. Note that `items` is an associative object and `elements` is a sequential table.

```lua
local myTable = {
    ready = true,
    config = {
        items = {
            item1 = true,
            item2 = false
        },
        elements = {
           'element1',
           'element2'
        }
    }
}
```

Get value

```lua
local item2 = tFlat.get(myTable, 'config.items.item2')
-- false

local element2 = tFlat.get(myTable, 'config.elements.2')
-- element2
```

Has value

```lua
local hasItem2 = tFlat.has(myTable, 'config.items.item2')
-- true

local hasElement2 = tFlat.has(myTable, 'config.elements.2')
-- true
```

Set value

```lua
tFlat.set(myTable, 'config.items.item2', true)

tFlat.set(myTable, 'config.elements.2', 'newElement2')
```

```
myTable = {
    ["ready"] = true,
    ["config"] = {
        ["items"] = {
            ["item1"] = true,
            ["item2"] = true,
        },
        ["elements"] = {
            "element1",
            "newElement2",
        },
    },
}
```

Insert sequential table value

```lua
tFlat.insert(myTable, 'config.elements', 'element3')
```

<pre><code><strong>myTable = {
</strong>    ["ready"] = true,
    ["config"] = {
        ["items"] = {
            ["item1"] = true,
            ["item2"] = false,
        },
        ["elements"] = {
            "element1",
            "element2",
            "element3",
        },
    },
}
</code></pre>

Delete value

```lua
tFlat.delete(myTable, 'config.items.item1')

tFlat.delete(myTable, 'config.elements.1')
```

```
myTable = {
    ["ready"] = true,
    ["config"] = {
        ["items"] = {
            ["item2"] = false,
        },
        ["elements"] = {
            "element2",
        },
    },
}
```

#### Source code

```lua
tFlat = {

    get = function(obj, path, default)

        -- get path array
        path = tFlat.split(path)

        -- vars
        local length = #path
        local current = obj
        local key

        -- loop through path
        for index = 1, length, 1 do

            -- current key
            key = path[ index ]

            -- convert key to number (sequential table)
            if tonumber(key) then
                key = tonumber(key)
            end

            -- stop searching if a child object is missing
            if current[ key ] == nil then
                return default
            end

            current = current[ key ]

        end

        return current

    end,

    has = function(obj, path)
        return tFlat.get(obj, path) ~= nil
    end,

    set = function(obj, path, val)

        -- get path array
        path = tFlat.split(path)

        -- vars
        local length = #path
        local current = obj
        local key

        -- loop through path
        for index = 1, length, 1 do

            -- current key
            key = path[ index ]

            -- convert key to number (sequential table)
            if tonumber(key) then
                key = tonumber(key)
            end

            -- set value on last key
            if index == length  then
                current[ key ] = val

            -- current key exists
            elseif current[ key ] then

                if type(current[ key ]) ~= 'table' then
                    current[ key ] = {}
                end

                current = current[ key ]

            -- current key doesn't exist
            else
                current[ key ] = {}
                current = current[ key ]

            end

        end

        -- return
        return obj

    end,

    insert = function(obj, path, val)

        -- get target
        local target = tFlat.get(obj, path)

        -- check if table and sequential
        if type(target) == 'table' and tFlat.isSequential(target) then
            table.insert(target, val)
        end

        -- return
        return obj

    end,

    delete = function(obj, path)

        -- get path array
        path = tFlat.split(path)
        
        -- vars
        local length = #path
        local current = obj
        local key

        -- loop through path
        for index = 1, length, 1 do

            -- current key
            key = path[ index ]

            -- convert key to number (sequential table)
            if tonumber(key) then
                key = tonumber(key)
            end

            -- set value on last key
            if index == length then
                current[ key ] = nil
            else
                current = current[ key ] or {}
            end

        end

        -- return
        return obj

    end,

    split = function(s)

        s = tostring(s)
        local fields = {}
        local pattern = string.format("([^%s]+)", '.')

        string.gsub(s, pattern, function(c)
            fields[ #fields + 1 ] = c
        end)

        return fields

    end,

    isSequential = function(array)
        for k, _ in pairs(array) do
            if type(k) ~= "number" then
                return false
            end
        end
        return true
    end,

}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.redmodding.org/cyber-engine-tweaks/snippets-examples/utilities/tables.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
