跳至內容
Astera Technology

舊欄改了,新表示欄為何仍不一致?

沿本例舊欄主導約定,以同一交易更新兩種表示。

下載完整個案資料及參考答案 ↓

先核來源與已訂規則

本例過渡結構存 old2、scaled20,須保持 scaled=old×10。兩種表示本來都要有值,來源只准改 old;更新值須是整數 Number,且本身與乘十結果都須為安全整數,NULL 則暫停。更正先核已有值、差異、權限及所提值,才在同一交易更新兩欄。

已填假設輸入
紀錄輸入 JSON
原例輸入{"old":2,"scaled":20,"edit":{"side":"old","value":3}}
下載可編輯 CSV ↓

比較兩條實際路徑

輸入 old3,更正真正狀態是 3/30。原有 2/21 相反就保原暫停,不在發現矛盾後靜靜選一邊當真。

錯誤與更正路徑的輸出
路徑輸出 JSON
錯誤路徑{"error":null,"records":[{"id":1,"size_old":3,"size_new":20}]}
更正路徑{"error":null,"records":[{"id":1,"size_old":3,"size_new":30}]}
下載可編輯 CSV ↓
本地 Node.js 程序:22.23.3 或 24.14.1
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 INTEGER PRIMARY KEY,size_old INTEGER,size_new INTEGER);');db.prepare('INSERT INTO target VALUES(1,?,?)').run(i.old,i.scaled);let error=null;
      if(corrected){db.exec('BEGIN;');if(db.prepare('SELECT COUNT(*) AS n FROM target WHERE size_old IS NULL OR size_new IS NULL').get().n)error='missing-representation';
        else if(db.prepare('SELECT COUNT(*) AS n FROM target WHERE size_new<>size_old*10').get().n)error='divergent-existing-pair';
        else if(i.edit.side!=='old')error='non-authoritative-edit';else if(i.edit.value===null)error='missing-edit-value';
        else if(!Number.isSafeInteger(i.edit.value)||!Number.isSafeInteger(i.edit.value*10))error='invalid-edit-value';
        else db.prepare('UPDATE target SET size_old=?,size_new=? WHERE id=1').run(i.edit.value,i.edit.value*10);
        db.exec(error?'ROLLBACK;':'COMMIT;');}
      else db.prepare('UPDATE target SET '+(i.edit.side==='old'?'size_old':'size_new')+'=? WHERE id=1').run(i.edit.value);
      return {error,records:rows(db,'SELECT * FROM target')};
    }finally{db.close();}
  };
const cases=[{"label":"misleading base","input":{"old":2,"scaled":20,"edit":{"side":"old","value":3}},"expected":{"error":null,"records":[{"id":1,"size_old":3,"size_new":20}]},"corrected":false},{"label":"corrected base","input":{"old":2,"scaled":20,"edit":{"side":"old","value":3}},"expected":{"error":null,"records":[{"id":1,"size_old":3,"size_new":30}]},"corrected":true},{"label":"existing divergence blocks a new edit","input":{"old":2,"scaled":21,"edit":{"side":"old","value":3}},"expected":{"error":"divergent-existing-pair","records":[{"id":1,"size_old":2,"size_new":21}]},"corrected":true},{"label":"new-side direct edit lacks authority","input":{"old":2,"scaled":20,"edit":{"side":"new","value":30}},"expected":{"error":"non-authoritative-edit","records":[{"id":1,"size_old":2,"size_new":20}]},"corrected":true},{"label":"missing scaled counterpart held","input":{"old":2,"scaled":null,"edit":{"side":"old","value":3}},"expected":{"error":"missing-representation","records":[{"id":1,"size_old":2,"size_new":null}]},"corrected":true},{"label":"missing old counterpart held","input":{"old":null,"scaled":20,"edit":{"side":"old","value":3}},"expected":{"error":"missing-representation","records":[{"id":1,"size_old":null,"size_new":20}]},"corrected":true},{"label":"missing incoming old value held","input":{"old":2,"scaled":20,"edit":{"side":"old","value":null}},"expected":{"error":"missing-edit-value","records":[{"id":1,"size_old":2,"size_new":20}]},"corrected":true},{"label":"numeric zero edit is present","input":{"old":2,"scaled":20,"edit":{"side":"old","value":0}},"expected":{"error":null,"records":[{"id":1,"size_old":0,"size_new":0}]},"corrected":true},{"label":"text numeral is not a numeric edit","input":{"old":2,"scaled":20,"edit":{"side":"old","value":"3"}},"expected":{"error":"invalid-edit-value","records":[{"id":1,"size_old":2,"size_new":20}]},"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);
}
下載可執行例子 ↓

下次載入前核邊界

原差異照留 2/21;未准 new 側改 30,則仍 2/20。scaled 或 old 欠值都以 missing-representation 保原暫停;所提 old 值 NULL 則以 missing-edit-value 暫停。數字零可改成 0/0,文字 3 卻要停,不自行轉型。

可編輯邊界紀錄及預期輸出
情況輸入 JSON預期輸出 JSON
原有兩表示已不符{"old":2,"scaled":21,"edit":{"side":"old","value":3}}{"error":"divergent-existing-pair","records":[{"id":1,"size_old":2,"size_new":21}]}
輸入改未獲准一側{"old":2,"scaled":20,"edit":{"side":"new","value":30}}{"error":"non-authoritative-edit","records":[{"id":1,"size_old":2,"size_new":20}]}
scaled 表示欠值{"old":2,"scaled":null,"edit":{"side":"old","value":3}}{"error":"missing-representation","records":[{"id":1,"size_old":2,"size_new":null}]}
old 表示欠值{"old":null,"scaled":20,"edit":{"side":"old","value":3}}{"error":"missing-representation","records":[{"id":1,"size_old":null,"size_new":20}]}
所提 old 更新值欠缺{"old":2,"scaled":20,"edit":{"side":"old","value":null}}{"error":"missing-edit-value","records":[{"id":1,"size_old":2,"size_new":20}]}
有值的數字零更新{"old":2,"scaled":20,"edit":{"side":"old","value":0}}{"error":null,"records":[{"id":1,"size_old":0,"size_new":0}]}
文字數字留待查{"old":2,"scaled":20,"edit":{"side":"old","value":"3"}}{"error":"invalid-edit-value","records":[{"id":1,"size_old":2,"size_new":20}]}
下載可編輯 CSV ↓

old3 可否提交,scaled20 卻不改?

查看參考答案

不可,違本例兩表示約定。獲准更新須一同提交 3/30。

相關資源