@useairfoil/effect-iceberg 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -0
- package/dist/chunk-Bp6m_JJh.js +13 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +130 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -7
- package/src/catalog.ts +377 -0
- package/src/errors.ts +33 -0
- package/src/index.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# @useairfoil/effect-iceberg
|
|
2
|
+
|
|
3
|
+
Effect wrapper for [`iceberg-js`](https://github.com/supabase/iceberg-js), the Apache Iceberg REST Catalog client.
|
|
4
|
+
|
|
5
|
+
This package provides an Effect service, layers, accessors, and typed errors around `iceberg-js`. It does not replace the `iceberg-js` API or type surface. Import Apache Iceberg domain types directly from `iceberg-js`.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @useairfoil/effect-iceberg iceberg-js effect
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`iceberg-js` and `effect` are peer dependencies so your application owns their versions.
|
|
14
|
+
|
|
15
|
+
## Imports
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { IcebergCatalog, IcebergError } from "@useairfoil/effect-iceberg";
|
|
19
|
+
import type { CreateTableRequest, TableIdentifier } from "iceberg-js";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`@useairfoil/effect-iceberg` exports wrapper modules only:
|
|
23
|
+
|
|
24
|
+
- `IcebergCatalog` contains the service tag, constructors, layers, and accessor functions.
|
|
25
|
+
- `IcebergError` contains the Effect error type and mapper for failures from `iceberg-js`.
|
|
26
|
+
|
|
27
|
+
Use `iceberg-js` directly for catalog options, request/response types, metadata types, table update unions, and helpers.
|
|
28
|
+
|
|
29
|
+
## Layer
|
|
30
|
+
|
|
31
|
+
Create a layer from normal `iceberg-js` catalog options:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { IcebergCatalog } from "@useairfoil/effect-iceberg";
|
|
35
|
+
|
|
36
|
+
const IcebergLive = IcebergCatalog.layer({
|
|
37
|
+
baseUrl: "https://catalog.example.com",
|
|
38
|
+
warehouse: "warehouse",
|
|
39
|
+
auth: { type: "bearer", token: process.env.ICEBERG_TOKEN ?? "" },
|
|
40
|
+
accessDelegation: ["vended-credentials"],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or build a layer from Effect `Config` values:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { Config } from "effect";
|
|
48
|
+
import { IcebergCatalog } from "@useairfoil/effect-iceberg";
|
|
49
|
+
import type { AuthConfig } from "iceberg-js";
|
|
50
|
+
|
|
51
|
+
const IcebergLive = IcebergCatalog.layerConfig({
|
|
52
|
+
baseUrl: Config.string("ICEBERG_REST_URL"),
|
|
53
|
+
warehouse: Config.string("ICEBERG_WAREHOUSE"),
|
|
54
|
+
auth: Config.string("ICEBERG_TOKEN").pipe(
|
|
55
|
+
Config.map((token): AuthConfig => ({ type: "bearer", token })),
|
|
56
|
+
),
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
Use the accessor functions for most application code. They read the `IcebergCatalog` service from the Effect context and delegate to the underlying `iceberg-js` client.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Effect } from "effect";
|
|
66
|
+
import { IcebergCatalog } from "@useairfoil/effect-iceberg";
|
|
67
|
+
import type { TableIdentifier } from "iceberg-js";
|
|
68
|
+
|
|
69
|
+
const IcebergLive = IcebergCatalog.layer({
|
|
70
|
+
baseUrl: "https://catalog.example.com",
|
|
71
|
+
warehouse: "warehouse",
|
|
72
|
+
auth: { type: "bearer", token: process.env.ICEBERG_TOKEN ?? "" },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const program = Effect.gen(function* () {
|
|
76
|
+
const id: TableIdentifier = { namespace: ["analytics"], name: "events" };
|
|
77
|
+
return yield* IcebergCatalog.loadTable(id);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await Effect.runPromise(program.pipe(Effect.provide(IcebergLive)));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Catalog Operations
|
|
84
|
+
|
|
85
|
+
The `IcebergCatalog` module mirrors the public `iceberg-js` `IcebergRestCatalog` methods as Effect accessors:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const program = Effect.gen(function* () {
|
|
89
|
+
const namespaces = yield* IcebergCatalog.listNamespaces();
|
|
90
|
+
|
|
91
|
+
const tables = yield* IcebergCatalog.listTables({ namespace: ["analytics"] });
|
|
92
|
+
|
|
93
|
+
const table = yield* IcebergCatalog.loadTable({
|
|
94
|
+
namespace: ["analytics"],
|
|
95
|
+
name: "events",
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return { namespaces, tables, table };
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Create tables with request types from `iceberg-js`:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import type { CreateTableRequest } from "iceberg-js";
|
|
106
|
+
|
|
107
|
+
const request: CreateTableRequest = {
|
|
108
|
+
name: "events",
|
|
109
|
+
schema: {
|
|
110
|
+
type: "struct",
|
|
111
|
+
"schema-id": 0,
|
|
112
|
+
fields: [{ id: 1, name: "id", type: "string", required: true }],
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const program = Effect.gen(function* () {
|
|
117
|
+
return yield* IcebergCatalog.createTable({ namespace: ["analytics"] }, request);
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use `loadTableResult`, `createTableResult`, or `registerTableResult` when you need the full spec-aligned result, including server config, storage credentials, metadata location, and ETag:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const program = Effect.gen(function* () {
|
|
125
|
+
const result = yield* IcebergCatalog.loadTableResult({
|
|
126
|
+
namespace: ["analytics"],
|
|
127
|
+
name: "events",
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (result) {
|
|
131
|
+
console.log(result.etag);
|
|
132
|
+
console.log(result["storage-credentials"]);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return result;
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Conditional table loads return `null` when the server responds with `304 Not Modified`:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const program = Effect.gen(function* () {
|
|
143
|
+
return yield* IcebergCatalog.loadTable(
|
|
144
|
+
{ namespace: ["analytics"], name: "events" },
|
|
145
|
+
{ ifNoneMatch: "abc123" },
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Service Access
|
|
151
|
+
|
|
152
|
+
For advanced use cases, access the service directly. This is useful when you want the underlying `iceberg-js` client or want to call several methods from one service value.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const program = Effect.gen(function* () {
|
|
156
|
+
const catalog = yield* IcebergCatalog.IcebergCatalog;
|
|
157
|
+
const client = catalog.getCatalogClient();
|
|
158
|
+
|
|
159
|
+
yield* catalog.loadConfig();
|
|
160
|
+
return client;
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Errors
|
|
165
|
+
|
|
166
|
+
Failures thrown by `iceberg-js` are mapped to `IcebergError.IcebergError`. The wrapper preserves the important Iceberg fields: HTTP `status`, Iceberg exception `type` / `code`, `details`, and `isCommitStateUnknown`.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { Effect } from "effect";
|
|
170
|
+
import { IcebergError } from "@useairfoil/effect-iceberg";
|
|
171
|
+
|
|
172
|
+
const handled = program.pipe(
|
|
173
|
+
Effect.catchTag("IcebergError", (error: IcebergError.IcebergError) =>
|
|
174
|
+
Effect.succeed({ status: error.status, type: error.icebergType }),
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
You can also inspect commit-state ambiguity from the Iceberg REST spec:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const safeCommit = IcebergCatalog.commitTable(id, request).pipe(
|
|
183
|
+
Effect.catchTag("IcebergError", (error) => {
|
|
184
|
+
if (error.isCommitStateUnknown) {
|
|
185
|
+
return Effect.fail(error);
|
|
186
|
+
}
|
|
187
|
+
return Effect.fail(error);
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Direct `iceberg-js` Types
|
|
193
|
+
|
|
194
|
+
Keep domain types close to `iceberg-js`:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import type {
|
|
198
|
+
CommitTableRequest,
|
|
199
|
+
LoadTableResultWithEtag,
|
|
200
|
+
NamespaceIdentifier,
|
|
201
|
+
TableIdentifier,
|
|
202
|
+
TableMetadata,
|
|
203
|
+
TableUpdate,
|
|
204
|
+
} from "iceberg-js";
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This keeps your application aligned with the exact `iceberg-js` version you install, while `@useairfoil/effect-iceberg` provides the Effect integration layer.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (all) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
return target;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __export as t };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Config, Context, Effect, Layer } from "effect";
|
|
2
|
+
import { CatalogConfig, CommitTableRequest, CommitTableResponse, CreateNamespaceResponse, CreateTableRequest, DropTableRequest, IcebergRestCatalog, IcebergRestCatalogOptions, ListNamespacesOptions, ListNamespacesResult, ListTablesOptions, ListTablesResult, LoadTableOptions, LoadTableResultWithEtag, NamespaceIdentifier, NamespaceMetadata, RegisterTableRequest, RenameTableRequest, TableIdentifier, TableMetadata, UpdateNamespacePropertiesRequest, UpdateNamespacePropertiesResponse, UpdateTableRequest } from "iceberg-js";
|
|
3
|
+
import * as effect_Types0 from "effect/Types";
|
|
4
|
+
import * as effect_Cause0 from "effect/Cause";
|
|
5
|
+
|
|
6
|
+
//#region src/errors.d.ts
|
|
7
|
+
declare namespace errors_d_exports {
|
|
8
|
+
export { IcebergError$1 as IcebergError, mapIcebergError };
|
|
9
|
+
}
|
|
10
|
+
declare const IcebergError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => effect_Cause0.YieldableError & {
|
|
11
|
+
readonly _tag: "IcebergError";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
/** Error type used by the Effect wrapper around `iceberg-js`. */
|
|
14
|
+
declare class IcebergError$1 extends IcebergError_base<{
|
|
15
|
+
readonly message: string;
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
readonly icebergType?: string;
|
|
18
|
+
readonly icebergCode?: number;
|
|
19
|
+
readonly details?: unknown;
|
|
20
|
+
readonly isCommitStateUnknown?: boolean;
|
|
21
|
+
readonly cause?: unknown;
|
|
22
|
+
}> {}
|
|
23
|
+
/** Maps errors thrown by `iceberg-js` into `IcebergError`. */
|
|
24
|
+
declare const mapIcebergError: (error: unknown) => IcebergError$1;
|
|
25
|
+
declare namespace catalog_d_exports {
|
|
26
|
+
export { IcebergCatalog, Service, commitTable, createNamespace, createNamespaceIfNotExists, createTable, createTableIfNotExists, createTableResult, dropNamespace, dropTable, getCatalogClient, layer, layerConfig, listNamespaces, listTables, loadConfig, loadNamespaceMetadata, loadTable, loadTableResult, make, namespaceExists, registerTable, registerTableResult, renameTable, tableExists, updateNamespaceProperties, updateTable };
|
|
27
|
+
}
|
|
28
|
+
interface Service {
|
|
29
|
+
/**
|
|
30
|
+
* Returns the underlying `iceberg-js` catalog client.
|
|
31
|
+
*
|
|
32
|
+
* Use this for advanced cases that need direct access to the Promise-based API.
|
|
33
|
+
*/
|
|
34
|
+
readonly getCatalogClient: () => IcebergRestCatalog;
|
|
35
|
+
/**
|
|
36
|
+
* Fetch and cache the server's catalog configuration. Calling this is optional;
|
|
37
|
+
* catalog operations trigger it lazily when a warehouse is configured.
|
|
38
|
+
*/
|
|
39
|
+
readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError$1>;
|
|
40
|
+
/** Lists all namespaces in the catalog. */
|
|
41
|
+
readonly listNamespaces: (options?: ListNamespacesOptions) => Effect.Effect<ListNamespacesResult, IcebergError$1>;
|
|
42
|
+
/** Creates a new namespace in the catalog. */
|
|
43
|
+
readonly createNamespace: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse, IcebergError$1>;
|
|
44
|
+
/**
|
|
45
|
+
* Drops a namespace from the catalog.
|
|
46
|
+
*
|
|
47
|
+
* The namespace must be empty before it can be dropped.
|
|
48
|
+
*/
|
|
49
|
+
readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError$1>;
|
|
50
|
+
/** Loads metadata for a namespace. */
|
|
51
|
+
readonly loadNamespaceMetadata: (id: NamespaceIdentifier) => Effect.Effect<NamespaceMetadata, IcebergError$1>;
|
|
52
|
+
/** Sets or removes properties on a namespace. */
|
|
53
|
+
readonly updateNamespaceProperties: (id: NamespaceIdentifier, request: UpdateNamespacePropertiesRequest) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError$1>;
|
|
54
|
+
/** Lists tables in a namespace. */
|
|
55
|
+
readonly listTables: (namespace: NamespaceIdentifier, options?: ListTablesOptions) => Effect.Effect<ListTablesResult, IcebergError$1>;
|
|
56
|
+
/** Creates a new table in the catalog. */
|
|
57
|
+
readonly createTable: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a table and returns the full spec-aligned `LoadTableResult`, including
|
|
60
|
+
* server config, storage credentials, and the response ETag.
|
|
61
|
+
*/
|
|
62
|
+
readonly createTableResult: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1>;
|
|
63
|
+
/** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */
|
|
64
|
+
readonly updateTable: (id: TableIdentifier, request: UpdateTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1>;
|
|
65
|
+
/** Spec-aligned alias for `updateTable`. */
|
|
66
|
+
readonly commitTable: (id: TableIdentifier, request: CommitTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1>;
|
|
67
|
+
/** Drops a table from the catalog. */
|
|
68
|
+
readonly dropTable: (id: TableIdentifier, options?: DropTableRequest) => Effect.Effect<void, IcebergError$1>;
|
|
69
|
+
/**
|
|
70
|
+
* Loads metadata for a table.
|
|
71
|
+
*
|
|
72
|
+
* Pass `ifNoneMatch` in options to perform a conditional GET. If the server
|
|
73
|
+
* returns 304 Not Modified, the result is `null`.
|
|
74
|
+
*/
|
|
75
|
+
readonly loadTable: {
|
|
76
|
+
(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError$1>;
|
|
77
|
+
(id: TableIdentifier, options: LoadTableOptions): Effect.Effect<TableMetadata | null, IcebergError$1>;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Loads the full spec-aligned `LoadTableResult`, including server config,
|
|
81
|
+
* storage credentials, and the response ETag. Returns `null` on 304.
|
|
82
|
+
*/
|
|
83
|
+
readonly loadTableResult: (id: TableIdentifier, options?: LoadTableOptions) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError$1>;
|
|
84
|
+
/** Checks if a namespace exists in the catalog. */
|
|
85
|
+
readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError$1>;
|
|
86
|
+
/** Checks if a table exists in the catalog. */
|
|
87
|
+
readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError$1>;
|
|
88
|
+
/** Creates a namespace if it does not exist. */
|
|
89
|
+
readonly createNamespaceIfNotExists: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse | void, IcebergError$1>;
|
|
90
|
+
/** Creates a table if it does not exist. */
|
|
91
|
+
readonly createTableIfNotExists: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
|
|
92
|
+
/** Registers an existing metadata file as a table in the given namespace. */
|
|
93
|
+
readonly registerTable: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
|
|
94
|
+
/** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */
|
|
95
|
+
readonly registerTableResult: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1>;
|
|
96
|
+
/** Renames a table. Servers may or may not support cross-namespace renames. */
|
|
97
|
+
readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError$1>;
|
|
98
|
+
}
|
|
99
|
+
declare const IcebergCatalog_base: Context.ServiceClass<IcebergCatalog, "@useairfoil/effect-iceberg/IcebergCatalog", Service>;
|
|
100
|
+
/** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
|
|
101
|
+
declare class IcebergCatalog extends IcebergCatalog_base {}
|
|
102
|
+
/** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
|
|
103
|
+
declare const make: (options: IcebergRestCatalogOptions) => Service;
|
|
104
|
+
declare const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog>;
|
|
105
|
+
declare const loadConfig: Effect.Effect<CatalogConfig, IcebergError$1, IcebergCatalog>;
|
|
106
|
+
declare const listNamespaces: (options?: ListNamespacesOptions) => Effect.Effect<ListNamespacesResult, IcebergError$1, IcebergCatalog>;
|
|
107
|
+
declare const createNamespace: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse, IcebergError$1, IcebergCatalog>;
|
|
108
|
+
declare const dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
|
|
109
|
+
declare const loadNamespaceMetadata: (id: NamespaceIdentifier) => Effect.Effect<NamespaceMetadata, IcebergError$1, IcebergCatalog>;
|
|
110
|
+
declare const updateNamespaceProperties: (id: NamespaceIdentifier, request: UpdateNamespacePropertiesRequest) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError$1, IcebergCatalog>;
|
|
111
|
+
declare const listTables: (namespace: NamespaceIdentifier, options?: ListTablesOptions) => Effect.Effect<ListTablesResult, IcebergError$1, IcebergCatalog>;
|
|
112
|
+
declare const createTable: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
|
|
113
|
+
declare const createTableResult: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1, IcebergCatalog>;
|
|
114
|
+
declare const updateTable: (id: TableIdentifier, request: UpdateTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1, IcebergCatalog>;
|
|
115
|
+
declare const commitTable: (id: TableIdentifier, request: CommitTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1, IcebergCatalog>;
|
|
116
|
+
declare const dropTable: (id: TableIdentifier, options?: DropTableRequest) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
|
|
117
|
+
declare function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
|
|
118
|
+
declare function loadTable(id: TableIdentifier, options: LoadTableOptions): Effect.Effect<TableMetadata | null, IcebergError$1, IcebergCatalog>;
|
|
119
|
+
declare const loadTableResult: (id: TableIdentifier, options?: LoadTableOptions) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError$1, IcebergCatalog>;
|
|
120
|
+
declare const namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError$1, IcebergCatalog>;
|
|
121
|
+
declare const tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError$1, IcebergCatalog>;
|
|
122
|
+
declare const createNamespaceIfNotExists: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse | void, IcebergError$1, IcebergCatalog>;
|
|
123
|
+
declare const createTableIfNotExists: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
|
|
124
|
+
declare const registerTable: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
|
|
125
|
+
declare const registerTableResult: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1, IcebergCatalog>;
|
|
126
|
+
declare const renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
|
|
127
|
+
/** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
|
|
128
|
+
declare const layer: (options: IcebergRestCatalogOptions) => Layer.Layer<IcebergCatalog>;
|
|
129
|
+
/** Creates an `IcebergCatalog` layer from Effect `Config` values. */
|
|
130
|
+
declare const layerConfig: (config: Config.Wrap<IcebergRestCatalogOptions>) => Layer.Layer<IcebergCatalog, Config.ConfigError>;
|
|
131
|
+
//#endregion
|
|
132
|
+
export { catalog_d_exports as IcebergCatalog, errors_d_exports as IcebergError };
|
|
133
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { t as __export } from "./chunk-Bp6m_JJh.js";
|
|
2
|
+
import { Config, Context, Data, Effect, Layer } from "effect";
|
|
3
|
+
import { IcebergError, IcebergRestCatalog } from "iceberg-js";
|
|
4
|
+
|
|
5
|
+
//#region src/errors.ts
|
|
6
|
+
var errors_exports = /* @__PURE__ */ __export({
|
|
7
|
+
IcebergError: () => IcebergError$1,
|
|
8
|
+
mapIcebergError: () => mapIcebergError
|
|
9
|
+
});
|
|
10
|
+
/** Error type used by the Effect wrapper around `iceberg-js`. */
|
|
11
|
+
var IcebergError$1 = class extends Data.TaggedError("IcebergError") {};
|
|
12
|
+
/** Maps errors thrown by `iceberg-js` into `IcebergError`. */
|
|
13
|
+
const mapIcebergError = (error) => {
|
|
14
|
+
if (error instanceof IcebergError) return new IcebergError$1({
|
|
15
|
+
message: error.message,
|
|
16
|
+
status: error.status,
|
|
17
|
+
icebergType: error.icebergType,
|
|
18
|
+
icebergCode: error.icebergCode,
|
|
19
|
+
details: error.details,
|
|
20
|
+
isCommitStateUnknown: error.isCommitStateUnknown,
|
|
21
|
+
cause: error
|
|
22
|
+
});
|
|
23
|
+
return new IcebergError$1({
|
|
24
|
+
message: error instanceof Error ? error.message : String(error),
|
|
25
|
+
cause: error
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/catalog.ts
|
|
31
|
+
var catalog_exports = /* @__PURE__ */ __export({
|
|
32
|
+
IcebergCatalog: () => IcebergCatalog,
|
|
33
|
+
commitTable: () => commitTable,
|
|
34
|
+
createNamespace: () => createNamespace,
|
|
35
|
+
createNamespaceIfNotExists: () => createNamespaceIfNotExists,
|
|
36
|
+
createTable: () => createTable,
|
|
37
|
+
createTableIfNotExists: () => createTableIfNotExists,
|
|
38
|
+
createTableResult: () => createTableResult,
|
|
39
|
+
dropNamespace: () => dropNamespace,
|
|
40
|
+
dropTable: () => dropTable,
|
|
41
|
+
getCatalogClient: () => getCatalogClient,
|
|
42
|
+
layer: () => layer,
|
|
43
|
+
layerConfig: () => layerConfig,
|
|
44
|
+
listNamespaces: () => listNamespaces,
|
|
45
|
+
listTables: () => listTables,
|
|
46
|
+
loadConfig: () => loadConfig,
|
|
47
|
+
loadNamespaceMetadata: () => loadNamespaceMetadata,
|
|
48
|
+
loadTable: () => loadTable,
|
|
49
|
+
loadTableResult: () => loadTableResult,
|
|
50
|
+
make: () => make,
|
|
51
|
+
namespaceExists: () => namespaceExists,
|
|
52
|
+
registerTable: () => registerTable,
|
|
53
|
+
registerTableResult: () => registerTableResult,
|
|
54
|
+
renameTable: () => renameTable,
|
|
55
|
+
tableExists: () => tableExists,
|
|
56
|
+
updateNamespaceProperties: () => updateNamespaceProperties,
|
|
57
|
+
updateTable: () => updateTable
|
|
58
|
+
});
|
|
59
|
+
/** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
|
|
60
|
+
var IcebergCatalog = class extends Context.Service()("@useairfoil/effect-iceberg/IcebergCatalog") {};
|
|
61
|
+
const tryCatalog = (evaluate) => Effect.tryPromise({
|
|
62
|
+
try: evaluate,
|
|
63
|
+
catch: mapIcebergError
|
|
64
|
+
});
|
|
65
|
+
/** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
|
|
66
|
+
const make = (options) => {
|
|
67
|
+
const catalog = new IcebergRestCatalog(options);
|
|
68
|
+
function loadTable$1(id, loadOptions) {
|
|
69
|
+
return tryCatalog(() => loadOptions === void 0 ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions));
|
|
70
|
+
}
|
|
71
|
+
return IcebergCatalog.of({
|
|
72
|
+
getCatalogClient: () => catalog,
|
|
73
|
+
loadConfig: () => tryCatalog(() => catalog.loadConfig()),
|
|
74
|
+
listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),
|
|
75
|
+
createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),
|
|
76
|
+
dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),
|
|
77
|
+
loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),
|
|
78
|
+
updateNamespaceProperties: (id, request) => tryCatalog(() => catalog.updateNamespaceProperties(id, request)),
|
|
79
|
+
listTables: (namespace, listOptions) => tryCatalog(() => catalog.listTables(namespace, listOptions)),
|
|
80
|
+
createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),
|
|
81
|
+
createTableResult: (namespace, request) => tryCatalog(() => catalog.createTableResult(namespace, request)),
|
|
82
|
+
updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),
|
|
83
|
+
commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),
|
|
84
|
+
dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),
|
|
85
|
+
loadTable: loadTable$1,
|
|
86
|
+
loadTableResult: (id, loadOptions) => tryCatalog(() => catalog.loadTableResult(id, loadOptions)),
|
|
87
|
+
namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),
|
|
88
|
+
tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),
|
|
89
|
+
createNamespaceIfNotExists: (id, metadata) => tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),
|
|
90
|
+
createTableIfNotExists: (namespace, request) => tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),
|
|
91
|
+
registerTable: (namespace, request) => tryCatalog(() => catalog.registerTable(namespace, request)),
|
|
92
|
+
registerTableResult: (namespace, request) => tryCatalog(() => catalog.registerTableResult(namespace, request)),
|
|
93
|
+
renameTable: (request) => tryCatalog(() => catalog.renameTable(request))
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const service = Effect.service(IcebergCatalog);
|
|
97
|
+
const getCatalogClient = Effect.map(service, (catalog) => catalog.getCatalogClient());
|
|
98
|
+
const loadConfig = Effect.flatMap(service, (catalog) => catalog.loadConfig());
|
|
99
|
+
const listNamespaces = (options) => Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));
|
|
100
|
+
const createNamespace = (id, metadata) => Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));
|
|
101
|
+
const dropNamespace = (id) => Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));
|
|
102
|
+
const loadNamespaceMetadata = (id) => Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));
|
|
103
|
+
const updateNamespaceProperties = (id, request) => Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));
|
|
104
|
+
const listTables = (namespace, options) => Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));
|
|
105
|
+
const createTable = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));
|
|
106
|
+
const createTableResult = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));
|
|
107
|
+
const updateTable = (id, request) => Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));
|
|
108
|
+
const commitTable = (id, request) => Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));
|
|
109
|
+
const dropTable = (id, options) => Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));
|
|
110
|
+
function loadTable(id, options) {
|
|
111
|
+
return Effect.flatMap(service, (catalog) => options === void 0 ? catalog.loadTable(id) : catalog.loadTable(id, options));
|
|
112
|
+
}
|
|
113
|
+
const loadTableResult = (id, options) => Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));
|
|
114
|
+
const namespaceExists = (id) => Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));
|
|
115
|
+
const tableExists = (id) => Effect.flatMap(service, (catalog) => catalog.tableExists(id));
|
|
116
|
+
const createNamespaceIfNotExists = (id, metadata) => Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));
|
|
117
|
+
const createTableIfNotExists = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));
|
|
118
|
+
const registerTable = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));
|
|
119
|
+
const registerTableResult = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));
|
|
120
|
+
const renameTable = (request) => Effect.flatMap(service, (catalog) => catalog.renameTable(request));
|
|
121
|
+
/** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
|
|
122
|
+
const layer = (options) => Layer.succeed(IcebergCatalog)(make(options));
|
|
123
|
+
/** Creates an `IcebergCatalog` layer from Effect `Config` values. */
|
|
124
|
+
const layerConfig = (config) => Layer.effect(IcebergCatalog, Effect.gen(function* () {
|
|
125
|
+
return make(yield* Config.unwrap(config));
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
export { catalog_exports as IcebergCatalog, errors_exports as IcebergError };
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["IcebergError","IcebergJsError","loadTable","getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog>","loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog>"],"sources":["../src/errors.ts","../src/catalog.ts"],"sourcesContent":["import { Data } from \"effect\";\nimport { IcebergError as IcebergJsError } from \"iceberg-js\";\n\n/** Error type used by the Effect wrapper around `iceberg-js`. */\nexport class IcebergError extends Data.TaggedError(\"IcebergError\")<{\n readonly message: string;\n readonly status?: number;\n readonly icebergType?: string;\n readonly icebergCode?: number;\n readonly details?: unknown;\n readonly isCommitStateUnknown?: boolean;\n readonly cause?: unknown;\n}> {}\n\n/** Maps errors thrown by `iceberg-js` into `IcebergError`. */\nexport const mapIcebergError = (error: unknown): IcebergError => {\n if (error instanceof IcebergJsError) {\n return new IcebergError({\n message: error.message,\n status: error.status,\n icebergType: error.icebergType,\n icebergCode: error.icebergCode,\n details: error.details,\n isCommitStateUnknown: error.isCommitStateUnknown,\n cause: error,\n });\n }\n\n return new IcebergError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n};\n","import type {\n CatalogConfig,\n CommitTableRequest,\n CommitTableResponse,\n CreateNamespaceResponse,\n CreateTableRequest,\n DropTableRequest,\n IcebergRestCatalogOptions,\n ListNamespacesOptions,\n ListNamespacesResult,\n ListTablesOptions,\n ListTablesResult,\n LoadTableOptions,\n LoadTableResultWithEtag,\n NamespaceIdentifier,\n NamespaceMetadata,\n RegisterTableRequest,\n RenameTableRequest,\n TableIdentifier,\n TableMetadata,\n UpdateNamespacePropertiesRequest,\n UpdateNamespacePropertiesResponse,\n UpdateTableRequest,\n} from \"iceberg-js\";\n\nimport { Config, Context, Effect, Layer } from \"effect\";\nimport { IcebergRestCatalog } from \"iceberg-js\";\n\nimport type { IcebergError } from \"./errors\";\n\nimport { mapIcebergError } from \"./errors\";\n\nexport interface Service {\n /**\n * Returns the underlying `iceberg-js` catalog client.\n *\n * Use this for advanced cases that need direct access to the Promise-based API.\n */\n readonly getCatalogClient: () => IcebergRestCatalog;\n\n /**\n * Fetch and cache the server's catalog configuration. Calling this is optional;\n * catalog operations trigger it lazily when a warehouse is configured.\n */\n readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError>;\n\n /** Lists all namespaces in the catalog. */\n readonly listNamespaces: (\n options?: ListNamespacesOptions,\n ) => Effect.Effect<ListNamespacesResult, IcebergError>;\n\n /** Creates a new namespace in the catalog. */\n readonly createNamespace: (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n ) => Effect.Effect<CreateNamespaceResponse, IcebergError>;\n\n /**\n * Drops a namespace from the catalog.\n *\n * The namespace must be empty before it can be dropped.\n */\n readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError>;\n\n /** Loads metadata for a namespace. */\n readonly loadNamespaceMetadata: (\n id: NamespaceIdentifier,\n ) => Effect.Effect<NamespaceMetadata, IcebergError>;\n\n /** Sets or removes properties on a namespace. */\n readonly updateNamespaceProperties: (\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest,\n ) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError>;\n\n /** Lists tables in a namespace. */\n readonly listTables: (\n namespace: NamespaceIdentifier,\n options?: ListTablesOptions,\n ) => Effect.Effect<ListTablesResult, IcebergError>;\n\n /** Creates a new table in the catalog. */\n readonly createTable: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /**\n * Creates a table and returns the full spec-aligned `LoadTableResult`, including\n * server config, storage credentials, and the response ETag.\n */\n readonly createTableResult: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;\n\n /** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */\n readonly updateTable: (\n id: TableIdentifier,\n request: UpdateTableRequest,\n ) => Effect.Effect<CommitTableResponse, IcebergError>;\n\n /** Spec-aligned alias for `updateTable`. */\n readonly commitTable: (\n id: TableIdentifier,\n request: CommitTableRequest,\n ) => Effect.Effect<CommitTableResponse, IcebergError>;\n\n /** Drops a table from the catalog. */\n readonly dropTable: (\n id: TableIdentifier,\n options?: DropTableRequest,\n ) => Effect.Effect<void, IcebergError>;\n\n /**\n * Loads metadata for a table.\n *\n * Pass `ifNoneMatch` in options to perform a conditional GET. If the server\n * returns 304 Not Modified, the result is `null`.\n */\n readonly loadTable: {\n (id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;\n (\n id: TableIdentifier,\n options: LoadTableOptions,\n ): Effect.Effect<TableMetadata | null, IcebergError>;\n };\n\n /**\n * Loads the full spec-aligned `LoadTableResult`, including server config,\n * storage credentials, and the response ETag. Returns `null` on 304.\n */\n readonly loadTableResult: (\n id: TableIdentifier,\n options?: LoadTableOptions,\n ) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError>;\n\n /** Checks if a namespace exists in the catalog. */\n readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError>;\n\n /** Checks if a table exists in the catalog. */\n readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError>;\n\n /** Creates a namespace if it does not exist. */\n readonly createNamespaceIfNotExists: (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n ) => Effect.Effect<CreateNamespaceResponse | void, IcebergError>;\n\n /** Creates a table if it does not exist. */\n readonly createTableIfNotExists: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /** Registers an existing metadata file as a table in the given namespace. */\n readonly registerTable: (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */\n readonly registerTableResult: (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;\n\n /** Renames a table. Servers may or may not support cross-namespace renames. */\n readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError>;\n}\n\n/** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */\nexport class IcebergCatalog extends Context.Service<IcebergCatalog, Service>()(\n \"@useairfoil/effect-iceberg/IcebergCatalog\",\n) {}\n\nconst tryCatalog = <A>(evaluate: () => Promise<A>): Effect.Effect<A, IcebergError> =>\n Effect.tryPromise({\n try: evaluate,\n catch: mapIcebergError,\n });\n\n/** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */\nexport const make = (options: IcebergRestCatalogOptions): Service => {\n const catalog = new IcebergRestCatalog(options);\n\n function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;\n function loadTable(\n id: TableIdentifier,\n loadOptions: LoadTableOptions,\n ): Effect.Effect<TableMetadata | null, IcebergError>;\n function loadTable(id: TableIdentifier, loadOptions?: LoadTableOptions) {\n return tryCatalog(() =>\n loadOptions === undefined ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions),\n );\n }\n\n return IcebergCatalog.of({\n getCatalogClient: () => catalog,\n loadConfig: () => tryCatalog(() => catalog.loadConfig()),\n\n listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),\n createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),\n dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),\n loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),\n updateNamespaceProperties: (id, request) =>\n tryCatalog(() => catalog.updateNamespaceProperties(id, request)),\n\n listTables: (namespace, listOptions) =>\n tryCatalog(() => catalog.listTables(namespace, listOptions)),\n createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),\n createTableResult: (namespace, request) =>\n tryCatalog(() => catalog.createTableResult(namespace, request)),\n updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),\n commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),\n dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),\n loadTable,\n loadTableResult: (id, loadOptions) =>\n tryCatalog(() => catalog.loadTableResult(id, loadOptions)),\n namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),\n tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),\n createNamespaceIfNotExists: (id, metadata) =>\n tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),\n createTableIfNotExists: (namespace, request) =>\n tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),\n registerTable: (namespace, request) =>\n tryCatalog(() => catalog.registerTable(namespace, request)),\n registerTableResult: (namespace, request) =>\n tryCatalog(() => catalog.registerTableResult(namespace, request)),\n renameTable: (request) => tryCatalog(() => catalog.renameTable(request)),\n });\n};\n\nconst service = Effect.service(IcebergCatalog);\n\nexport const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog> =\n Effect.map(service, (catalog) => catalog.getCatalogClient());\n\nexport const loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog> =\n Effect.flatMap(service, (catalog) => catalog.loadConfig());\n\nexport const listNamespaces = (\n options?: ListNamespacesOptions,\n): Effect.Effect<ListNamespacesResult, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));\n\nexport const createNamespace = (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n): Effect.Effect<CreateNamespaceResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));\n\nexport const dropNamespace = (\n id: NamespaceIdentifier,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));\n\nexport const loadNamespaceMetadata = (\n id: NamespaceIdentifier,\n): Effect.Effect<NamespaceMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));\n\nexport const updateNamespaceProperties = (\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest,\n): Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));\n\nexport const listTables = (\n namespace: NamespaceIdentifier,\n options?: ListTablesOptions,\n): Effect.Effect<ListTablesResult, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));\n\nexport const createTable = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));\n\nexport const createTableResult = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));\n\nexport const updateTable = (\n id: TableIdentifier,\n request: UpdateTableRequest,\n): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));\n\nexport const commitTable = (\n id: TableIdentifier,\n request: CommitTableRequest,\n): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));\n\nexport const dropTable = (\n id: TableIdentifier,\n options?: DropTableRequest,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));\n\nexport function loadTable(\n id: TableIdentifier,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog>;\nexport function loadTable(\n id: TableIdentifier,\n options: LoadTableOptions,\n): Effect.Effect<TableMetadata | null, IcebergError, IcebergCatalog>;\nexport function loadTable(id: TableIdentifier, options?: LoadTableOptions) {\n return Effect.flatMap(service, (catalog) =>\n options === undefined ? catalog.loadTable(id) : catalog.loadTable(id, options),\n );\n}\n\nexport const loadTableResult = (\n id: TableIdentifier,\n options?: LoadTableOptions,\n): Effect.Effect<LoadTableResultWithEtag | null, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));\n\nexport const namespaceExists = (\n id: NamespaceIdentifier,\n): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));\n\nexport const tableExists = (\n id: TableIdentifier,\n): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.tableExists(id));\n\nexport const createNamespaceIfNotExists = (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n): Effect.Effect<CreateNamespaceResponse | void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));\n\nexport const createTableIfNotExists = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));\n\nexport const registerTable = (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));\n\nexport const registerTableResult = (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));\n\nexport const renameTable = (\n request: RenameTableRequest,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.renameTable(request));\n\n/** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */\nexport const layer = (options: IcebergRestCatalogOptions): Layer.Layer<IcebergCatalog> =>\n Layer.succeed(IcebergCatalog)(make(options));\n\n/** Creates an `IcebergCatalog` layer from Effect `Config` values. */\nexport const layerConfig = (\n config: Config.Wrap<IcebergRestCatalogOptions>,\n): Layer.Layer<IcebergCatalog, Config.ConfigError> =>\n Layer.effect(\n IcebergCatalog,\n Effect.gen(function* () {\n const options = yield* Config.unwrap(config);\n return make(options);\n }),\n );\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useairfoil/effect-iceberg",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"effect",
|
|
6
|
+
"iceberg"
|
|
7
|
+
],
|
|
8
|
+
"repository": "useairfoil/typescript-sdk",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
6
24
|
"scripts": {
|
|
25
|
+
"build": "tsdown",
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"test:ci": "vitest run",
|
|
28
|
+
"typecheck": "tsc --noEmit"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@effect/vitest": "^4.0.0-rc.108",
|
|
32
|
+
"@types/node": "^24.2.0",
|
|
33
|
+
"effect": "^4.0.0-rc.108",
|
|
34
|
+
"iceberg-js": "^1.0.0",
|
|
35
|
+
"tsdown": "^0.15.6",
|
|
36
|
+
"vitest": "^4.1.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"effect": "^4.0.0-rc.108",
|
|
40
|
+
"iceberg-js": "^1.0.0"
|
|
7
41
|
},
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"effect": {
|
|
44
|
+
"optional": false
|
|
45
|
+
},
|
|
46
|
+
"iceberg-js": {
|
|
47
|
+
"optional": false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
12
50
|
}
|
package/src/catalog.ts
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CatalogConfig,
|
|
3
|
+
CommitTableRequest,
|
|
4
|
+
CommitTableResponse,
|
|
5
|
+
CreateNamespaceResponse,
|
|
6
|
+
CreateTableRequest,
|
|
7
|
+
DropTableRequest,
|
|
8
|
+
IcebergRestCatalogOptions,
|
|
9
|
+
ListNamespacesOptions,
|
|
10
|
+
ListNamespacesResult,
|
|
11
|
+
ListTablesOptions,
|
|
12
|
+
ListTablesResult,
|
|
13
|
+
LoadTableOptions,
|
|
14
|
+
LoadTableResultWithEtag,
|
|
15
|
+
NamespaceIdentifier,
|
|
16
|
+
NamespaceMetadata,
|
|
17
|
+
RegisterTableRequest,
|
|
18
|
+
RenameTableRequest,
|
|
19
|
+
TableIdentifier,
|
|
20
|
+
TableMetadata,
|
|
21
|
+
UpdateNamespacePropertiesRequest,
|
|
22
|
+
UpdateNamespacePropertiesResponse,
|
|
23
|
+
UpdateTableRequest,
|
|
24
|
+
} from "iceberg-js";
|
|
25
|
+
|
|
26
|
+
import { Config, Context, Effect, Layer } from "effect";
|
|
27
|
+
import { IcebergRestCatalog } from "iceberg-js";
|
|
28
|
+
|
|
29
|
+
import type { IcebergError } from "./errors";
|
|
30
|
+
|
|
31
|
+
import { mapIcebergError } from "./errors";
|
|
32
|
+
|
|
33
|
+
export interface Service {
|
|
34
|
+
/**
|
|
35
|
+
* Returns the underlying `iceberg-js` catalog client.
|
|
36
|
+
*
|
|
37
|
+
* Use this for advanced cases that need direct access to the Promise-based API.
|
|
38
|
+
*/
|
|
39
|
+
readonly getCatalogClient: () => IcebergRestCatalog;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Fetch and cache the server's catalog configuration. Calling this is optional;
|
|
43
|
+
* catalog operations trigger it lazily when a warehouse is configured.
|
|
44
|
+
*/
|
|
45
|
+
readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError>;
|
|
46
|
+
|
|
47
|
+
/** Lists all namespaces in the catalog. */
|
|
48
|
+
readonly listNamespaces: (
|
|
49
|
+
options?: ListNamespacesOptions,
|
|
50
|
+
) => Effect.Effect<ListNamespacesResult, IcebergError>;
|
|
51
|
+
|
|
52
|
+
/** Creates a new namespace in the catalog. */
|
|
53
|
+
readonly createNamespace: (
|
|
54
|
+
id: NamespaceIdentifier,
|
|
55
|
+
metadata?: NamespaceMetadata,
|
|
56
|
+
) => Effect.Effect<CreateNamespaceResponse, IcebergError>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Drops a namespace from the catalog.
|
|
60
|
+
*
|
|
61
|
+
* The namespace must be empty before it can be dropped.
|
|
62
|
+
*/
|
|
63
|
+
readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError>;
|
|
64
|
+
|
|
65
|
+
/** Loads metadata for a namespace. */
|
|
66
|
+
readonly loadNamespaceMetadata: (
|
|
67
|
+
id: NamespaceIdentifier,
|
|
68
|
+
) => Effect.Effect<NamespaceMetadata, IcebergError>;
|
|
69
|
+
|
|
70
|
+
/** Sets or removes properties on a namespace. */
|
|
71
|
+
readonly updateNamespaceProperties: (
|
|
72
|
+
id: NamespaceIdentifier,
|
|
73
|
+
request: UpdateNamespacePropertiesRequest,
|
|
74
|
+
) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError>;
|
|
75
|
+
|
|
76
|
+
/** Lists tables in a namespace. */
|
|
77
|
+
readonly listTables: (
|
|
78
|
+
namespace: NamespaceIdentifier,
|
|
79
|
+
options?: ListTablesOptions,
|
|
80
|
+
) => Effect.Effect<ListTablesResult, IcebergError>;
|
|
81
|
+
|
|
82
|
+
/** Creates a new table in the catalog. */
|
|
83
|
+
readonly createTable: (
|
|
84
|
+
namespace: NamespaceIdentifier,
|
|
85
|
+
request: CreateTableRequest,
|
|
86
|
+
) => Effect.Effect<TableMetadata, IcebergError>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a table and returns the full spec-aligned `LoadTableResult`, including
|
|
90
|
+
* server config, storage credentials, and the response ETag.
|
|
91
|
+
*/
|
|
92
|
+
readonly createTableResult: (
|
|
93
|
+
namespace: NamespaceIdentifier,
|
|
94
|
+
request: CreateTableRequest,
|
|
95
|
+
) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;
|
|
96
|
+
|
|
97
|
+
/** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */
|
|
98
|
+
readonly updateTable: (
|
|
99
|
+
id: TableIdentifier,
|
|
100
|
+
request: UpdateTableRequest,
|
|
101
|
+
) => Effect.Effect<CommitTableResponse, IcebergError>;
|
|
102
|
+
|
|
103
|
+
/** Spec-aligned alias for `updateTable`. */
|
|
104
|
+
readonly commitTable: (
|
|
105
|
+
id: TableIdentifier,
|
|
106
|
+
request: CommitTableRequest,
|
|
107
|
+
) => Effect.Effect<CommitTableResponse, IcebergError>;
|
|
108
|
+
|
|
109
|
+
/** Drops a table from the catalog. */
|
|
110
|
+
readonly dropTable: (
|
|
111
|
+
id: TableIdentifier,
|
|
112
|
+
options?: DropTableRequest,
|
|
113
|
+
) => Effect.Effect<void, IcebergError>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Loads metadata for a table.
|
|
117
|
+
*
|
|
118
|
+
* Pass `ifNoneMatch` in options to perform a conditional GET. If the server
|
|
119
|
+
* returns 304 Not Modified, the result is `null`.
|
|
120
|
+
*/
|
|
121
|
+
readonly loadTable: {
|
|
122
|
+
(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;
|
|
123
|
+
(
|
|
124
|
+
id: TableIdentifier,
|
|
125
|
+
options: LoadTableOptions,
|
|
126
|
+
): Effect.Effect<TableMetadata | null, IcebergError>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Loads the full spec-aligned `LoadTableResult`, including server config,
|
|
131
|
+
* storage credentials, and the response ETag. Returns `null` on 304.
|
|
132
|
+
*/
|
|
133
|
+
readonly loadTableResult: (
|
|
134
|
+
id: TableIdentifier,
|
|
135
|
+
options?: LoadTableOptions,
|
|
136
|
+
) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError>;
|
|
137
|
+
|
|
138
|
+
/** Checks if a namespace exists in the catalog. */
|
|
139
|
+
readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError>;
|
|
140
|
+
|
|
141
|
+
/** Checks if a table exists in the catalog. */
|
|
142
|
+
readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError>;
|
|
143
|
+
|
|
144
|
+
/** Creates a namespace if it does not exist. */
|
|
145
|
+
readonly createNamespaceIfNotExists: (
|
|
146
|
+
id: NamespaceIdentifier,
|
|
147
|
+
metadata?: NamespaceMetadata,
|
|
148
|
+
) => Effect.Effect<CreateNamespaceResponse | void, IcebergError>;
|
|
149
|
+
|
|
150
|
+
/** Creates a table if it does not exist. */
|
|
151
|
+
readonly createTableIfNotExists: (
|
|
152
|
+
namespace: NamespaceIdentifier,
|
|
153
|
+
request: CreateTableRequest,
|
|
154
|
+
) => Effect.Effect<TableMetadata, IcebergError>;
|
|
155
|
+
|
|
156
|
+
/** Registers an existing metadata file as a table in the given namespace. */
|
|
157
|
+
readonly registerTable: (
|
|
158
|
+
namespace: NamespaceIdentifier,
|
|
159
|
+
request: RegisterTableRequest,
|
|
160
|
+
) => Effect.Effect<TableMetadata, IcebergError>;
|
|
161
|
+
|
|
162
|
+
/** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */
|
|
163
|
+
readonly registerTableResult: (
|
|
164
|
+
namespace: NamespaceIdentifier,
|
|
165
|
+
request: RegisterTableRequest,
|
|
166
|
+
) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;
|
|
167
|
+
|
|
168
|
+
/** Renames a table. Servers may or may not support cross-namespace renames. */
|
|
169
|
+
readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError>;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
|
|
173
|
+
export class IcebergCatalog extends Context.Service<IcebergCatalog, Service>()(
|
|
174
|
+
"@useairfoil/effect-iceberg/IcebergCatalog",
|
|
175
|
+
) {}
|
|
176
|
+
|
|
177
|
+
const tryCatalog = <A>(evaluate: () => Promise<A>): Effect.Effect<A, IcebergError> =>
|
|
178
|
+
Effect.tryPromise({
|
|
179
|
+
try: evaluate,
|
|
180
|
+
catch: mapIcebergError,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
|
|
184
|
+
export const make = (options: IcebergRestCatalogOptions): Service => {
|
|
185
|
+
const catalog = new IcebergRestCatalog(options);
|
|
186
|
+
|
|
187
|
+
function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;
|
|
188
|
+
function loadTable(
|
|
189
|
+
id: TableIdentifier,
|
|
190
|
+
loadOptions: LoadTableOptions,
|
|
191
|
+
): Effect.Effect<TableMetadata | null, IcebergError>;
|
|
192
|
+
function loadTable(id: TableIdentifier, loadOptions?: LoadTableOptions) {
|
|
193
|
+
return tryCatalog(() =>
|
|
194
|
+
loadOptions === undefined ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return IcebergCatalog.of({
|
|
199
|
+
getCatalogClient: () => catalog,
|
|
200
|
+
loadConfig: () => tryCatalog(() => catalog.loadConfig()),
|
|
201
|
+
|
|
202
|
+
listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),
|
|
203
|
+
createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),
|
|
204
|
+
dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),
|
|
205
|
+
loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),
|
|
206
|
+
updateNamespaceProperties: (id, request) =>
|
|
207
|
+
tryCatalog(() => catalog.updateNamespaceProperties(id, request)),
|
|
208
|
+
|
|
209
|
+
listTables: (namespace, listOptions) =>
|
|
210
|
+
tryCatalog(() => catalog.listTables(namespace, listOptions)),
|
|
211
|
+
createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),
|
|
212
|
+
createTableResult: (namespace, request) =>
|
|
213
|
+
tryCatalog(() => catalog.createTableResult(namespace, request)),
|
|
214
|
+
updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),
|
|
215
|
+
commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),
|
|
216
|
+
dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),
|
|
217
|
+
loadTable,
|
|
218
|
+
loadTableResult: (id, loadOptions) =>
|
|
219
|
+
tryCatalog(() => catalog.loadTableResult(id, loadOptions)),
|
|
220
|
+
namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),
|
|
221
|
+
tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),
|
|
222
|
+
createNamespaceIfNotExists: (id, metadata) =>
|
|
223
|
+
tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),
|
|
224
|
+
createTableIfNotExists: (namespace, request) =>
|
|
225
|
+
tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),
|
|
226
|
+
registerTable: (namespace, request) =>
|
|
227
|
+
tryCatalog(() => catalog.registerTable(namespace, request)),
|
|
228
|
+
registerTableResult: (namespace, request) =>
|
|
229
|
+
tryCatalog(() => catalog.registerTableResult(namespace, request)),
|
|
230
|
+
renameTable: (request) => tryCatalog(() => catalog.renameTable(request)),
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const service = Effect.service(IcebergCatalog);
|
|
235
|
+
|
|
236
|
+
export const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog> =
|
|
237
|
+
Effect.map(service, (catalog) => catalog.getCatalogClient());
|
|
238
|
+
|
|
239
|
+
export const loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog> =
|
|
240
|
+
Effect.flatMap(service, (catalog) => catalog.loadConfig());
|
|
241
|
+
|
|
242
|
+
export const listNamespaces = (
|
|
243
|
+
options?: ListNamespacesOptions,
|
|
244
|
+
): Effect.Effect<ListNamespacesResult, IcebergError, IcebergCatalog> =>
|
|
245
|
+
Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));
|
|
246
|
+
|
|
247
|
+
export const createNamespace = (
|
|
248
|
+
id: NamespaceIdentifier,
|
|
249
|
+
metadata?: NamespaceMetadata,
|
|
250
|
+
): Effect.Effect<CreateNamespaceResponse, IcebergError, IcebergCatalog> =>
|
|
251
|
+
Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));
|
|
252
|
+
|
|
253
|
+
export const dropNamespace = (
|
|
254
|
+
id: NamespaceIdentifier,
|
|
255
|
+
): Effect.Effect<void, IcebergError, IcebergCatalog> =>
|
|
256
|
+
Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));
|
|
257
|
+
|
|
258
|
+
export const loadNamespaceMetadata = (
|
|
259
|
+
id: NamespaceIdentifier,
|
|
260
|
+
): Effect.Effect<NamespaceMetadata, IcebergError, IcebergCatalog> =>
|
|
261
|
+
Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));
|
|
262
|
+
|
|
263
|
+
export const updateNamespaceProperties = (
|
|
264
|
+
id: NamespaceIdentifier,
|
|
265
|
+
request: UpdateNamespacePropertiesRequest,
|
|
266
|
+
): Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError, IcebergCatalog> =>
|
|
267
|
+
Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));
|
|
268
|
+
|
|
269
|
+
export const listTables = (
|
|
270
|
+
namespace: NamespaceIdentifier,
|
|
271
|
+
options?: ListTablesOptions,
|
|
272
|
+
): Effect.Effect<ListTablesResult, IcebergError, IcebergCatalog> =>
|
|
273
|
+
Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));
|
|
274
|
+
|
|
275
|
+
export const createTable = (
|
|
276
|
+
namespace: NamespaceIdentifier,
|
|
277
|
+
request: CreateTableRequest,
|
|
278
|
+
): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
|
|
279
|
+
Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));
|
|
280
|
+
|
|
281
|
+
export const createTableResult = (
|
|
282
|
+
namespace: NamespaceIdentifier,
|
|
283
|
+
request: CreateTableRequest,
|
|
284
|
+
): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>
|
|
285
|
+
Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));
|
|
286
|
+
|
|
287
|
+
export const updateTable = (
|
|
288
|
+
id: TableIdentifier,
|
|
289
|
+
request: UpdateTableRequest,
|
|
290
|
+
): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>
|
|
291
|
+
Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));
|
|
292
|
+
|
|
293
|
+
export const commitTable = (
|
|
294
|
+
id: TableIdentifier,
|
|
295
|
+
request: CommitTableRequest,
|
|
296
|
+
): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>
|
|
297
|
+
Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));
|
|
298
|
+
|
|
299
|
+
export const dropTable = (
|
|
300
|
+
id: TableIdentifier,
|
|
301
|
+
options?: DropTableRequest,
|
|
302
|
+
): Effect.Effect<void, IcebergError, IcebergCatalog> =>
|
|
303
|
+
Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));
|
|
304
|
+
|
|
305
|
+
export function loadTable(
|
|
306
|
+
id: TableIdentifier,
|
|
307
|
+
): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog>;
|
|
308
|
+
export function loadTable(
|
|
309
|
+
id: TableIdentifier,
|
|
310
|
+
options: LoadTableOptions,
|
|
311
|
+
): Effect.Effect<TableMetadata | null, IcebergError, IcebergCatalog>;
|
|
312
|
+
export function loadTable(id: TableIdentifier, options?: LoadTableOptions) {
|
|
313
|
+
return Effect.flatMap(service, (catalog) =>
|
|
314
|
+
options === undefined ? catalog.loadTable(id) : catalog.loadTable(id, options),
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export const loadTableResult = (
|
|
319
|
+
id: TableIdentifier,
|
|
320
|
+
options?: LoadTableOptions,
|
|
321
|
+
): Effect.Effect<LoadTableResultWithEtag | null, IcebergError, IcebergCatalog> =>
|
|
322
|
+
Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));
|
|
323
|
+
|
|
324
|
+
export const namespaceExists = (
|
|
325
|
+
id: NamespaceIdentifier,
|
|
326
|
+
): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>
|
|
327
|
+
Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));
|
|
328
|
+
|
|
329
|
+
export const tableExists = (
|
|
330
|
+
id: TableIdentifier,
|
|
331
|
+
): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>
|
|
332
|
+
Effect.flatMap(service, (catalog) => catalog.tableExists(id));
|
|
333
|
+
|
|
334
|
+
export const createNamespaceIfNotExists = (
|
|
335
|
+
id: NamespaceIdentifier,
|
|
336
|
+
metadata?: NamespaceMetadata,
|
|
337
|
+
): Effect.Effect<CreateNamespaceResponse | void, IcebergError, IcebergCatalog> =>
|
|
338
|
+
Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));
|
|
339
|
+
|
|
340
|
+
export const createTableIfNotExists = (
|
|
341
|
+
namespace: NamespaceIdentifier,
|
|
342
|
+
request: CreateTableRequest,
|
|
343
|
+
): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
|
|
344
|
+
Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));
|
|
345
|
+
|
|
346
|
+
export const registerTable = (
|
|
347
|
+
namespace: NamespaceIdentifier,
|
|
348
|
+
request: RegisterTableRequest,
|
|
349
|
+
): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
|
|
350
|
+
Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));
|
|
351
|
+
|
|
352
|
+
export const registerTableResult = (
|
|
353
|
+
namespace: NamespaceIdentifier,
|
|
354
|
+
request: RegisterTableRequest,
|
|
355
|
+
): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>
|
|
356
|
+
Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));
|
|
357
|
+
|
|
358
|
+
export const renameTable = (
|
|
359
|
+
request: RenameTableRequest,
|
|
360
|
+
): Effect.Effect<void, IcebergError, IcebergCatalog> =>
|
|
361
|
+
Effect.flatMap(service, (catalog) => catalog.renameTable(request));
|
|
362
|
+
|
|
363
|
+
/** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
|
|
364
|
+
export const layer = (options: IcebergRestCatalogOptions): Layer.Layer<IcebergCatalog> =>
|
|
365
|
+
Layer.succeed(IcebergCatalog)(make(options));
|
|
366
|
+
|
|
367
|
+
/** Creates an `IcebergCatalog` layer from Effect `Config` values. */
|
|
368
|
+
export const layerConfig = (
|
|
369
|
+
config: Config.Wrap<IcebergRestCatalogOptions>,
|
|
370
|
+
): Layer.Layer<IcebergCatalog, Config.ConfigError> =>
|
|
371
|
+
Layer.effect(
|
|
372
|
+
IcebergCatalog,
|
|
373
|
+
Effect.gen(function* () {
|
|
374
|
+
const options = yield* Config.unwrap(config);
|
|
375
|
+
return make(options);
|
|
376
|
+
}),
|
|
377
|
+
);
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Data } from "effect";
|
|
2
|
+
import { IcebergError as IcebergJsError } from "iceberg-js";
|
|
3
|
+
|
|
4
|
+
/** Error type used by the Effect wrapper around `iceberg-js`. */
|
|
5
|
+
export class IcebergError extends Data.TaggedError("IcebergError")<{
|
|
6
|
+
readonly message: string;
|
|
7
|
+
readonly status?: number;
|
|
8
|
+
readonly icebergType?: string;
|
|
9
|
+
readonly icebergCode?: number;
|
|
10
|
+
readonly details?: unknown;
|
|
11
|
+
readonly isCommitStateUnknown?: boolean;
|
|
12
|
+
readonly cause?: unknown;
|
|
13
|
+
}> {}
|
|
14
|
+
|
|
15
|
+
/** Maps errors thrown by `iceberg-js` into `IcebergError`. */
|
|
16
|
+
export const mapIcebergError = (error: unknown): IcebergError => {
|
|
17
|
+
if (error instanceof IcebergJsError) {
|
|
18
|
+
return new IcebergError({
|
|
19
|
+
message: error.message,
|
|
20
|
+
status: error.status,
|
|
21
|
+
icebergType: error.icebergType,
|
|
22
|
+
icebergCode: error.icebergCode,
|
|
23
|
+
details: error.details,
|
|
24
|
+
isCommitStateUnknown: error.isCommitStateUnknown,
|
|
25
|
+
cause: error,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return new IcebergError({
|
|
30
|
+
message: error instanceof Error ? error.message : String(error),
|
|
31
|
+
cause: error,
|
|
32
|
+
});
|
|
33
|
+
};
|
package/src/index.ts
ADDED