先核來源與已訂規則
本例可先存各有效行,但正式採用須每筆都有已接受處理。A2、B−1、C3 同受 NOT NULL 及正數 CHECK;OR IGNORE 跳 B 卻不拋錯。更正普通插入捕捉 B 真正 CHECK275,暫停採用。
| 紀錄 | 輸入 JSON |
|---|---|
| 原例輸入 | {"records":[{"id":"A","quantity":2},{"id":"B","quantity":-1},{"id":"C","quantity":3}]} |
比較兩條實際路徑
兩路都有暫存 A、C;分別是更正留 B 拒收資料,不再誤稱三筆全成功。
| 路徑 | 輸出 JSON |
|---|---|
| 錯誤路徑 | {"released":true,"errors":[],"target":[{"id":"A","quantity":2},{"id":"C","quantity":3}]} |
| 更正路徑 | {"released":false,"errors":[{"source":"B","code":275}],"target":[{"id":"A","quantity":2},{"id":"C","quantity":3}]} |
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};
import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
const db=new DatabaseSync(':memory:');try{db.exec('CREATE TABLE target(id TEXT PRIMARY KEY,quantity INTEGER NOT NULL CHECK(quantity>0));');const errors=[];
for(const r of i.records){const error=failed(()=>db.prepare('INSERT '+(corrected?'':'OR IGNORE ')+'INTO target VALUES(?,?)').run(r.id,r.quantity));if(error)errors.push({source:r.id,code:error.code});}
return {released:errors.length===0,errors,target:rows(db,'SELECT * FROM target ORDER BY id')};
}finally{db.close();}
};
const cases=[{"label":"misleading base","input":{"records":[{"id":"A","quantity":2},{"id":"B","quantity":-1},{"id":"C","quantity":3}]},"expected":{"released":true,"errors":[],"target":[{"id":"A","quantity":2},{"id":"C","quantity":3}]},"corrected":false},{"label":"corrected base","input":{"records":[{"id":"A","quantity":2},{"id":"B","quantity":-1},{"id":"C","quantity":3}]},"expected":{"released":false,"errors":[{"source":"B","code":275}],"target":[{"id":"A","quantity":2},{"id":"C","quantity":3}]},"corrected":true},{"label":"all valid writes","input":{"records":[{"id":"A","quantity":2}]},"expected":{"released":true,"errors":[],"target":[{"id":"A","quantity":2}]},"corrected":true},{"label":"empty permitted input batch","input":{"records":[]},"expected":{"released":true,"errors":[],"target":[]},"corrected":true},{"label":"missing quantity is retained as rejection","input":{"records":[{"id":"A","quantity":2},{"id":"B","quantity":null}]},"expected":{"released":false,"errors":[{"source":"B","code":1299}],"target":[{"id":"A","quantity":2}]},"corrected":true}];
for(const test of cases){
const actual=run(test.input,test.corrected);
assert.deepEqual(actual,test.expected,test.label);
console.log(test.label,actual);
}
下次載入前核邊界
全部有效 A 可收;本例明准空批次,不會有拒收輸入。B 數量欠值則違 NOT NULL1299,保留有效暫存 A,但暫停正式採用。
| 情況 | 輸入 JSON | 預期輸出 JSON |
|---|---|---|
| 所有輸入行有效 | {"records":[{"id":"A","quantity":2}]} | {"released":true,"errors":[],"target":[{"id":"A","quantity":2}]} |
| 明准的空批次 | {"records":[]} | {"released":true,"errors":[],"target":[]} |
| 欠缺數量留拒收記錄 | {"records":[{"id":"A","quantity":2},{"id":"B","quantity":null}]} | {"released":false,"errors":[{"source":"B","code":1299}],"target":[{"id":"A","quantity":2}]} |
三筆輸入存到兩行,是否證明整批成功?
查看參考答案
不是,錯路跳過 B。須留其 275 處理記錄,更正前暫停正式採用。