先核來源與已訂規則
本例紀錄有 name 及 extensions,後者未知成員也要搬移保留。只重建熟悉的 name,會丟 colour blue。擴充集合不可再定保留欄 name,空集合形狀也須留。
| 紀錄 | 輸入 JSON |
|---|---|
| 原例輸入 | {"name":"A","extensions":{"colour":"blue"}} |
比較兩條實際路徑
更正保 nameA 及擴充 colour blue。擴充又寫 nameB,要連原輸入暫停,不靜靜選其中一值。
| 路徑 | 輸出 JSON |
|---|---|
| 錯誤路徑 | {"accepted":true,"record":{"name":"A"}} |
| 更正路徑 | {"accepted":true,"record":{"name":"A","extensions":{"colour":"blue"}}} |
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 {name,extensions}=i;
if(corrected&&Object.hasOwn(extensions,'name'))return {accepted:false,error:'reserved-extension-name',original:i};
const db=new DatabaseSync(':memory:');try{db.exec('CREATE TABLE target(name TEXT,extensions TEXT);');
if(corrected)db.prepare('INSERT INTO target VALUES(?,?)').run(name,JSON.stringify(extensions));
else db.prepare('INSERT INTO target(name) VALUES(?)').run(name);
const stored=db.prepare('SELECT * FROM target').get();
return {accepted:true,record:stored.extensions===null?{name:stored.name}:{name:stored.name,extensions:JSON.parse(stored.extensions)}};
}finally{db.close();}
};
const cases=[{"label":"misleading base","input":{"name":"A","extensions":{"colour":"blue"}},"expected":{"accepted":true,"record":{"name":"A"}},"corrected":false},{"label":"corrected base","input":{"name":"A","extensions":{"colour":"blue"}},"expected":{"accepted":true,"record":{"name":"A","extensions":{"colour":"blue"}}},"corrected":true},{"label":"reserved extension conflict","input":{"name":"A","extensions":{"name":"B"}},"expected":{"accepted":false,"error":"reserved-extension-name","original":{"name":"A","extensions":{"name":"B"}}},"corrected":true},{"label":"empty extension map","input":{"name":"A","extensions":{}},"expected":{"accepted":true,"record":{"name":"A","extensions":{}}},"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);
}
下次載入前核邊界
保留欄名衝突要拒收;空集合仍 {},不是消失或改 null。
| 情況 | 輸入 JSON | 預期輸出 JSON |
|---|---|---|
| 擴充名稱與保留欄衝突 | {"name":"A","extensions":{"name":"B"}} | {"accepted":false,"error":"reserved-extension-name","original":{"name":"A","extensions":{"name":"B"}}} |
| 刻意保留空擴充集合 | {"name":"A","extensions":{}} | {"accepted":true,"record":{"name":"A","extensions":{}}} |
只拷貝熟悉欄位,這裏可算完整搬移嗎?
查看參考答案
不可,已約定擴充資料也是紀錄部分。colour blue 與整個集合均須保,明確空集合也一樣。