@kmlckj/licos-platform-sdk 0.5.0 → 0.6.1
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 +31 -33
- package/package.json +45 -45
- package/src/browser.d.ts +0 -74
- package/src/browser.js +1 -102
- package/src/database.js +255 -0
- package/src/index.d.ts +189 -72
- package/src/index.js +3 -120
- package/src/runtime.js +70 -0
- package/src/shared.js +0 -246
- package/src/storage.js +155 -0
package/README.md
CHANGED
|
@@ -1,47 +1,45 @@
|
|
|
1
1
|
# @kmlckj/licos-platform-sdk
|
|
2
2
|
|
|
3
|
-
LICOS
|
|
3
|
+
LICOS platform SDK for server-side project runtime code.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Runtime Configuration
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- `uploadUser` / `uploadProject` 支持直接传本地文件路径
|
|
11
|
-
- `download(url, outputPath)` 会把文件写到本地路径
|
|
12
|
-
- 上传、预览、下载都要求鉴权;`download(...)` 会自动带上 `token` 或 `LICOS_USER_TOKEN`
|
|
7
|
+
Server-side helpers call platform Studio runtime APIs. Project code does not
|
|
8
|
+
pass API base URLs, project IDs, tokens, or environment scopes. The SDK loads
|
|
9
|
+
them from runtime environment variables injected by LICOS:
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```
|
|
11
|
+
- `LICOS_PLATFORM_API_BASE_URL`
|
|
12
|
+
- `LICOS_RUNTIME_TOKEN` or `LICOS_USER_TOKEN`
|
|
13
|
+
- `LICOS_PROJECT_ID` or `AGENT_PROJECT_ID`
|
|
14
|
+
- `LICOS_WORKSPACE_ID` or `AGENT_WORKSPACE_ID`
|
|
15
|
+
- `LICOS_PROJECT_ENV`, mapped internally to `dev` or `prod`
|
|
20
16
|
|
|
21
|
-
##
|
|
17
|
+
## Database
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
- `download(url)` 返回 `Blob`
|
|
26
|
-
- TypeScript 前端可显式导入浏览器入口 `@kmlckj/licos-platform-sdk/browser`,拿到浏览器专用类型
|
|
27
|
-
- 预览 / 下载接口同样要求传 `token`
|
|
19
|
+
Database helpers call the runtime database data plane only. They do not expose
|
|
20
|
+
database control-plane or service deletion APIs.
|
|
28
21
|
|
|
29
22
|
```js
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
import { database } from '@kmlckj/licos-platform-sdk';
|
|
24
|
+
|
|
25
|
+
const rows = await database
|
|
26
|
+
.table('todos')
|
|
27
|
+
.select('id', 'title')
|
|
28
|
+
.eq('done', false)
|
|
29
|
+
.order('created_at', { desc: true })
|
|
30
|
+
.limit(10)
|
|
31
|
+
.execute();
|
|
37
32
|
```
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
import { uploadUser, download } from '@kmlckj/licos-platform-sdk/browser';
|
|
34
|
+
## Object Storage
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
36
|
+
```js
|
|
37
|
+
import { storage } from '@kmlckj/licos-platform-sdk';
|
|
45
38
|
|
|
46
|
-
|
|
39
|
+
await storage.createFolder('reports');
|
|
40
|
+
const file = await storage.uploadFile('/tmp/report.pdf');
|
|
41
|
+
const link = await storage.shareUrl(file.id);
|
|
47
42
|
```
|
|
43
|
+
|
|
44
|
+
The browser entry does not export object storage helpers because runtime tokens
|
|
45
|
+
must not be bundled into public frontend code.
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@kmlckj/licos-platform-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "LICOS platform SDK
|
|
5
|
-
"author": "kmlckj",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./src/index.js",
|
|
8
|
-
"browser": "./src/browser.js",
|
|
9
|
-
"types": "./src/index.d.ts",
|
|
10
|
-
"typesVersions": {
|
|
11
|
-
"*": {
|
|
12
|
-
"browser": [
|
|
13
|
-
"src/browser.d.ts"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"exports": {
|
|
18
|
-
".": {
|
|
19
|
-
"browser": {
|
|
20
|
-
"types": "./src/browser.d.ts",
|
|
21
|
-
"default": "./src/browser.js"
|
|
22
|
-
},
|
|
23
|
-
"types": "./src/index.d.ts",
|
|
24
|
-
"import": "./src/index.js",
|
|
25
|
-
"default": "./src/index.js"
|
|
26
|
-
},
|
|
27
|
-
"./browser": {
|
|
28
|
-
"types": "./src/browser.d.ts",
|
|
29
|
-
"import": "./src/browser.js",
|
|
30
|
-
"default": "./src/browser.js"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"files": [
|
|
34
|
-
"src",
|
|
35
|
-
"README.md"
|
|
36
|
-
],
|
|
37
|
-
"scripts": {
|
|
38
|
-
"test": "node --test"
|
|
39
|
-
},
|
|
40
|
-
"license": "MIT",
|
|
41
|
-
"publishConfig": {
|
|
42
|
-
"access": "public",
|
|
43
|
-
"registry": "https://registry.npmjs.org"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@kmlckj/licos-platform-sdk",
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "LICOS platform SDK package shell for browser and Node runtimes",
|
|
5
|
+
"author": "kmlckj",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./src/index.js",
|
|
8
|
+
"browser": "./src/browser.js",
|
|
9
|
+
"types": "./src/index.d.ts",
|
|
10
|
+
"typesVersions": {
|
|
11
|
+
"*": {
|
|
12
|
+
"browser": [
|
|
13
|
+
"src/browser.d.ts"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"browser": {
|
|
20
|
+
"types": "./src/browser.d.ts",
|
|
21
|
+
"default": "./src/browser.js"
|
|
22
|
+
},
|
|
23
|
+
"types": "./src/index.d.ts",
|
|
24
|
+
"import": "./src/index.js",
|
|
25
|
+
"default": "./src/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./browser": {
|
|
28
|
+
"types": "./src/browser.d.ts",
|
|
29
|
+
"import": "./src/browser.js",
|
|
30
|
+
"default": "./src/browser.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"test": "node --test"
|
|
39
|
+
},
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public",
|
|
43
|
+
"registry": "https://registry.npmjs.org"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/browser.d.ts
CHANGED
|
@@ -1,48 +1,3 @@
|
|
|
1
|
-
export interface UploadResult {
|
|
2
|
-
bucket: string;
|
|
3
|
-
object_key: string;
|
|
4
|
-
file_name: string;
|
|
5
|
-
content_type: string;
|
|
6
|
-
size_bytes: number;
|
|
7
|
-
preview_url: string;
|
|
8
|
-
download_url: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface BlobLike {
|
|
12
|
-
arrayBuffer(): Promise<ArrayBuffer>;
|
|
13
|
-
readonly size?: number;
|
|
14
|
-
readonly type?: string;
|
|
15
|
-
readonly name?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface UploadBinaryDescriptor {
|
|
19
|
-
data?: ArrayBuffer | ArrayBufferView | BlobLike;
|
|
20
|
-
file?: ArrayBuffer | ArrayBufferView | BlobLike;
|
|
21
|
-
fileName?: string;
|
|
22
|
-
contentType?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type UploadSource =
|
|
26
|
-
| ArrayBuffer
|
|
27
|
-
| ArrayBufferView
|
|
28
|
-
| BlobLike
|
|
29
|
-
| UploadBinaryDescriptor;
|
|
30
|
-
|
|
31
|
-
export interface StorageClientOptions {
|
|
32
|
-
baseUrl?: string;
|
|
33
|
-
token?: string;
|
|
34
|
-
userId?: string;
|
|
35
|
-
projectId?: string;
|
|
36
|
-
fetch?: typeof fetch;
|
|
37
|
-
headers?: HeadersInit;
|
|
38
|
-
credentials?: RequestCredentials;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface UploadProjectOptions extends StorageClientOptions {
|
|
42
|
-
userId?: string;
|
|
43
|
-
projectId?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
1
|
export class PlatformSdkError extends Error {
|
|
47
2
|
status?: number;
|
|
48
3
|
code?: number;
|
|
@@ -51,32 +6,3 @@ export class PlatformSdkError extends Error {
|
|
|
51
6
|
|
|
52
7
|
export class ConfigurationError extends PlatformSdkError {}
|
|
53
8
|
export class ApiError extends PlatformSdkError {}
|
|
54
|
-
|
|
55
|
-
export class StorageClient {
|
|
56
|
-
constructor(options?: StorageClientOptions);
|
|
57
|
-
previewUrl(bucket: string, objectKey: string): string;
|
|
58
|
-
downloadUrl(bucket: string, objectKey: string): string;
|
|
59
|
-
uploadUser(file: UploadSource): Promise<UploadResult>;
|
|
60
|
-
uploadProject(file: UploadSource, options?: UploadProjectOptions): Promise<UploadResult>;
|
|
61
|
-
download(url: string): Promise<Blob>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function previewUrl(
|
|
65
|
-
bucket: string,
|
|
66
|
-
objectKey: string,
|
|
67
|
-
options?: StorageClientOptions,
|
|
68
|
-
): string;
|
|
69
|
-
export function downloadUrl(
|
|
70
|
-
bucket: string,
|
|
71
|
-
objectKey: string,
|
|
72
|
-
options?: StorageClientOptions,
|
|
73
|
-
): string;
|
|
74
|
-
export function uploadUser(
|
|
75
|
-
file: UploadSource,
|
|
76
|
-
options?: StorageClientOptions,
|
|
77
|
-
): Promise<UploadResult>;
|
|
78
|
-
export function uploadProject(
|
|
79
|
-
file: UploadSource,
|
|
80
|
-
options?: UploadProjectOptions,
|
|
81
|
-
): Promise<UploadResult>;
|
|
82
|
-
export function download(url: string, options?: StorageClientOptions): Promise<Blob>;
|
package/src/browser.js
CHANGED
|
@@ -1,102 +1 @@
|
|
|
1
|
-
|
|
2
|
-
ApiError,
|
|
3
|
-
ConfigurationError,
|
|
4
|
-
PlatformSdkError,
|
|
5
|
-
downloadBlob,
|
|
6
|
-
encodeObjectKey,
|
|
7
|
-
encodeStorageSegment,
|
|
8
|
-
normalizeBaseUrl,
|
|
9
|
-
resolveProjectId,
|
|
10
|
-
resolveUserId,
|
|
11
|
-
uploadFile,
|
|
12
|
-
} from './shared.js';
|
|
13
|
-
|
|
14
|
-
export class StorageClient {
|
|
15
|
-
constructor(options = {}) {
|
|
16
|
-
this.baseUrl = options.baseUrl;
|
|
17
|
-
this.token = options.token;
|
|
18
|
-
this.userId = options.userId;
|
|
19
|
-
this.projectId = options.projectId;
|
|
20
|
-
this.fetchImpl = options.fetch ?? fetch;
|
|
21
|
-
this.headers = options.headers;
|
|
22
|
-
this.credentials = options.credentials;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
previewUrl(bucket, objectKey) {
|
|
26
|
-
const baseUrl = normalizeBaseUrl(this.baseUrl);
|
|
27
|
-
return `${baseUrl}/api/v1/public/storage/${encodeStorageSegment(bucket)}/${encodeObjectKey(objectKey)}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
downloadUrl(bucket, objectKey) {
|
|
31
|
-
return `${this.previewUrl(bucket, objectKey)}?download=1`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async uploadUser(file) {
|
|
35
|
-
const baseUrl = normalizeBaseUrl(this.baseUrl);
|
|
36
|
-
return uploadFile(this.fetchImpl, `${baseUrl}/api/v1/storage/upload/user`, file, {
|
|
37
|
-
token: this.token,
|
|
38
|
-
headers: this.headers,
|
|
39
|
-
credentials: this.credentials,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async uploadProject(file, options = {}) {
|
|
44
|
-
const baseUrl = normalizeBaseUrl(this.baseUrl);
|
|
45
|
-
const userId = resolveUserId(options.userId ?? this.userId);
|
|
46
|
-
const projectId = resolveProjectId(options.projectId ?? this.projectId);
|
|
47
|
-
return uploadFile(
|
|
48
|
-
this.fetchImpl,
|
|
49
|
-
`${baseUrl}/api/v1/storage/upload/project/${encodeStorageSegment(userId)}/${encodeStorageSegment(projectId)}`,
|
|
50
|
-
file,
|
|
51
|
-
{
|
|
52
|
-
token: this.token,
|
|
53
|
-
headers: this.headers,
|
|
54
|
-
credentials: this.credentials,
|
|
55
|
-
},
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async download(url, outputPath) {
|
|
60
|
-
if (outputPath !== undefined) {
|
|
61
|
-
throw new ConfigurationError(
|
|
62
|
-
'Front-end mode does not support downloading directly to a filesystem path. Omit outputPath to receive a Blob.',
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return downloadBlob(this.fetchImpl, url, {
|
|
66
|
-
token: this.token,
|
|
67
|
-
headers: this.headers,
|
|
68
|
-
credentials: this.credentials,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function defaultClient(options = {}) {
|
|
74
|
-
return new StorageClient(options);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function previewUrl(bucket, objectKey, options = {}) {
|
|
78
|
-
return defaultClient(options).previewUrl(bucket, objectKey);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function downloadUrl(bucket, objectKey, options = {}) {
|
|
82
|
-
return defaultClient(options).downloadUrl(bucket, objectKey);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export async function uploadUser(file, options = {}) {
|
|
86
|
-
return defaultClient(options).uploadUser(file);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function uploadProject(file, options = {}) {
|
|
90
|
-
return defaultClient(options).uploadProject(file, options);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function download(url, outputPathOrOptions, maybeOptions = {}) {
|
|
94
|
-
if (typeof outputPathOrOptions === 'string') {
|
|
95
|
-
throw new ConfigurationError(
|
|
96
|
-
'Front-end mode does not support downloading directly to a filesystem path. Omit outputPath to receive a Blob.',
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
return defaultClient(outputPathOrOptions ?? maybeOptions).download(url);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export { PlatformSdkError, ConfigurationError, ApiError };
|
|
1
|
+
export { PlatformSdkError, ConfigurationError, ApiError } from './shared.js';
|
package/src/database.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { ApiError } from './shared.js';
|
|
2
|
+
import { authHeaders, runtimeConfig } from './runtime.js';
|
|
3
|
+
|
|
4
|
+
function databaseConfig() {
|
|
5
|
+
return runtimeConfig({ environmentOverrideEnv: 'LICOS_DATABASE_ENVIRONMENT' });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function databaseUrl(config, route) {
|
|
9
|
+
return `${config.baseUrl}/api/v1/studio/runtime/database/projects/${encodeURIComponent(config.projectId)}${route}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function compactObject(value) {
|
|
13
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined && item !== null));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeSelect(select) {
|
|
17
|
+
if (select === undefined || select === null) return undefined;
|
|
18
|
+
if (typeof select === 'string') {
|
|
19
|
+
return select.split(',').map((item) => item.trim()).filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
return Array.from(select).map((item) => String(item));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function decodeResponse(response) {
|
|
25
|
+
const text = await response.text();
|
|
26
|
+
const payload = text ? JSON.parse(text) : null;
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
throw new ApiError(text || `platform database API returned ${response.status}`, {
|
|
29
|
+
status: response.status,
|
|
30
|
+
details: payload,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (!payload || typeof payload !== 'object') return payload;
|
|
34
|
+
if ((payload.code !== undefined && payload.code !== 0) || payload.success === false) {
|
|
35
|
+
throw new ApiError(payload.message || 'platform database API failed', {
|
|
36
|
+
status: response.status,
|
|
37
|
+
code: typeof payload.code === 'number' ? payload.code : undefined,
|
|
38
|
+
details: payload,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return payload.data;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function requestJson(route, body) {
|
|
45
|
+
const config = databaseConfig();
|
|
46
|
+
const payload = { environment: config.environment, ...compactObject(body) };
|
|
47
|
+
const response = await fetch(databaseUrl(config, route), {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: authHeaders(config),
|
|
50
|
+
body: JSON.stringify(payload),
|
|
51
|
+
});
|
|
52
|
+
return decodeResponse(response);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function query(table, options = {}) {
|
|
56
|
+
return requestJson('/query', {
|
|
57
|
+
table,
|
|
58
|
+
select: normalizeSelect(options.select),
|
|
59
|
+
filters: options.filters?.length ? options.filters : undefined,
|
|
60
|
+
orderBy: options.orderBy?.length ? options.orderBy : undefined,
|
|
61
|
+
range: options.range,
|
|
62
|
+
limit: options.limit,
|
|
63
|
+
offset: options.offset,
|
|
64
|
+
count: options.count,
|
|
65
|
+
head: options.head,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function single(table, options = {}) {
|
|
70
|
+
return requestJson('/single', {
|
|
71
|
+
table,
|
|
72
|
+
select: normalizeSelect(options.select),
|
|
73
|
+
filters: options.filters?.length ? options.filters : undefined,
|
|
74
|
+
orderBy: options.orderBy?.length ? options.orderBy : undefined,
|
|
75
|
+
mode: options.maybe ? 'maybe_single' : 'single',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function maybeSingle(table, options = {}) {
|
|
80
|
+
return single(table, { ...options, maybe: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function aggregate(table, aggregateName, options = {}) {
|
|
84
|
+
return requestJson('/aggregate', {
|
|
85
|
+
table,
|
|
86
|
+
filters: options.filters?.length ? options.filters : undefined,
|
|
87
|
+
aggregate: aggregateName,
|
|
88
|
+
field: options.field,
|
|
89
|
+
groupBy: options.groupBy?.length ? options.groupBy : undefined,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function insert(table, options = {}) {
|
|
94
|
+
return requestJson('/insert', {
|
|
95
|
+
table,
|
|
96
|
+
row: options.row,
|
|
97
|
+
rows: options.rows,
|
|
98
|
+
returning: options.returning ?? true,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function updateRows(table, options = {}) {
|
|
103
|
+
return requestJson('/update', {
|
|
104
|
+
table,
|
|
105
|
+
values: options.values,
|
|
106
|
+
filters: options.filters?.length ? options.filters : undefined,
|
|
107
|
+
updates: options.updates?.length ? options.updates : undefined,
|
|
108
|
+
returning: options.returning ?? true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function deleteRows(table, options = {}) {
|
|
113
|
+
return requestJson('/delete', {
|
|
114
|
+
table,
|
|
115
|
+
filters: options.filters?.length ? options.filters : undefined,
|
|
116
|
+
deletes: options.deletes?.length ? options.deletes : undefined,
|
|
117
|
+
returning: options.returning ?? true,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function upsert(table, options = {}) {
|
|
122
|
+
return requestJson('/upsert', {
|
|
123
|
+
table,
|
|
124
|
+
row: options.row,
|
|
125
|
+
rows: options.rows,
|
|
126
|
+
conflictKeys: options.conflictKeys?.length ? options.conflictKeys : undefined,
|
|
127
|
+
returning: options.returning ?? true,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function transaction(operations) {
|
|
132
|
+
const config = databaseConfig();
|
|
133
|
+
const normalized = operations.map((operation) => ({
|
|
134
|
+
type: operation.type,
|
|
135
|
+
request: {
|
|
136
|
+
...operation.request,
|
|
137
|
+
environment: operation.request?.environment || config.environment,
|
|
138
|
+
},
|
|
139
|
+
}));
|
|
140
|
+
return requestJson('/transaction', { operations: normalized });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function rpc(functionName, args = {}) {
|
|
144
|
+
return requestJson(`/rpc/${encodeURIComponent(functionName)}`, { args });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function table(name) {
|
|
148
|
+
return new TableQuery(name);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
class TableQuery {
|
|
152
|
+
constructor(name) {
|
|
153
|
+
this.name = name;
|
|
154
|
+
this._select = undefined;
|
|
155
|
+
this._filters = [];
|
|
156
|
+
this._orderBy = [];
|
|
157
|
+
this._range = undefined;
|
|
158
|
+
this._limit = undefined;
|
|
159
|
+
this._offset = undefined;
|
|
160
|
+
this._count = undefined;
|
|
161
|
+
this._head = undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
select(...fields) {
|
|
165
|
+
this._select = fields.length === 1 && fields[0].includes(',') ? normalizeSelect(fields[0]) : fields;
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
filter(field, op, value) {
|
|
170
|
+
this._filters.push({ field, op, value });
|
|
171
|
+
return this;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
eq(field, value) { return this.filter(field, 'eq', value); }
|
|
175
|
+
neq(field, value) { return this.filter(field, 'neq', value); }
|
|
176
|
+
gt(field, value) { return this.filter(field, 'gt', value); }
|
|
177
|
+
gte(field, value) { return this.filter(field, 'gte', value); }
|
|
178
|
+
lt(field, value) { return this.filter(field, 'lt', value); }
|
|
179
|
+
lte(field, value) { return this.filter(field, 'lte', value); }
|
|
180
|
+
in(field, value) { return this.filter(field, 'in', value); }
|
|
181
|
+
notIn(field, value) { return this.filter(field, 'not_in', value); }
|
|
182
|
+
isNull(field) { return this.filter(field, 'is_null'); }
|
|
183
|
+
isNotNull(field) { return this.filter(field, 'is_not_null'); }
|
|
184
|
+
like(field, value) { return this.filter(field, 'like', value); }
|
|
185
|
+
ilike(field, value) { return this.filter(field, 'ilike', value); }
|
|
186
|
+
|
|
187
|
+
order(field, options = {}) {
|
|
188
|
+
this._orderBy.push({ field, direction: options.desc ? 'desc' : 'asc' });
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
range(from, to) {
|
|
193
|
+
this._range = { from, to };
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
limit(value) {
|
|
198
|
+
this._limit = value;
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
offset(value) {
|
|
203
|
+
this._offset = value;
|
|
204
|
+
return this;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
withCount(options = {}) {
|
|
208
|
+
this._count = true;
|
|
209
|
+
this._head = Boolean(options.head);
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
execute() {
|
|
214
|
+
return query(this.name, {
|
|
215
|
+
select: this._select,
|
|
216
|
+
filters: this._filters,
|
|
217
|
+
orderBy: this._orderBy,
|
|
218
|
+
range: this._range,
|
|
219
|
+
limit: this._limit,
|
|
220
|
+
offset: this._offset,
|
|
221
|
+
count: this._count,
|
|
222
|
+
head: this._head,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
single() {
|
|
227
|
+
return single(this.name, {
|
|
228
|
+
select: this._select,
|
|
229
|
+
filters: this._filters,
|
|
230
|
+
orderBy: this._orderBy,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
maybeSingle() {
|
|
235
|
+
return maybeSingle(this.name, {
|
|
236
|
+
select: this._select,
|
|
237
|
+
filters: this._filters,
|
|
238
|
+
orderBy: this._orderBy,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export const database = {
|
|
244
|
+
query,
|
|
245
|
+
single,
|
|
246
|
+
maybeSingle,
|
|
247
|
+
aggregate,
|
|
248
|
+
insert,
|
|
249
|
+
updateRows,
|
|
250
|
+
deleteRows,
|
|
251
|
+
upsert,
|
|
252
|
+
transaction,
|
|
253
|
+
rpc,
|
|
254
|
+
table,
|
|
255
|
+
};
|