본문으로 건너뛰기

3. 시트의 구조

「주 시트 레이아웃」으로 돌아가기


3.1 마커 열과 선언 셀

엔티티는 선언 셀로 시작합니다. :table · :enum · :const로 시작하는 셀이 어디에 있든 그 자리가 엔티티의 시작이고, 그 셀의 열이 그 엔티티의 마커 열입니다.

:table Item(side=s) ← 선언 셀. 이름과 괄호 메타
  • 선언 셀의 오른쪽 첫 셀이 엔티티의 설명입니다. 비우면 설명 없음입니다. :table · :enum · :const 셋 다 같은 규칙입니다.
  • 괄호 메타는 생략할 수 있습니다. 아는 키는 §3.4의 표가 정본이고, 모르는 키는 아는 키의 목록과 함께 오류입니다(RequireKnownOptions와 같은 정책).
  • 이름은 기존 규칙 그대로 Pascal 표기로 정규화되고, 종류와 무관하게 유일해야 합니다.

마커 열은 엔티티의 세로 범위 전체에서 예약됩니다. 담을 수 있는 것은 다음뿐이고, :로 시작하는 미지의 값은 오류입니다 — Luban이 미지의 헤더 태그를 로그로만 남기는 것과 갈리는 자리입니다. : 없는 낱말은 행 태그이고, 그쪽은 이름을 선언하지 않으므로 검사하지 않습니다(태그 §4).

마커 열의 셀
:table … · :enum … · :const …엔티티 선언 (이 엔티티의 종료이기도 합니다)
:field · :type · :desc · :target · :variant헤더 행 키(§3.3)
빈 칸데이터 행
# (또는 //)그 행을 변환에서 제외. 데이터 칸을 편집하지 않고 제외 · 복원합니다
그 밖그 행의 태그key 또는 key=value, 쉼표로 여러 개. 레시피가 부를 때만 그 행이 빠집니다(태그). :enum:const에서는 담기기만 하고 행은 빠지지 않습니다 — 그 행들은 생성 코드이기 때문입니다

3.2 경계

범위
가로마커 열의 오른쪽부터, 다음 마커 열 직전까지. 없으면 시트의 마지막 컬럼까지
세로선언 셀의 다음 행부터, 완전히 빈 행 또는 다음 선언 셀 직전까지
  • 「완전히 빈 행」의 판정 범위는 그 엔티티의 컬럼 범위이고, 마커 열과 메모 컬럼을 포함합니다. 데이터 아래에 메모를 적으려면 한 줄 띄우면 됩니다.
  • 데이터 중간에 시각적 여백이 필요하면 마커 열에 #를 적거나 메모 컬럼에 구분선 문자를 적습니다 — 그 행은 빈 행이 아니므로 엔티티가 계속됩니다.
  • 기존 레이아웃의 「엔티티 간 침범 금지」 규칙은 필요 없습니다 — 옆 엔티티는 자기 마커 열에서 시작합니다. 엔티티 옆에 자유 기재가 필요하면 메모 컬럼(#, §3.3)으로 자리를 만들거나, 빈 행 하나로 닫힌 아래쪽에 적습니다.
  • 셀 병합은 읽지 않습니다. 병합 범위의 좌상단 셀만 값을 갖고 나머지는 빈 칸의 일반 규칙(§3.7)으로 읽힙니다. 판정은 경고이고 대상은 엔티티 범위 안의 병합입니다 — 메모 컬럼과 엔티티 밖은 자유입니다.

경고를 내려면 병합 정보가 먼저 와야 합니다. 지금은 병합 여부가 로우 모델에 오지 않습니다RawCell에 그 자리가 없고, 스트리밍 리더(Sylvan.Data.Excel)는 행과 값만 줍니다. 병합 사각형은 xlsx의 <mergeCells> · xlsb의 병합 레코드 · 구글 API의 merges를 따로 읽어야 나오고, 그것은 정의된 이름과 같은 등급의 임포터 작업입니다. 그래서 이 레이아웃의 일이 아니라 별건이고, §16의 순서에 넣지 않았습니다.

그때까지 병합 사고가 조용히 지나가지는 않습니다 — 병합에 의존하던 헤더는 좌상단 밖이 빈 칸이 되므로 「:field가 빈 컬럼에 데이터가 있음」(§3.3)과 「:type 셀이 빔」 (§3.7)이 그 셀을 가리켜 걸립니다. 없는 것은 「병합입니다」라고 이름을 대는 것이고, 그것이 경고가 더할 값입니다.

3.3 헤더 행

행 키역할생략
:field컬럼의 정체 — 이름 · 경로 · @N · * · #불가
:type타입 표현과 괄호 메타(§4)테이블은 불가. enum · const는 행 자체가 없습니다(§8)
:desc컬럼 설명. 생성 코드의 doc comment가 됩니다가능
:target대상의 쉼표 목록c · s · c,s. 행 생략과 개별 빈 칸 모두 양쪽입니다가능
:variant필드 변형의 이름(§3.6). 빈 칸은 기본 변형입니다가능
  • 행의 순서는 자유이고, 데이터 행보다 위에 있어야 합니다. :field를 데이터 바로 위에 두는 것을 권장 관례로 합니다 — 엑셀의 정렬 · 필터 머리글이 데이터와 인접합니다.
  • :field 셀에 # 하나만 적은 컬럼은 메모 컬럼입니다 — 시트 작성자가 자유롭게 적는 공간이라는 표시이고, 모델에 흔적을 남기지 않습니다. VLOOKUP 표시, 계산용 임시 열, 한국어 라벨이 여기에 해당합니다.
  • :field 셀이 빈 컬럼은 자리가 없는 컬럼입니다. 그 컬럼의 데이터 칸에 값이 있으면 오류이고, 메시지가 「필드라면 이름을, 메모 공간이라면 #를」 안내합니다 — 이름 없는 컬럼의 데이터가 조용히 버려지는 경로를 없애는 자리입니다(§11의 7).
  • #이름@N은 제외된 필드이고 와이어 태그를 예약합니다(Tombstone). 메모 컬럼(# 단독)과 뜻이 다릅니다 — 행 키 레이아웃 §2.3의 구분 그대로입니다.
  • 기본 인덱스는 지정이 없으면 첫 필드 컬럼입니다. 선언 셀의 key 메타로 다른 컬럼을 지정하거나 복합 키를 선언할 수 있습니다(§3.5). 어느 쪽이든 기존 규칙 전부가 성분마다 적용됩니다 — 유일 · 옵셔널 불가 · 양쪽 대상 필수 · 될 수 있는 타입.

3.4 선언 셀의 메타 키

sidec · s · c,s(기본)엔티티의 target-side. 기존 마커의 :side 자리
key필드 이름, 또는 따옴표 쉼표 목록기본 인덱스의 지정. 생략하면 첫 필드 컬럼입니다(§3.5)

단일 행 테이블(one) 등은 예약 후보로만 두고 §13에 적었습니다.

target의 표기는 쉼표 목록입니다 — Luban의 ##group c,s와 같은 형태이고, 대상이 셋 이상으로 일반화되는 날(기능 대조 §5.3)에도 표기가 그대로 확장됩니다. 붙여 쓴 csc,s와 같은 뜻으로 받습니다 — 기존 시트 · recipe · CLI가 쓰는 표기라서입니다. 괄호 메타 안에서는 쉼표가 항목 구분자이므로, 쉼표가 든 값은 DSL의 규칙 그대로 따옴표로 감쌉니다(side="c,s") — 다만 양쪽이 기본값이라 실제로 적을 일이 드뭅니다.

3.5 키의 지정 — key 메타

SQL의 키 체계를 따릅니다. 첫 키가 PRIMARY KEY, 나머지가 UNIQUE 키에 대응하고, 어느 것이든 단일 · 복합이 됩니다. 쉼표가 한 키 안의 성분을, 세미콜론이 키와 키를 가릅니다 — allowed=a;b;c와 같은 관례이고 새 기호가 없습니다. 쉼표 · 세미콜론이 들어가는 값은 따옴표로 감쌉니다(§3.4).

표기SQL 대응
(생략)첫 필드 컬럼이 기본 인덱스 — 지금 규칙 그대로PRIMARY KEY
key=code그 이름의 컬럼이 기본 인덱스. 첫 컬럼 강제가 풀리고, 첫 컬럼은 평범한 필드가 됩니다PRIMARY KEY
key="stage,slot"복합 기본 인덱스. 조합이 유일해야 하고, 조회가 다인자가 됩니다 — FindByKey(stage, slot)복합 PRIMARY KEY
key="stage,slot; slot,code"키 여러 개. 첫 키가 기본 인덱스, 나머지는 보조 키입니다 — 각자 유일하고 각자 조회를 얻으며, 개수 제한이 없습니다PRIMARY KEY + UNIQUE …
  • 첫 키가 기본 인덱스입니다 — 행을 가리키는 것 · 참조 대상 · 멀티 로우의 레코드 경계(§6.1)가 전부 첫 키의 것입니다.
  • *는 단일 보조 키의 컬럼 자리 표기입니다 — SQL이 컬럼 자리의 UNIQUE와 테이블 자리의 UNIQUE (…)를 둘 다 두는 것에 대응합니다. 컬럼 옆에서 보이는 것이 *의 가치이고, 목록에 적는 것과 뜻이 같습니다. 같은 키를 양쪽에 이중 선언하면 오류입니다.
  • 성분의 규칙 — key에 적힌 이름은 실재하는 최상위 스칼라 필드여야 하고(경로 · [] · [n] 불가), 성분마다 기본 인덱스의 기존 규칙(인덱스 가능 타입 · 옵셔널 불가 · 양쪽 대상)이 적용됩니다. 한 키 안에서 같은 성분을 두 번 적거나, 성분 구성이 같은 키를 두 번 선언하면 오류입니다. 성분 하나가 여러 키에 들어가는 것은 됩니다 — 위 표의 slot이 그 예입니다.
  • 복합 키의 성분에 *를 따로 붙이는 것도 됩니다 — 「조합도 유일하고 이 성분 혼자서도 유일하다」는 서로 다른 두 선언입니다.
  • 성분이 foreign인 것은 됩니다. 연결 테이블 — 한 행이 두 카탈로그의 짝을 뜻하는 표 — 이 복합 키가 가장 많이 나오는 자리이고, 그 두 컬럼이 다 참조입니다. 이때 조회의 매개변수는 대상의 키이지 대상의 행이 아닙니다 — 부르는 쪽이 들고 있는 것은 어디서 읽어 온 id이고, 사전이 키로 삼는 것도 그 id들이 만드는 텍스트입니다. 참조가 내는 두 이름 중 컬럼 자신의 이름이 키이고 파생된 이름이 행이므로(참조가 내는 이름 §4·§5), 둘을 바꿔 쓰면 부를 수 없는 조회가 나옵니다.
  • 기본 인덱스가 복합인 테이블은 foreign의 대상이 될 수 없습니다 — 참조는 키 값 하나를 담는 구조이므로(설계) 거부로 시작하고, 요구가 실측되면 그때 형태를 정합니다. 보조 키는 참조와 무관합니다.
  • 와이어는 움직이지 않습니다 — 성분 컬럼이 그대로 실립니다. 움직이는 것은 생성 코드의 조회 표면(키마다 하나, 복합이면 다인자)이고, 모든 언어에 파급되므로 별도 단계입니다(§16의 8). 그때까지 복합 키는 문법 · 모델 · 유일성 검사까지 받고, 조회 생성만 이름과 함께 거부합니다. 단일 key= 지정은 조회 형태가 지금과 같으므로 1단계에 포함됩니다.

3.6 필드 변형 — :variant

한 필드의 값 컬럼을 여러 벌 적고, 빌드가 하나를 고르는 표기입니다. 지역별 가격처럼 컬럼 하나만 갈리고 나머지가 공유되는 데이터가 대상입니다.

  • 같은 필드 이름을 컬럼 여러 개에 그대로 적고, :variant 행이 그것들을 구분합니다. :variant가 빈 컬럼이 기본 변형입니다. 같은 이름 · 같은 변형 이름의 컬럼 둘은 중복 오류입니다(빈 칸 둘도 마찬가지입니다).
  • 선택은 recipe가 합니다"Variants": { "Item.Price": "kr" } 형태의 테이블.필드 → 변형 이름 맵이고, CLI는 --variant Item.Price=kr입니다. 지정이 없으면 기본 변형이고, 기본 변형이 없는 필드(모든 컬럼에 변형 이름이 있는 필드)는 선택이 필수입니다. 없는 변형을 지정하면 있는 목록과 함께 오류입니다.
  • 산출물은 변형을 모릅니다. 선택된 컬럼 하나가 그 필드가 되고, 나머지 컬럼은 그 빌드에 없습니다 — 모델 · 와이어 · 생성 코드 전부 필드 하나이므로 형식 · 생성 코드 무변경입니다. text 수집도 선택된 컬럼만 합니다.
  • 헤더 기재의 정본은 기본 변형 컬럼(없으면 첫 변형 컬럼)입니다. :type · :desc · :target · @N은 거기에 적고, 다른 변형 컬럼에 반복 기재하면 일치를 검사합니다 — §4.3의 그룹 규칙과 같은 형태입니다.
  • 키 컬럼(§3.5의 성분 포함)에는 변형을 둘 수 없습니다. 행을 가리키는 값이 빌드마다 달라지면 참조 · 히스토리 · 배포 판정이 전부 「같은 행」을 말할 수 없게 됩니다.
  • 그룹 멤버(pos.x) · [] · [n] 컬럼의 변형은 1차에서 거부합니다 — 컬럼 집합이 변형마다 복제되는 형태라, 요구가 실측되면 그때 정합니다.

행 세트와의 구분

행 세트(그 문서의 이름은 「행 벌」입니다)와는 둘 다 「여러 벌 중 하나를 고른다」이지만 고르는 단위가 다릅니다. 겹치는 기능이 아니므로 어느 쪽도 다른 쪽을 대신하지 않습니다.

:variant행 세트
여러 벌인 것한 필드의 값 컬럼행의 집합(레코드들)
공유되는 것같은 행의 나머지 필드 전부테이블의 스키마
맞는 요구지역별 가격 · 난이도별 수치 하나지역별 상품 구성 · 환경별 데이터 추가 · 교체

3.7 빈 칸의 뜻 — 자리별 총정리

시트를 작성하는 사람이 가장 자주 묻는 질문이 「여기 비워도 되나」입니다. 빈 칸의 뜻이 자리마다 다르므로 한 표로 정리합니다 — 이 표가 시트 작성 문서에 그대로 들어가야 합니다. 데이터 칸의 정본 규칙은 빈 칸과 없음이고, 이 절은 그 규칙을 이 레이아웃의 자리에 배치한 것입니다.

세 줄 요약.

  1. 빈 칸은 「값 없음」이 아닙니다. 값 없음은 -이고, ? 컬럼에서만 적을 수 있습니다.
  2. 비워도 되는 곳 — 문자열 · bool · 배열의 데이터 칸(각각 "" · false · 빈 배열이 됩니다), 선택 헤더 행의 칸, 정본이 다른 칸에 있는 헤더 칸.
  3. 비우면 안 되는 곳 — 숫자 계열의 데이터 칸(기본 정책), 기본 인덱스, 연장 행의 스칼라 칸, 이름 없는 컬럼의 데이터 칸.

헤더 영역

자리빈 칸의 뜻
선언 셀의 오른쪽(설명)설명 없음. 허용
:field자리가 없는 컬럼. 그 아래 데이터가 있으면 오류(§3.3) — 자유 기재 공간이 필요하면 #를 적습니다
:type 셀 — 보통의 필드 컬럼오류. 타입은 생략할 수 없습니다
:type 셀 — struct 그룹의 2번째 이후 멤버 · [n]의 원소 1 이후 · 기본이 아닌 변형 컬럼비우는 것이 정본입니다(§4.3). 적으면 일치 검사
:desc설명 없음. 허용
:target양쪽(c,s). 허용
:variant기본 변형. 허용
:desc · :target · :variant 행 자체의 생략전부 위의 기본값. 허용
메모 컬럼(#)의 모든 칸자유 공간 — 헤더 행의 칸도 포함합니다

데이터 영역

자리빈 칸의 뜻
마커 열보통의 데이터 행
기본 인덱스 칸오류 — 그 행을 가리킬 것이 없습니다. 예외는 멀티 로우 표 하나이고, 거기서는 연장 행의 신호입니다(§6.1). 복합 키의 성분 일부만 비면 오류
string · bool · T[]값입니다"" · false · 빈 배열. 값 없음이 아닙니다
숫자 · bitset · datetime · timespan · uuid · enum 칸오류(기본). 소스의 OnBlankCell: "empty"가 타입의 빈 값으로 완화하고, 그렇게 읽은 것은 컬럼당 한 번 경고됩니다
참조(foreign) 칸오류. OnBlankCell로도 통과하지 않습니다 — 키를 적거나, 옵셔널 참조면 -를 적습니다
옵셔널(?) 칸빈 칸의 뜻은 위와 똑같습니다. ?가 바꾸는 것은 「-를 적을 수 있다」뿐입니다 — string?의 빈 칸은 없음이 아니라 ""입니다
[n] 원소 칸TrimTrailingArrayElements가 켜져 있으면 값 없는 뒤쪽 원소(-)는 배열 밖입니다. 가운데의 빈 원소는 기본 거부입니다(AllowArrayGaps)
[] 그룹의 범위가 전부 빈 행그 행에 그 그룹의 원소가 없습니다(§6.1 규칙 4)
연장 행의 [] 아닌 칸비어 있어야 합니다. 값이 있으면 그 셀을 가리켜 오류입니다(§6.1 규칙 3)
enum의 label · value, const의 name · type · value오류 — 필수 칸입니다
enum의 alias · desc, const의 desc없음. 허용
완전히 빈 행엔티티의 종료(§3.2)
엔티티 밖(경계 너머)의 셀레이아웃이 읽지 않습니다 — 자유