본문으로 건너뛰기

레코드 멤버별 옵셔널 — :requiredInObject

문서 목록으로

상태: 구현 완료

배열은 첫 원소가 배열 전체를 정하지만, 레코드 멤버는 각자 정합니다. named-range 레이아웃은 그것을 제약 행에 적어 두고, 이 도구가 그 행을 읽습니다.


1. 문제 — 버려지는 216개의 선언

한 레이아웃의 시트에는 제약 행이 여러 종류 있고, 그중 하나가 이것입니다.

제약개수
:required이 컬럼은 값이 있어야 한다580
:requiredInObject중첩 객체가 존재할 때 그 안에서 필수216

레이아웃 파서는 이 행을 읽지 않고 있었습니다. 216개의 선언이 말없이 버려졌고, 그 규칙을 어긴 시트는 통과했습니다.

2. 로드맵의 전제와 다른 점

로드맵 5d는 이 항목을 이렇게 적어 두었습니다.

와이어가 레코드 멤버의 presence를 담지 않습니다 — 「Id는 있는데 Count는 없다」를 낼 자리가 없습니다. 형식과 모든 생성기를 함께 건드리는 일이라…

그리고 v103 스펙 6절도 같은 전제로 이 항목을 미뤄 두었습니다.

그 전제가 한 겹 어긋나 있습니다. :requiredInObject표현의 요구가 아니라 검증 규칙입니다. 「그 안에서 필수」는 무엇이 담길 수 있어야 하는지가 아니라 무엇이 참이어야 하는지를 규정합니다.

강제와 표현의 관계

레코드가 존재하는데 그 멤버가 비어 있는 시트를 변환이 거부하면, 「Id는 있는데 Count는 없다」는 애초에 파일에 도달하지 않습니다. 담을 자리가 없는 것이 문제가 아니라, 담길 일이 없어야 하는 것이 규칙의 내용입니다.

읽는 방식비용
검증 규칙으로 (이 문서의 결정)레이아웃이 제약 행 하나를 더 읽고, 이미 있는 검증 패스가 어느 셀인지 함께 보고합니다. 형식 무변경 · 모든 생성기 무변경 · 모든 리더 무변경
와이어 presence로형식 개정 + 모든 생성기 + 모든 리더. 로드맵이 가정한 것

결정. 검증 규칙으로 읽습니다.

3. 결정 — 「레코드가 존재한다」의 정의

규칙이 「객체가 존재할 때」로 조건이 붙어 있으므로, 그 조건을 정해야 합니다. 이것이 로드맵이 말한 「결정 사항」입니다.

결정. 멤버 중 하나라도 값이 있으면 그 레코드는 존재합니다.

Slot1.IdSlot1.CountCount:requiredInObject일 때
통과
없음거부 — 레코드가 존재하는데 필수 멤버가 비었습니다
없음거부 — Id:requiredInObject라면
없음없음통과 — 레코드가 없으므로 조건이 성립하지 않습니다

배열 규칙과 다른 이유

배열의 옵셔널은 첫 원소가 전부를 정합니다. 레코드는 그럴 수 없습니다 — Slot[0]["Id"]Slot[0]["Count"]서로 다른 컬럼이고 타입도 다릅니다. 하나를 골라 대표로 삼으면 그 멤버가 비었을 때 나머지가 있어도 레코드가 없는 것이 됩니다.

이것은 가변 길이 배열의 절단 규칙이 이미 쓰고 있는 정의와 같습니다 — 「원소는 멤버 전부가 값이 없을 때 비어 있다」. 두 자리가 같은 규칙을 쓰는 편이 맞습니다. 하나는 자를지를 정하고 다른 하나는 거부할지를 정하지만, 확인하는 것은 같은 질문입니다.

「값이 없다」의 정의

레이아웃이 정합니다. 코어는 Cell.HasValue 하나만 읽습니다 — 다른 두 스펙과 같은 규칙입니다.

4. 거부

거부할 것메시지에 나오는 것
레코드가 존재하는데 :requiredInObject 멤버가 비어 있음그 셀과, 그 레코드를 존재하게 만든 멤버
:requiredInObject가 레코드 멤버가 아닌 컬럼에 붙음그 제약 행의 셀. 평평한 컬럼에는 「객체 안」이 없습니다

두 번째가 필요한 이유는 그 표기가 실수하기 쉬운 자리이기 때문입니다 — 한 시트에는 :requireedInObject라는 오타가 세 테이블에 있고, 그것은 지금 아무 일도 하지 않습니다.

5. 담지 않는 것

  • 와이어의 멤버별 presence. 2절. 규칙을 강제하면 표현할 것이 남지 않습니다. 강제하지 않는 소스에서 그 형태가 필요해지면 그때 다시 봅니다.
  • :requiredInObject를 코어 표기로. 이것은 그 레이아웃의 제약 행 이름입니다. 코어가 받는 것은 「이 필드는 레코드가 존재할 때 필수」라는 모델 수준의 선언이고, 그 이름은 레이아웃 파일에만 있습니다 (CLAUDE.md).
  • 레코드 자체의 옵셔널. 「이 로우에 Slot1이 아예 없다」는 배열의 길이가 정하는 것이고, 그것은 가변 길이 배열입니다.

6. 검증 게이트

게이트확인하는 것
픽스처레코드가 존재하는데 필수 멤버가 빈 로우. 셀 위치가 나오는지까지
통과 픽스처멤버 전부가 빈 레코드 — 조건이 성립하지 않으므로 통과해야 합니다
오타 거부레코드 멤버가 아닌 컬럼에 붙은 제약
샘플 재생성됨. 위반 0건. main 7개 테이블에서 이 제약이 붙은 컬럼이 85개 읽혔고, 그중 규칙을 어긴 로우가 없습니다 — 그 시트들이 이미 지키고 있습니다. 읽히는 개수를 함께 센 것은 「0건」이 「검사가 안 돌았다」와 구별되지 않기 때문입니다
골든한 바이트도 바뀌지 않아야 합니다. 이 개정은 거부를 더할 뿐 값을 바꾸지 않습니다

마지막 줄이 이 설계의 성질을 요약합니다 — 출력이 바뀌지 않는 변경입니다.

7. 구현 순서

  1. 모델ColumnConstraints.RequiredInRecord와 그것을 선언한 셀. 완료.
  2. 레이아웃 — 제약 행을 읽어 그 자리에 넣습니다. 이름은 레이아웃 파일 안에만 있습니다. 완료.
  3. 검증 패스 — 3절의 정의로 판정하고 어느 셀인지 함께 보고합니다. 완료.
  4. 게이트 — 6절. 완료.
  5. 샘플 재생성완료. 위반 0건이므로 시트 오류 보고에 더할 것이 없습니다.