1import type * as lf from "@distilled.cloud/aws/lakeformation";
2
3/**
4 * A Data Catalog reference (`Resource.Catalog`). Grants catalog-level
5 * permissions such as `CREATE_DATABASE` or `CREATE_LF_TAG`.
6 */
7export interface CatalogSpec {
8 /**
9 * The catalog id (AWS account id).
10 * @default the caller's account
11 */
12 id?: string;
13}
14
15/**
16 * A Glue Data Catalog database reference (`Resource.Database`).
17 */
18export interface DatabaseResourceSpec {
19 /**
20 * The catalog id (AWS account id) the database lives in.
21 * @default the caller's account
22 */
23 catalogId?: string;
24 /**
25 * Name of the Glue database.
26 */
27 name: string;
28}
29
30/**
31 * A Glue Data Catalog table reference (`Resource.Table`). Provide either a
32 * table `name` or `tableWildcard: true` for all tables in the database.
33 */
34export interface TableResourceSpec {
35 /**
36 * The catalog id (AWS account id) the table lives in.
37 * @default the caller's account
38 */
39 catalogId?: string;
40 /**
41 * Name of the Glue database that contains the table.
42 */
43 databaseName: string;
44 /**
45 * Name of the table. Omit when using `tableWildcard`.
46 */
47 name?: string;
48 /**
49 * When true, references every table in the database.
50 * @default false
51 */
52 tableWildcard?: boolean;
53}
54
55/**
56 * A Glue table reference with a column filter (`Resource.TableWithColumns`).
57 */
58export interface TableWithColumnsResourceSpec {
59 /**
60 * The catalog id (AWS account id) the table lives in.
61 * @default the caller's account
62 */
63 catalogId?: string;
64 /**
65 * Name of the Glue database that contains the table.
66 */
67 databaseName: string;
68 /**
69 * Name of the table.
70 */
71 name: string;
72 /**
73 * Include-list of column names. Mutually exclusive with
74 * `excludedColumnNames`.
75 */
76 columnNames?: string[];
77 /**
78 * Exclude-list of column names (a column wildcard excluding these columns).
79 * Mutually exclusive with `columnNames`.
80 */
81 excludedColumnNames?: string[];
82}
83
84/**
85 * A registered S3 data location reference (`Resource.DataLocation`). Used to
86 * grant `DATA_LOCATION_ACCESS`.
87 */
88export interface DataLocationResourceSpec {
89 /**
90 * The catalog id (AWS account id) that registered the location.
91 * @default the caller's account
92 */
93 catalogId?: string;
94 /**
95 * ARN of the registered S3 location (e.g. `arn:aws:s3:::my-bucket`).
96 */
97 resourceArn: string;
98}
99
100/**
101 * An LF-tag key/values reference (`Resource.LFTag`). Used to grant
102 * permissions on the LF-tag itself (`DESCRIBE`, `ASSOCIATE`).
103 */
104export interface LFTagKeyResourceSpec {
105 /**
106 * The catalog id (AWS account id) the LF-tag lives in.
107 * @default the caller's account
108 */
109 catalogId?: string;
110 /**
111 * Key of the LF-tag.
112 */
113 tagKey: string;
114 /**
115 * Values of the LF-tag the reference applies to.
116 */
117 tagValues: string[];
118}
119
120/**
121 * An LF-tag policy expression (`Resource.LFTagPolicy`). Grants permissions on
122 * all databases or tables whose LF-tags match the expression.
123 */
124export interface LFTagPolicyResourceSpec {
125 /**
126 * The catalog id (AWS account id).
127 * @default the caller's account
128 */
129 catalogId?: string;
130 /**
131 * Whether the expression matches `DATABASE` or `TABLE` resources.
132 */
133 resourceType: lf.ResourceType;
134 /**
135 * The LF-tag conditions that resources must match.
136 */
137 expression: { tagKey: string; tagValues: string[] }[];
138}
139
140/**
141 * A Lake Formation resource reference — exactly one variant should be set.
142 * Mirrors the Lake Formation `Resource` union used by `GrantPermissions`,
143 * `AddLFTagsToResource`, etc.
144 */
145export interface LakeFormationResourceSpec {
146 /**
147 * The Data Catalog itself (catalog-level permissions).
148 */
149 catalog?: CatalogSpec;
150 /**
151 * A Glue database.
152 */
153 database?: DatabaseResourceSpec;
154 /**
155 * A Glue table (or all tables via `tableWildcard`).
156 */
157 table?: TableResourceSpec;
158 /**
159 * A Glue table restricted to specific columns.
160 */
161 tableWithColumns?: TableWithColumnsResourceSpec;
162 /**
163 * A registered S3 data location.
164 */
165 dataLocation?: DataLocationResourceSpec;
166 /**
167 * An LF-tag key/values pair.
168 */
169 lfTag?: LFTagKeyResourceSpec;
170 /**
171 * An LF-tag policy expression.
172 */
173 lfTagPolicy?: LFTagPolicyResourceSpec;
174}
175
176/**
177 * Convert a {@link LakeFormationResourceSpec} to the wire `Resource` union
178 * shape expected by the Lake Formation API.
179 */
180export const toWireResource = (
181 spec: LakeFormationResourceSpec,
182): lf.Resource => {
183 const resource: lf.Resource = {};
184 if (spec.catalog !== undefined) {
185 resource.Catalog = { Id: spec.catalog.id };
186 }
187 if (spec.database !== undefined) {
188 resource.Database = {
189 CatalogId: spec.database.catalogId,
190 Name: spec.database.name,
191 };
192 }
193 if (spec.table !== undefined) {
194 resource.Table = {
195 CatalogId: spec.table.catalogId,
196 DatabaseName: spec.table.databaseName,
197 Name: spec.table.name,
198 TableWildcard: spec.table.tableWildcard ? {} : undefined,
199 };
200 }
201 if (spec.tableWithColumns !== undefined) {
202 resource.TableWithColumns = {
203 CatalogId: spec.tableWithColumns.catalogId,
204 DatabaseName: spec.tableWithColumns.databaseName,
205 Name: spec.tableWithColumns.name,
206 ColumnNames: spec.tableWithColumns.columnNames,
207 ColumnWildcard:
208 spec.tableWithColumns.excludedColumnNames !== undefined
209 ? { ExcludedColumnNames: spec.tableWithColumns.excludedColumnNames }
210 : undefined,
211 };
212 }
213 if (spec.dataLocation !== undefined) {
214 resource.DataLocation = {
215 CatalogId: spec.dataLocation.catalogId,
216 ResourceArn: spec.dataLocation.resourceArn,
217 };
218 }
219 if (spec.lfTag !== undefined) {
220 resource.LFTag = {
221 CatalogId: spec.lfTag.catalogId,
222 TagKey: spec.lfTag.tagKey,
223 TagValues: spec.lfTag.tagValues,
224 };
225 }
226 if (spec.lfTagPolicy !== undefined) {
227 resource.LFTagPolicy = {
228 CatalogId: spec.lfTagPolicy.catalogId,
229 ResourceType: spec.lfTagPolicy.resourceType,
230 Expression: spec.lfTagPolicy.expression.map((e) => ({
231 TagKey: e.tagKey,
232 TagValues: e.tagValues,
233 })),
234 };
235 }
236 return resource;
237};