Skip to Content
核心概念規則date_interval_exclusion

date_interval_exclusion 規則

date_interval_exclusion 讓日期期間在同一個分割(partition)內不會重疊:同一時間每個產品只有一個價格、每位員工只有一份合約、每個資源只有一個指派。期間從必填的起始日起算,到結束日(不含)為止,結束日可以是 null,代表沒有終點。分割由一或兩個基數為 one 的 link 決定。它是 no_overlap 的「只限日期、更嚴格」版本:每次新增都必須明確帶出結束日,沒有終點的期間是真正永不結束的期間,而且每一條寫入路徑——REST、bulk、匯入、IaC、Command、callback、trigger、agent 與 MCP——都在同一個資料表 guard 下受它約束。

Payload

{ "type": "date_interval_exclusion", "name": "同一時間每個產品只有一個價格", "start_column": "生效日", "end_column": "失效日", "scope_columns": ["產品"] }
欄位契約
start_column本資料表上必須是 required 的儲存型 date 欄位。
end_column另一個不是 required 的儲存型 date 欄位:null 代表期間永不結束。
scope_columns本資料表上一或兩個基數為 one 的原生 link 欄位。只有每個 scope link 依所列順序指向相同目標的資料列才會互相競爭。

引用可用顯示名稱或內部 key。when 只能省略、為 null 或 [],id 必須符合 rule_<8–32 hex>,name 最長 128 個字元,未知 key 會被拒絕;request schema 把這些回報為 422 Value error, rules[<i>]: …。這條規則算進 10 條規則上限,不算進 unique 上限。GET 會把 start_column、end_column 與 scope_columns 以顯示名稱回傳。

設定錯誤是 400,detail 為單純字串(後面可能接一段列出候選欄位的提示):

detail原因
column '<name>' not found in '<table>'引用的欄位不存在
column '<name>' is type <type> — start_column requires one of: date起始欄位(結束欄位則是 end_column)不是 date 欄位
column '<name>' is type <type> — rules may only reference stored scalar columns (and link columns where documented)用 link、rollup、lookup 或 formula 欄位當作邊界
start and end columns must be distinctstart_column 與 end_column 是同一個欄位
date_interval_exclusion start column must be required起始欄位允許 null
date_interval_exclusion end column must allow null結束欄位是 required
'<name>' must be a link column of '<table>'scope_columns 的項目不是本資料表的 link 欄位
date_interval_exclusion requires cardinality-one linksscope link 的基數是 many
date_interval_exclusion scope columns must be distinct同一個 link 列了兩次

伺服器會強制什麼

每一個存活資料列,都是它 scope link 所屬分割中的一個期間 [start, end):

  • start 是合法的 YYYY-MM-DD 日期,end 是 null 或較晚的 YYYY-MM-DD 日期——結束日等於或早於起始日會被拒絕;
  • 每個 scope link 都必須剛好指向一個目標,所以沒有分割、或有兩個分割的資料列會被拒絕;
  • 同一個分割內,沒有任何兩個存活資料列重疊。期間是左閉右開的,所以一個期間可以在另一個結束的當天開始;null 的結束日代表期間永不結束:它會與該分割內所有「在它的起始日之前尚未結束」的期間重疊。軟刪除的資料列不算。

被拒絕的寫入是不含任何值的 409:

{"detail": {"error": "date_interval_exclusion_overlap", "message": "Date period overlaps another period in this partition."}}
errormessage意義
date_interval_exclusion_invalid_periodDate period is invalid.建立時省略了 end key、結束日為空字串、結束日不晚於起始日,或 scope link 沒有剛好指向一個目標(為 null 或格式錯誤的起始日、欄位沒有預設值時缺漏的起始日,以及格式錯誤的結束日,會被欄位檢查以 400 拒絕,訊息依寫入者而異;若建立同時省略了 end key,則先得到這個 409)
date_interval_exclusion_overlapDate period overlaps another period in this partition.同一分割內另一個存活資料列涵蓋了這個期間的一部分
date_interval_exclusion_retryDate period rules changed during this write; retry.寫入等待 guard 期間資料表的規則改變了;沒有寫入任何東西,請重送

任何 body 都不會指出衝突的資料列、它的日期或 scope 值;但拒絕訊息仍會讓呼叫者知道,該分割中有某筆存活資料列(可能是他們讀不到的)與這段期間重疊。

寫入資料列

建立資料列時必須帶出結束日,值是日期或 JSON null:省略這個 key 是 date_interval_exclusion_invalid_period,不是沒有終點;欄位預設值也不算,因為檢查針對的是呼叫者送來的內容。部分更新時,省略的起始、結束與 scope 欄位保留原本儲存的值,只有明確的 null 結束日才會把期間改為沒有終點。每次更新都會重新檢查完整的新期間與分割,包含只改動 scope link 的更新。

規則在每一次寫入之後檢查,而不是等到 commit。要換掉一個期間,請先關閉舊期間、再插入接續的新期間——在同一個原子 Command 或同一個 bulk 批次中依此順序進行;先插入接續的期間,只要舊期間仍涵蓋它的起始日就會被拒絕。帶有這條規則的資料表,每個寫入者在讀取或鎖定資料列之前,都會以排他方式取得該資料表的寫入 guard,所以對該表的寫入會序列化,兩個寫入者不可能並行放進重疊的期間。bulk 批次與匯入會逐列 flush,讓每一列都看得到它之前的資料列。

啟用規則

PUT 在儲存之前會檢查每一個既有的存活資料列:每列都必須是合法分割中的合法期間,而且任兩列不得重疊,否則整份清單以 409 date_interval_exclusion_invalid_period 或 409 date_interval_exclusion_overlap 被拒絕,什麼都不儲存。沒有儲存 end key 的資料列視為不合法。這項檢查在資料表寫入 guard 之下執行,所以也會和一般寫入者序列化。rules.preview 只驗證候選規則的格式,不會掃描既有資料列,所以請在發布前先自行稽核資料表。

相關欄位與資料表的保護

操作回應
刪除 start_column、end_column 或 scope_columns 的 link,或變更起訖欄位的型別409 衝突 {"type": "dependent_rule", …},指出該規則:請先刪除規則(link 欄位本身完全不能改型別:400 Only name/description can be updated on link columns (got: type))
把起始欄位改為可選,或把結束欄位改為必填409 {"error": "date_interval_exclusion_dependency", "message": "Remove the date interval rule before changing this bound column requirement."}
Purge scope link 所指向的資料表Purge preview blocker {"code": "date_interval_exclusion_dependency", "table_id": "<source table>", "message": "remove the dependent date interval exclusion rule before purging its link target"};若資料表 purge 仍然執行到那裡,則回 400 並帶同一則訊息,tag purge 則回 409 purge_blocked 並列出該 blocker

其他寫入路徑

  • 還原與 revert。 還原垃圾桶中的資料列,或把資料列 revert 到較早版本,都和任何寫入一樣:會對照存活資料列檢查,期間被占用或不合法時,以相同的錯誤碼被拒絕。
  • 審批。 被 require_approval 規則攔下的寫入不會保留它的期間。Apply 時會對照存活資料列重新檢查,發生衝突就讓 staged change 以 apply_failed 結束。
  • Bulk 與匯入。 同步 bulk 請求會整個回滾。非同步的 bulk 或匯入 ticket 會讓每一列各自在 savepoint 內 flush,所以被拒絕的期間是該列的 ticket 錯誤,其他列仍會寫入。
  • Publish session。 暫存 chunk 時會對照存活資料列執行建議性檢查,而不是對照 replace_filter 的結果:期間與「replace 會刪除的存活資料列」衝突的資料列,會在暫存時以 400 invalid_rows 被拒絕。請把這樣的資料列改放到空閒的區間,或先更動存活資料列。互相重疊的暫存列在暫存時不會彼此比對:兩筆都會通過暫存,commit 時才以 rule_violation 在較後那一列的 seq 與 row_index 失敗。commit 時會在 guard 之下再檢查一次。
  • Command。 每個寫入 step 都會立即檢查。拒絕會讓整個 command 回滾,並把規則自己的 409 body 原樣傳出,agent 工具會回報為 custom_table_command_failed,並帶 http_status: 409。若呼叫者並非管理每一張被引用的資料表,而執行的是 definer authority 的 command,得到的則是遮蔽過的 command_failed body。見寫入型 steps。
  • IaC。 record 行會把起始日、結束日與每個基數為 one 的 link 在一次寫入中完成(見 record 行);拒絕會以相同的錯誤碼作為 IacLineError.code。rule 行接受相同的 payload(IaC rule 行)。
  • Agent。 資料表頁面會帶 Visible date interval exclusion policies JSON——最多 10 組 {"start_column","end_column","scope_columns"},只有起始、結束與每個 scope 欄位都可見時才會出現。任何一部分被隱藏,整條政策就不會出現在頁面上,但規則仍然會被強制執行。協定教模型送出 YYYY-MM-DD 的起始日、較晚的日期或 null 的結束日,以及每個 scope link 一個被允許的目標,而且絕不推測或繞過衝突的資料列。

兩者怎麼選

no_overlapdate_interval_exclusion
邊界數值、decimal、日期、日期時間、類字串,或單一 interval 儲存格兩個 date 欄位,起始必填、結束可為 null
沒有終點缺少邊界的資料列會被豁免null 結束日是永不結束的期間;新增時省略結束日會被拒絕
分割scope_columns 的 link 加上可選的 date_column一或兩個基數為 one 的原生 link;每列對每個 link 都必須剛好有一個目標
最小間隔min_gap無:相鄰的期間可以相接
Last updated on