Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.

Latest commit

 

History

History
272 lines (214 loc) · 6.9 KB

File metadata and controls

272 lines (214 loc) · 6.9 KB

Example Configuration

server.cfg

Add these lines to your server.cfg:

# IMPORTANT: Load ink_postgresql BEFORE resources that use it
ensure ink_postgresql

# Set PostgreSQL connection string
set postgresql_connection_string "postgresql://username:password@localhost:5432/database_name"

# Optional: Configure connection pool size
# set postgresql_connection_string "postgresql://username:password@localhost:5432/database_name?max=20&idle_timeout=30"

# Optional: Enable SSL connection
# set postgresql_connection_string "postgresql://username:password@localhost:5432/database_name?ssl=true"

# Then load your resources that depend on ink_postgresql
ensure your_gamemode
ensure your_resource

Load Order is Critical: ink_postgresql must start before any resource that uses it.

Example Usage Script

Create a test resource to verify InkPG is working:

fxmanifest.lua:

fx_version 'cerulean'
game 'gta5'

server_scripts {
    'server.lua'
}

dependency 'ink_postgresql'

server.lua:

-- Use wrapper pattern for better performance
local InkPG = exports.ink_postgresql

-- IMPORTANT: Always wait for database to be ready
InkPG:ready(function()
    print('[Test] Database connected!')
    
    -- Create a test table
    InkPG:execute([[
        CREATE TABLE IF NOT EXISTS test_users (
            id SERIAL PRIMARY KEY,
            name VARCHAR(255) NOT NULL,
            age INT,
            created_at TIMESTAMP DEFAULT NOW()
        )
    ]], {})
    
    print('[Test] Test table created')
end)

-- Test command: /testdb
RegisterCommand('testdb', function(source, args)
    -- Insert a user
    local result = InkPG:insert(
        'INSERT INTO test_users (name, age) VALUES ($1, $2)',
        {'John Doe', 25}
    )
    
    print('Inserted user with ID:', result.insertId)
    
    -- Query all users
    local users = InkPG:query('SELECT * FROM test_users ORDER BY id DESC LIMIT 10', {})
    
    print('Recent users:')
    for _, user in ipairs(users) do
        print(string.format('  ID: %d, Name: %s, Age: %d', user.id, user.name, user.age or 0))
    end
    
    -- Get single user
    local user = InkPG:single('SELECT * FROM test_users WHERE id = $1', {result.insertId})
    if user then
        print('Found user:', user.name)
    end
    
    -- Update user
    local updated = InkPG:update(
        'UPDATE test_users SET age = $1 WHERE id = $2',
        {30, result.insertId}
    )
    print('Updated rows:', updated.affectedRows)
    
    -- Using named parameters
    local results = InkPG:query(
        'SELECT * FROM test_users WHERE name = :name AND age > :minAge',
        {name = 'John Doe', minAge = 20}
    )
    print('Named param results:', #results)
    
end, false)

-- Test command: /testcallback
RegisterCommand('testcallback', function(source, args)
    -- Using callbacks instead of promises
    InkPG:query('SELECT COUNT(*) as total FROM test_users', {}, function(result)
        if result and result[1] then
            print('Total users (callback):', result[1].total)
        end
    end)
end, false)

-- Test command: /testjson
RegisterCommand('testjson', function(source, args)
    -- Create table with JSONB column
    InkPG:execute([[
        CREATE TABLE IF NOT EXISTS test_players (
            id SERIAL PRIMARY KEY,
            identifier VARCHAR(255) NOT NULL,
            data JSONB,
            created_at TIMESTAMP DEFAULT NOW()
        )
    ]], {})
    
    -- Insert with JSON data
    local playerData = json.encode({
        inventory = {
            {item = 'bread', count = 5},
            {item = 'water', count = 3}
        },
        position = {x = 100.5, y = 200.3, z = 30.1},
        job = 'police',
        money = 5000
    })
    
    local result = InkPG:insert(
        'INSERT INTO test_players (identifier, data) VALUES ($1, $2)',
        {'license:abc123', playerData}
    )
    
    print('Inserted player ID:', result.insertId)
    
    -- Query using JSONB operators
    local cops = InkPG:query(
        "SELECT * FROM test_players WHERE data->>'job' = $1",
        {'police'}
    )
    
    print('Found', #cops, 'police officers')
    
    -- Check if key exists in JSONB
    local playersWithInventory = InkPG:query(
        "SELECT * FROM test_players WHERE data ? 'inventory'",
        {}
    )
    
    print('Players with inventory:', #playersWithInventory)
    
end, false)

Example: ESX Integration

-- In your ESX resource
local InkPG = exports.ink_postgresql

-- Get player by identifier
function GetPlayerFromIdentifier(identifier)
    local player = InkPG:single(
        'SELECT * FROM users WHERE identifier = $1',
        {identifier}
    )
    return player
end

-- Save player data
function SavePlayer(identifier, data)
    local result = InkPG:update(
        'UPDATE users SET accounts = $1, job = $2, position = $3 WHERE identifier = $4',
        {json.encode(data.accounts), data.job, json.encode(data.position), identifier}
    )
    return result.affectedRows > 0
end

-- Get all online players
function GetOnlinePlayers()
    return InkPG:query('SELECT * FROM users WHERE online = $1', {true})
end

Example: QB-Core Integration

-- In your QB-Core resource
local InkPG = exports.ink_postgresql

-- Load player data
QBCore.Player.LoadPlayer = function(source, citizenid)
    local player = InkPG:single(
        'SELECT * FROM players WHERE citizenid = $1',
        {citizenid}
    )
    
    if not player then return nil end
    
    -- Parse JSON data
    player.money = json.decode(player.money)
    player.job = json.decode(player.job)
    player.metadata = json.decode(player.metadata)
    
    return player
end

-- Save player data
QBCore.Player.SavePlayer = function(source)
    local Player = QBCore.Functions.GetPlayer(source)
    
    InkPG:update([[
        UPDATE players 
        SET money = $1, job = $2, position = $3, metadata = $4 
        WHERE citizenid = $5
    ]], {
        json.encode(Player.PlayerData.money),
        json.encode(Player.PlayerData.job),
        json.encode(Player.PlayerData.position),
        json.encode(Player.PlayerData.metadata),
        Player.PlayerData.citizenid
    })
end

Docker PostgreSQL Setup

Quick PostgreSQL setup using Docker:

docker run --name fivem-postgres \
  -e POSTGRES_USER=fivem \
  -e POSTGRES_PASSWORD=changeme \
  -e POSTGRES_DB=gameserver \
  -p 5432:5432 \
  -v postgres-data:/var/lib/postgresql/data \
  -d postgres:15-alpine

Then configure in server.cfg:

set postgresql_connection_string "postgresql://fivem:changeme@localhost:5432/gameserver"

Performance Test

Test query performance:

RegisterCommand('perftest', function()
    local startTime = os.clock()
    
    -- Run 1000 queries
    for i = 1, 1000 do
        InkPG:single('SELECT $1 as num', {i})
    end
    
    local endTime = os.clock()
    local duration = (endTime - startTime) * 1000
    
    print(string.format('1000 queries completed in %.2fms (%.2fms avg)', duration, duration / 1000))
end, false)