Files
metabuilder/packages/github_tools/seed/scripts/db/operations.lua
2025-12-30 22:00:26 +00:00

318 lines
9.1 KiB
Lua

-- github_tools/seed/scripts/db/operations.lua
-- DBAL operations for GitHub integration settings
-- @module github_tools.db.operations
local M = {}
local json = require('json')
---------------------------------------------------------------------------
-- GITHUB CONNECTION OPERATIONS
---------------------------------------------------------------------------
---@class GitHubConnectionParams
---@field tenantId string
---@field userId string
---@field accessToken string Encrypted token
---@field username string
---@field avatarUrl string|nil
---@field scopes table|nil
---Save GitHub connection
---@param dbal table DBAL client instance
---@param params GitHubConnectionParams
---@return table Created/updated connection
function M.saveConnection(dbal, params)
-- Check for existing connection
local existing = dbal:findFirst('GitHubConnection', {
where = { tenantId = params.tenantId, userId = params.userId },
})
if existing then
return dbal:update('GitHubConnection', existing.id, {
accessToken = params.accessToken,
username = params.username,
avatarUrl = params.avatarUrl,
scopes = params.scopes and json.encode(params.scopes) or nil,
updatedAt = os.time() * 1000,
})
end
return dbal:create('GitHubConnection', {
tenantId = params.tenantId,
userId = params.userId,
accessToken = params.accessToken,
username = params.username,
avatarUrl = params.avatarUrl,
scopes = params.scopes and json.encode(params.scopes) or nil,
createdAt = os.time() * 1000,
updatedAt = os.time() * 1000,
})
end
---Get user's GitHub connection
---@param dbal table
---@param tenantId string
---@param userId string
---@return table|nil Connection
function M.getConnection(dbal, tenantId, userId)
return dbal:findFirst('GitHubConnection', {
where = { tenantId = tenantId, userId = userId },
})
end
---Delete GitHub connection
---@param dbal table
---@param tenantId string
---@param userId string
---@return boolean Success
function M.deleteConnection(dbal, tenantId, userId)
local connection = M.getConnection(dbal, tenantId, userId)
if connection then
return dbal:delete('GitHubConnection', connection.id)
end
return false
end
---Check if user has GitHub connected
---@param dbal table
---@param tenantId string
---@param userId string
---@return boolean
function M.isConnected(dbal, tenantId, userId)
return M.getConnection(dbal, tenantId, userId) ~= nil
end
---------------------------------------------------------------------------
-- REPOSITORY OPERATIONS
---------------------------------------------------------------------------
---@class GitHubRepoParams
---@field tenantId string
---@field connectionId string
---@field owner string
---@field name string
---@field fullName string
---@field description string|nil
---@field isPrivate boolean
---@field defaultBranch string
---Sync a repository
---@param dbal table
---@param params GitHubRepoParams
---@return table Created/updated repo
function M.syncRepository(dbal, params)
local existing = dbal:findFirst('GitHubRepository', {
where = { tenantId = params.tenantId, fullName = params.fullName },
})
if existing then
return dbal:update('GitHubRepository', existing.id, {
description = params.description,
isPrivate = params.isPrivate,
defaultBranch = params.defaultBranch,
syncedAt = os.time() * 1000,
})
end
return dbal:create('GitHubRepository', {
tenantId = params.tenantId,
connectionId = params.connectionId,
owner = params.owner,
name = params.name,
fullName = params.fullName,
description = params.description,
isPrivate = params.isPrivate,
defaultBranch = params.defaultBranch,
createdAt = os.time() * 1000,
syncedAt = os.time() * 1000,
})
end
---List synced repositories
---@param dbal table
---@param connectionId string
---@return table[] Repositories
function M.listRepositories(dbal, connectionId)
local result = dbal:list('GitHubRepository', {
where = { connectionId = connectionId },
orderBy = { name = 'asc' },
take = 200,
})
return result.items or {}
end
---Get repository by full name
---@param dbal table
---@param tenantId string
---@param fullName string e.g., "owner/repo"
---@return table|nil Repository
function M.getRepository(dbal, tenantId, fullName)
return dbal:findFirst('GitHubRepository', {
where = { tenantId = tenantId, fullName = fullName },
})
end
---Delete repository record
---@param dbal table
---@param repoId string
---@return boolean
function M.deleteRepository(dbal, repoId)
return dbal:delete('GitHubRepository', repoId)
end
---------------------------------------------------------------------------
-- WEBHOOK OPERATIONS
---------------------------------------------------------------------------
---@class WebhookCreateParams
---@field tenantId string
---@field repositoryId string
---@field webhookId string GitHub's webhook ID
---@field events table[] Events to listen for
---@field secret string Webhook secret
---Register a webhook
---@param dbal table
---@param params WebhookCreateParams
---@return table Created webhook
function M.registerWebhook(dbal, params)
return dbal:create('GitHubWebhook', {
tenantId = params.tenantId,
repositoryId = params.repositoryId,
webhookId = params.webhookId,
events = json.encode(params.events or {}),
secret = params.secret,
isActive = true,
createdAt = os.time() * 1000,
})
end
---Get webhook for repository
---@param dbal table
---@param repositoryId string
---@return table|nil Webhook
function M.getWebhook(dbal, repositoryId)
return dbal:findFirst('GitHubWebhook', {
where = { repositoryId = repositoryId, isActive = true },
})
end
---Deactivate webhook
---@param dbal table
---@param webhookId string
function M.deactivateWebhook(dbal, webhookId)
return dbal:update('GitHubWebhook', webhookId, {
isActive = false,
updatedAt = os.time() * 1000,
})
end
---------------------------------------------------------------------------
-- WEBHOOK EVENT LOG
---------------------------------------------------------------------------
---Log a webhook event
---@param dbal table
---@param tenantId string
---@param repositoryId string
---@param event string push|pull_request|issue|etc
---@param payload table Event payload
---@param processed boolean
function M.logWebhookEvent(dbal, tenantId, repositoryId, event, payload, processed)
return dbal:create('GitHubWebhookEvent', {
tenantId = tenantId,
repositoryId = repositoryId,
event = event,
payload = json.encode(payload),
processed = processed,
receivedAt = os.time() * 1000,
})
end
---List recent webhook events
---@param dbal table
---@param repositoryId string
---@param take number|nil
---@return table[] Events
function M.listWebhookEvents(dbal, repositoryId, take)
local result = dbal:list('GitHubWebhookEvent', {
where = { repositoryId = repositoryId },
orderBy = { receivedAt = 'desc' },
take = take or 50,
})
return result.items or {}
end
---Mark event as processed
---@param dbal table
---@param eventId string
function M.markEventProcessed(dbal, eventId)
return dbal:update('GitHubWebhookEvent', eventId, {
processed = true,
processedAt = os.time() * 1000,
})
end
---------------------------------------------------------------------------
-- PULL REQUEST TRACKING
---------------------------------------------------------------------------
---Track a pull request
---@param dbal table
---@param tenantId string
---@param repositoryId string
---@param prNumber number
---@param title string
---@param author string
---@param status string open|closed|merged
---@param url string
function M.trackPullRequest(dbal, tenantId, repositoryId, prNumber, title, author, status, url)
local existing = dbal:findFirst('GitHubPullRequest', {
where = { repositoryId = repositoryId, prNumber = prNumber },
})
if existing then
return dbal:update('GitHubPullRequest', existing.id, {
title = title,
status = status,
updatedAt = os.time() * 1000,
})
end
return dbal:create('GitHubPullRequest', {
tenantId = tenantId,
repositoryId = repositoryId,
prNumber = prNumber,
title = title,
author = author,
status = status,
url = url,
createdAt = os.time() * 1000,
updatedAt = os.time() * 1000,
})
end
---List pull requests for repository
---@param dbal table
---@param repositoryId string
---@param status string|nil Filter by status
---@param take number|nil
---@return table[] Pull requests
function M.listPullRequests(dbal, repositoryId, status, take)
local where = { repositoryId = repositoryId }
if status then
where.status = status
end
local result = dbal:list('GitHubPullRequest', {
where = where,
orderBy = { updatedAt = 'desc' },
take = take or 20,
})
return result.items or {}
end
return M