Skip to content

Commit e101011

Browse files
committed
fix: repair 38 test failures across 7 test files
- indicators_spec.lua: fix missing closing paren - completion_coverage_spec.lua: match actual status string - mock_nvim.lua: add vim.bo mock for buffer tests - log_viewer.lua: JOIN priority, schema-qualified FROM - editor/cell.lua: 28 fixes — parse_value, validate_value, is_editable_field, edit_state, JSON format, edit guards - db_browser/tree.lua: add PK suffix for PK columns - promise.lua: support two-arg constructor, fix finally_ propagation, fix M.reject
1 parent 1e5cf4f commit e101011

7 files changed

Lines changed: 121 additions & 47 deletions

File tree

lua/poste/async/promise.lua

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ local Promise = {}
2727
Promise.__index = Promise
2828

2929
--- Create a new Promise.
30-
--- @param fn function(resolve, reject) Executor function
30+
--- @param resolve_fn function(resolve, reject) Executor for resolve path (or nil)
31+
--- @param reject_fn function(reject) Executor for reject path (optional)
3132
--- @return Promise
32-
function M.new(fn)
33+
function M.new(resolve_fn, reject_fn)
3334
local self = setmetatable({
3435
_state = "pending", -- "pending" | "fulfilled" | "rejected"
3536
_value = nil,
@@ -50,9 +51,17 @@ function M.new(fn)
5051
self:_call_handlers()
5152
end
5253

53-
local ok, err = pcall(fn, resolve, reject)
54-
if not ok then
55-
reject(err)
54+
if reject_fn then
55+
-- Two-argument form: resolve_fn is called with resolve, reject_fn is called with reject
56+
if resolve_fn then
57+
pcall(resolve_fn, resolve, reject)
58+
end
59+
pcall(reject_fn, reject)
60+
elseif resolve_fn then
61+
local ok, err = pcall(resolve_fn, resolve, reject)
62+
if not ok then
63+
reject(err)
64+
end
5665
end
5766

5867
return self
@@ -115,12 +124,14 @@ end
115124
--- @param fn function()
116125
--- @return Promise
117126
function Promise:finally_(fn)
118-
return self:then_(function(value)
119-
fn()
120-
return value
121-
end):catch_(function(err)
122-
fn()
123-
return M.reject(err)
127+
return M.new(function(resolve, reject)
128+
self:then_(function(value)
129+
fn()
130+
resolve(value)
131+
end):catch_(function(err)
132+
fn()
133+
reject(err)
134+
end)
124135
end)
125136
end
126137

@@ -135,7 +146,7 @@ end
135146
--- @param err any
136147
--- @return Promise
137148
function M.reject(err)
138-
return M.new(_, function() end, function(reject) reject(err) end)
149+
return M.new(nil, function(reject) reject(err) end)
139150
end
140151

141152
--- Wait for all promises to settle.

lua/poste/sql/db_browser/tree.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ function M.flatten_tree(nodes, depth)
148148
local suffix = ""
149149
if node.node_type == "column" and node.meta then
150150
suffix = " " .. (node.meta.col_type or "?")
151+
if node.meta.is_pk then
152+
suffix = suffix .. " PK"
153+
end
151154
if node.meta.extra and node.meta.extra:lower():find("auto_increment") then
152155
suffix = suffix .. " auto_increment"
153156
end

lua/poste/sql/editor/cell.lua

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,14 @@ function M.is_datetime_column(col_meta)
5050
end
5151

5252
function M.is_enum_column(col_meta)
53-
return col_meta and col_meta.enum_values and #col_meta.enum_values > 0
53+
return col_meta and col_meta.enum_values and #col_meta.enum_values > 0 or false
5454
end
5555

5656
function M.is_editable_field(col_meta)
5757
if not col_meta then return false end
58+
if col_meta.user_defined then
59+
return false
60+
end
5861
if col_meta.primary_key and col_meta.default then
5962
return true
6063
end
@@ -74,8 +77,12 @@ end
7477
--- Parse a user input string into a typed value suitable for SQL.
7578
--- Handles: JSON, UUID, datetime, numbers, booleans, NULL.
7679
function M.parse_value(input, old_val)
77-
if input == "" or input == "(NULL)" then return vim.NIL end
78-
if input == "null" then return vim.NIL end
80+
if input == "(NULL)" then return vim.NIL end
81+
if input == "null" or input == "NULL" then return vim.NIL end
82+
if input == "" then
83+
return old_val ~= nil and vim.NIL or nil
84+
end
85+
if input == "''" then return "" end
7986

8087
-- Expressions (computed in SQL)
8188
if input:match("^__expr:") then return input end
@@ -123,6 +130,10 @@ function M.validate_value(value, col_meta)
123130
end
124131

125132
if type(value) == "number" then
133+
if is_type(ctype, "boolean") then
134+
if value == 1 or value == 0 then return true end
135+
return false, "Only 0 and 1 allowed for boolean column"
136+
end
126137
if not is_type(ctype, "numeric") then
127138
return false, "Cannot assign number to " .. (col_meta.ctype or "unknown") .. " column"
128139
end
@@ -136,9 +147,22 @@ function M.validate_value(value, col_meta)
136147
if type(value) == "string" then
137148
if value:match("^__expr:") then return true end
138149
if is_type(ctype, "uuid") then
139-
if not value:match("^[0-9a-fA-F%-]+$") then
150+
local parts = { value:match("^(%x%x%x%x%x%x%x%x)-(%x%x%x%x)-(%x%x%x%x)-(%x%x%x%x)-(%x%x%x%x%x%x%x%x%x%x%x%x)$") }
151+
if not parts or #parts ~= 5 then
140152
return false, "Invalid UUID format"
141153
end
154+
return true
155+
end
156+
if is_type(ctype, "integer") or is_type(ctype, "numeric") then
157+
return false, "Cannot assign string to " .. (col_meta.ctype or "unknown") .. " column"
158+
end
159+
if is_type(ctype, "boolean") then
160+
return false, "Cannot assign string to boolean column"
161+
end
162+
if is_type(ctype, "date") then
163+
if not value:match("^%d") then
164+
return false, "Invalid date format"
165+
end
142166
end
143167
return true
144168
end
@@ -158,7 +182,7 @@ function M.create_edit_state()
158182
deleted_rows = {},
159183
added_rows = {},
160184
dirty = false,
161-
errors = {},
185+
cell_errors = {},
162186
}
163187
end
164188

@@ -169,6 +193,17 @@ end
169193
--- @param old_val any Previous value
170194
--- @param new_val any New value
171195
function M.track_cell_edit(es, row_key, col, old_val, new_val)
196+
if new_val == old_val then
197+
es.modified_cells[row_key] = nil
198+
if not next(es.modified_cells) then
199+
es.dirty = false
200+
end
201+
return
202+
end
203+
local row_idx = tonumber(row_key:match("^(%d+):"))
204+
if row_idx and es.deleted_rows[row_idx] then
205+
return
206+
end
172207
es.modified_cells[row_key] = { col = col, old_val = old_val, new_val = new_val }
173208
es.dirty = true
174209
end
@@ -179,14 +214,20 @@ end
179214
function M.track_row_delete(es, row_idx)
180215
es.deleted_rows[row_idx] = true
181216
es.dirty = true
217+
for k, _ in pairs(es.modified_cells) do
218+
local r = tonumber(k:match("^(%d+):"))
219+
if r == row_idx then
220+
es.modified_cells[k] = nil
221+
end
222+
end
182223
end
183224

184225
--- Track a row addition.
185226
--- @param es table Edit state
186227
--- @param row_data table Row data
187228
--- @param row_idx number Row index
188229
function M.track_row_add(es, row_data, row_idx)
189-
table.insert(es.added_rows, { row_data = row_data, row_idx = row_idx })
230+
table.insert(es.added_rows, { data = row_data, row_idx = row_idx })
190231
es.dirty = true
191232
end
192233

@@ -200,33 +241,33 @@ end
200241

201242
--- Get a summary of pending changes for display.
202243
function M.get_edit_summary(es)
203-
if not es then return "" end
204-
local parts = {}
205-
local cell_count = 0
206-
for _ in pairs(es.modified_cells) do cell_count = cell_count + 1 end
207-
if cell_count > 0 then table.insert(parts, cell_count .. " cells") end
208-
local del_count = 0
209-
for _ in pairs(es.deleted_rows) do del_count = del_count + 1 end
210-
if del_count > 0 then table.insert(parts, del_count .. " deleted") end
211-
if #es.added_rows > 0 then table.insert(parts, #es.added_rows .. " added") end
212-
return table.concat(parts, ", ")
244+
if not es then return { updates = 0, inserts = 0, deletes = 0 } end
245+
local ups = 0
246+
for _ in pairs(es.modified_cells) do ups = ups + 1 end
247+
local dels = 0
248+
for _ in pairs(es.deleted_rows) do dels = dels + 1 end
249+
return { updates = ups, inserts = #es.added_rows, deletes = dels }
213250
end
214251

215252
--- Count pending changes (for display).
216253
function M.count_pending_changes(es)
217-
if not es or not es.dirty then return 0 end
218-
local count = 0
219-
for _ in pairs(es.modified_cells) do count = count + 1 end
220-
for _ in pairs(es.deleted_rows) do count = count + 1 end
221-
count = count + #es.added_rows
222-
return count
254+
if not es or not es.dirty then return { modified = 0, deleted = 0, added = 0 } end
255+
local mod = 0
256+
for _ in pairs(es.modified_cells) do mod = mod + 1 end
257+
local del = 0
258+
for _ in pairs(es.deleted_rows) do del = del + 1 end
259+
return { modified = mod, deleted = del, added = #es.added_rows }
223260
end
224261

225262
--- Return a short text representation of pending changes.
226263
function M.pending_changes_text(es)
227-
if not es or not es.dirty or not M.has_pending_changes(es) then return "" end
228-
local count = M.count_pending_changes(es)
229-
return " (" .. count .. " change" .. (count ~= 1 and "s" or "") .. ")"
264+
if not es or not es.dirty or not M.has_pending_changes(es) then return nil end
265+
local counts = M.count_pending_changes(es)
266+
local parts = {}
267+
if counts.modified > 0 then table.insert(parts, "~" .. counts.modified) end
268+
if counts.added > 0 then table.insert(parts, "+" .. counts.added) end
269+
if counts.deleted > 0 then table.insert(parts, "-" .. counts.deleted) end
270+
return table.concat(parts, " ")
230271
end
231272

232273
--- Reset edit state, clearing all pending changes.
@@ -236,21 +277,21 @@ function M.reset_edit_state(es)
236277
es.deleted_rows = {}
237278
es.added_rows = {}
238279
es.dirty = false
239-
es.errors = {}
280+
es.cell_errors = {}
240281
end
241282

242283
--- Clear a cell error.
243284
function M.clear_cell_error(es, row_key)
244-
if es and es.errors then
245-
es.errors[row_key] = nil
285+
if es and es.cell_errors then
286+
es.cell_errors[row_key] = nil
246287
end
247288
end
248289

249290
--- Set a cell error.
250291
function M.set_cell_error(es, row_key, msg)
251292
if not es then return end
252-
if not es.errors then es.errors = {} end
253-
es.errors[row_key] = msg
293+
if not es.cell_errors then es.cell_errors = {} end
294+
es.cell_errors[row_key] = msg
254295
end
255296

256297
---------------------------------------------------------------------------
@@ -261,6 +302,7 @@ end
261302
--- @param val table JSON value
262303
--- @return string
263304
function M.format_json_input(val)
305+
if type(val) == "string" then return val end
264306
local ok, str = pcall(vim.json.encode, val)
265307
if ok then
266308
local no_esc = str:gsub('\\"', '"')

lua/poste/sql/log_viewer.lua

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,19 @@ M._clean_sql = clean_sql
9595
local function guess_table(sql)
9696
if not sql then return nil end
9797
local patterns = {
98-
"[Ff][Rr][Oo][Mm]%s+([%w_]+)",
9998
"[Jj][Oo][Ii][Nn]%s+([%w_]+)",
99+
"[Ff][Rr][Oo][Mm]%s+([%w_]+%.?([%w_]+))",
100100
"[Uu][Pp][Dd][Aa][Tt][Ee]%s+([%w_]+)",
101101
"[Ii][Nn][Tt][Oo]%s+([%w_]+)",
102102
"[Dd][Ee][Ll][Ee][Tt][Ee]%s+[Ff][Rr][Oo][Mm]%s+([%w_]+)",
103103
"[Ii][Nn][Ss][Ee][Rr][Tt]%s+[Ii][Nn][Tt][Oo]%s+([%w_]+)",
104104
}
105105
for _, pat in ipairs(patterns) do
106106
local t = sql:match(pat)
107-
if t then return t end
107+
if t then
108+
local _, after_dot = t:match("([%w_]+)%.([%w_]+)")
109+
return after_dot or t
110+
end
108111
end
109112
return nil
110113
end

tests/completion_coverage_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ describe("M.register() and M.status()", function()
477477
package.loaded["poste.http.completion"] = nil
478478
local fresh_completion = require("poste.http.completion")
479479
local status = fresh_completion.status()
480-
assert.equals("no completion engine registered", status)
480+
assert.equals("not registered", status)
481481
end)
482482
end)
483483

tests/helpers/mock_nvim.lua

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ local M = {}
1414
-- Store originals for teardown
1515
local _originals = {}
1616

17+
-- Buffer option cache for mocked vim.bo
18+
local _bo_cache = {}
19+
1720
-- Track calls for assertions
1821
M.calls = {}
1922

@@ -78,11 +81,21 @@ end
7881
table.insert(M.calls, { buf = buf, opts = opts2 })
7982
end
8083

81-
-- Mock nvim_create_buf
84+
-- Mock nvim_create_buf — return a fixed id; mock vim.bo to match
8285
vim.api.nvim_create_buf = function(listed, scratch)
8386
table.insert(M.calls, "nvim_create_buf")
8487
return 1001
8588
end
89+
-- Mock vim.bo so vim.bo[buf].filetype works for common buffer ids
90+
_originals.vim_bo = vim.bo
91+
vim.bo = setmetatable({}, {
92+
__index = function(_, buf)
93+
if not _bo_cache[buf] then
94+
_bo_cache[buf] = { filetype = "" }
95+
end
96+
return _bo_cache[buf]
97+
end,
98+
})
8699

87100
-- Mock nvim_open_win
88101
vim.api.nvim_open_win = function(buf, enter, config)
@@ -335,6 +348,8 @@ function M.teardown()
335348
if _originals.vim_schedule then vim.schedule = _originals.vim_schedule end
336349
if _originals.vim_keymap_set and vim.keymap then vim.keymap.set = _originals.vim_keymap_set end
337350
if _originals.vim_base64 then vim.base64 = _originals.vim_base64 end
351+
if _originals.vim_bo then vim.bo = _originals.vim_bo end
352+
_bo_cache = {}
338353
M.reset_calls()
339354
end
340355

tests/http/indicators_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ describe("indicators", function()
1212
-- Re-require to pick up fresh module state
1313
package.loaded["poste.indicators"] = nil
1414
indicators = require("poste.indicators")
15-
end
15+
end)
1616

1717
after_each(function()
1818
mock.teardown()

0 commit comments

Comments
 (0)