@onchaindb/sdk 0.4.0 → 0.4.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/.DS_Store +0 -0
- package/.claude/settings.local.json +8 -0
- package/.gitignore +5 -0
- package/.idea/.gitignore +5 -0
- package/.idea/compiler.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/sdk.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +257 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -3
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +0 -20
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +0 -40
- package/dist/database.js.map +1 -1
- package/dist/query-sdk/tests/setup.d.ts +16 -0
- package/dist/query-sdk/tests/setup.d.ts.map +1 -0
- package/dist/query-sdk/tests/setup.js +49 -0
- package/dist/query-sdk/tests/setup.js.map +1 -0
- package/examples/basic-usage.ts +136 -0
- package/examples/blob-upload-example.ts +140 -0
- package/examples/collection-schema-example.ts +304 -0
- package/examples/server-side-joins.ts +201 -0
- package/examples/tweet-self-joins-example.ts +352 -0
- package/package-lock.json +3823 -0
- package/package.json +1 -1
- package/skills.md +1096 -0
- package/src/.env +1 -0
- package/src/batch.d.ts +121 -0
- package/src/batch.js +205 -0
- package/src/batch.ts +257 -0
- package/src/client.ts +1856 -0
- package/src/database.d.ts +268 -0
- package/src/database.js +294 -0
- package/src/database.ts +695 -0
- package/src/index.d.ts +160 -0
- package/src/index.js +186 -0
- package/src/index.ts +253 -0
- package/src/query-sdk/ConditionBuilder.ts +103 -0
- package/src/query-sdk/FieldConditionBuilder.ts +2 -0
- package/src/query-sdk/NestedBuilders.ts +186 -0
- package/src/query-sdk/OnChainDB.ts +294 -0
- package/src/query-sdk/QueryBuilder.ts +1191 -0
- package/src/query-sdk/QueryResult.ts +375 -0
- package/src/query-sdk/README.md +866 -0
- package/src/query-sdk/SelectionBuilder.ts +94 -0
- package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
- package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
- package/src/query-sdk/dist/ConditionBuilder.js +90 -0
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
- package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
- package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
- package/src/query-sdk/dist/NestedBuilders.js +144 -0
- package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
- package/src/query-sdk/dist/OnChainDB.js +123 -0
- package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
- package/src/query-sdk/dist/QueryBuilder.js +295 -0
- package/src/query-sdk/dist/QueryResult.d.ts +52 -0
- package/src/query-sdk/dist/QueryResult.js +293 -0
- package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
- package/src/query-sdk/dist/SelectionBuilder.js +80 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
- package/src/query-sdk/dist/index.d.ts +36 -0
- package/src/query-sdk/dist/index.js +27 -0
- package/src/query-sdk/dist/operators.d.ts +56 -0
- package/src/query-sdk/dist/operators.js +289 -0
- package/src/query-sdk/dist/tests/setup.d.ts +15 -0
- package/src/query-sdk/dist/tests/setup.js +46 -0
- package/src/query-sdk/index.ts +59 -0
- package/src/query-sdk/jest.config.js +25 -0
- package/src/query-sdk/operators.ts +335 -0
- package/src/query-sdk/package.json +46 -0
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
- package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
- package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
- package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
- package/src/query-sdk/tests/QueryResult.test.ts +464 -0
- package/src/query-sdk/tests/aggregations.test.ts +653 -0
- package/src/query-sdk/tests/comprehensive.test.ts +279 -0
- package/src/query-sdk/tests/integration.test.ts +608 -0
- package/src/query-sdk/tests/operators.test.ts +327 -0
- package/src/query-sdk/tests/setup.ts +59 -0
- package/src/query-sdk/tests/unit.test.ts +794 -0
- package/src/query-sdk/tsconfig.json +26 -0
- package/src/query-sdk/yarn.lock +3092 -0
- package/src/types.d.ts +131 -0
- package/src/types.js +46 -0
- package/src/types.ts +534 -0
- package/src/x402/index.ts +12 -0
- package/src/x402/types.ts +250 -0
- package/src/x402/utils.ts +332 -0
- package/tsconfig.json +20 -0
- package/yarn.lock +2309 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { LogicalOperator, FieldConditionBuilder, Condition } from './operators';
|
|
2
|
+
|
|
3
|
+
// Builder for creating nested field conditions with ORM-like syntax
|
|
4
|
+
export class NestedConditionBuilder {
|
|
5
|
+
private path: string[];
|
|
6
|
+
|
|
7
|
+
constructor(rootField: string) {
|
|
8
|
+
this.path = [rootField];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Add another level to the path and create field conditions
|
|
12
|
+
field(fieldName: string): NestedFieldConditionBuilder {
|
|
13
|
+
const newPath = [...this.path, fieldName];
|
|
14
|
+
return new NestedFieldConditionBuilder(newPath);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Create nested structure with callback
|
|
18
|
+
nested(fieldName: string, builderFn: (builder: NestedConditionBuilder) => LogicalOperator): LogicalOperator {
|
|
19
|
+
const nestedPath = [...this.path, fieldName];
|
|
20
|
+
const nestedBuilder = new NestedConditionBuilder('');
|
|
21
|
+
nestedBuilder.path = nestedPath;
|
|
22
|
+
return builderFn(nestedBuilder);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Create logical groups
|
|
26
|
+
andGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
|
|
27
|
+
const conditions = builderFn(this);
|
|
28
|
+
return LogicalOperator.And(conditions);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
orGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
|
|
32
|
+
const conditions = builderFn(this);
|
|
33
|
+
return LogicalOperator.Or(conditions);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
notGroup(builderFn: (builder: NestedConditionBuilder) => LogicalOperator[]): LogicalOperator {
|
|
37
|
+
const conditions = builderFn(this);
|
|
38
|
+
return LogicalOperator.Not(conditions);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Builder for field conditions within nested structures
|
|
43
|
+
// Only includes operators that actually exist in the Rust implementation
|
|
44
|
+
export class NestedFieldConditionBuilder {
|
|
45
|
+
private fieldPath: string[];
|
|
46
|
+
|
|
47
|
+
constructor(fieldPath: string[]) {
|
|
48
|
+
this.fieldPath = fieldPath;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private createCondition(operator: string, value: any): Condition {
|
|
52
|
+
const path = this.fieldPath.join('.');
|
|
53
|
+
return {
|
|
54
|
+
field: path,
|
|
55
|
+
operator,
|
|
56
|
+
value
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ===== BASE OPERATORS (BaseOperator) =====
|
|
61
|
+
|
|
62
|
+
equals(value: any): Condition {
|
|
63
|
+
return this.createCondition('is', value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
notEquals(value: any): Condition {
|
|
67
|
+
return this.createCondition('isNot', value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
in(values: any[]): Condition {
|
|
71
|
+
return this.createCondition('in', values);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
notIn(values: any[]): Condition {
|
|
75
|
+
return this.createCondition('notIn', values);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
isNull(): Condition {
|
|
79
|
+
return this.createCondition('isNull', true);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
isNotNull(): Condition {
|
|
83
|
+
return this.createCondition('isNull', false);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
exists(): Condition {
|
|
87
|
+
return this.createCondition('exists', true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
notExists(): Condition {
|
|
91
|
+
return this.createCondition('exists', false);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ===== STRING OPERATORS (StringOperator) =====
|
|
95
|
+
|
|
96
|
+
startsWith(value: string): Condition {
|
|
97
|
+
return this.createCondition('startsWith', value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
endsWith(value: string): Condition {
|
|
101
|
+
return this.createCondition('endsWith', value);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
contains(value: string): Condition {
|
|
105
|
+
return this.createCondition('includes', value);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
regExpMatches(pattern: string): Condition {
|
|
109
|
+
return this.createCondition('regExpMatches', pattern);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
includesCaseInsensitive(value: string): Condition {
|
|
113
|
+
return this.createCondition('includesCaseInsensitive', value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
startsWithCaseInsensitive(value: string): Condition {
|
|
117
|
+
return this.createCondition('startsWithCaseInsensitive', value);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
endsWithCaseInsensitive(value: string): Condition {
|
|
121
|
+
return this.createCondition('endsWithCaseInsensitive', value);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ===== NUMBER OPERATORS (NumberOperator) =====
|
|
125
|
+
|
|
126
|
+
greaterThan(value: any): Condition {
|
|
127
|
+
return this.createCondition('greaterThan', value);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
lessThan(value: any): Condition {
|
|
131
|
+
return this.createCondition('lessThan', value);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
greaterThanOrEqual(value: any): Condition {
|
|
135
|
+
return this.createCondition('greaterThanOrEqual', value);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
lessThanOrEqual(value: any): Condition {
|
|
139
|
+
return this.createCondition('lessThanOrEqual', value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ===== IP OPERATORS (IpOperator) =====
|
|
143
|
+
|
|
144
|
+
isLocalIp(): Condition {
|
|
145
|
+
return this.createCondition('isLocalIp', true);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
isExternalIp(): Condition {
|
|
149
|
+
return this.createCondition('isExternalIp', true);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ===== MISC OPERATORS (MiscOperator) =====
|
|
153
|
+
|
|
154
|
+
b64(value: string): Condition {
|
|
155
|
+
return this.createCondition('b64', value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
inDataset(dataset: string): Condition {
|
|
159
|
+
return this.createCondition('inDataset', dataset);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
inCountry(countryCode: string): Condition {
|
|
163
|
+
return this.createCondition('inCountry', countryCode);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
cidr(cidr: string): Condition {
|
|
167
|
+
return this.createCondition('CIDR', cidr);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ===== BETWEEN OPERATOR =====
|
|
171
|
+
|
|
172
|
+
between(min: any, max: any): Condition {
|
|
173
|
+
return this.createCondition('between', { from: min, to: max });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ===== CONVENIENCE METHODS =====
|
|
177
|
+
|
|
178
|
+
// Boolean checks (using base operators)
|
|
179
|
+
isTrue(): Condition {
|
|
180
|
+
return this.equals(true);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
isFalse(): Condition {
|
|
184
|
+
return this.equals(false);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import {QueryBuilder} from './QueryBuilder';
|
|
2
|
+
import {SelectionBuilder} from './SelectionBuilder';
|
|
3
|
+
import {FieldMap, HttpClient, QueryRequest, QueryResponse, QueryValue} from "./index";
|
|
4
|
+
|
|
5
|
+
// Main SDK class providing static methods for query building
|
|
6
|
+
export class OnChainDB {
|
|
7
|
+
private static httpClient?: HttpClient;
|
|
8
|
+
private static serverUrl?: string;
|
|
9
|
+
private static apiKey?: string;
|
|
10
|
+
|
|
11
|
+
// Configure the SDK with HTTP client and server URL
|
|
12
|
+
static configure(httpClient: HttpClient, serverUrl: string, apiKey?: string): void {
|
|
13
|
+
this.httpClient = httpClient;
|
|
14
|
+
this.serverUrl = serverUrl;
|
|
15
|
+
this.apiKey = apiKey;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Get the configured HTTP client
|
|
19
|
+
static getHttpClient(): HttpClient | undefined {
|
|
20
|
+
return this.httpClient;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Get the configured server URL
|
|
24
|
+
static getServerUrl(): string | undefined {
|
|
25
|
+
return this.serverUrl;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Start building a new query
|
|
29
|
+
static query(): QueryBuilder {
|
|
30
|
+
return new QueryBuilder(this.httpClient, this.serverUrl);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create a query builder with specific HTTP client and server URL (one-time use)
|
|
34
|
+
static queryWith(httpClient: HttpClient, serverUrl: string): QueryBuilder {
|
|
35
|
+
return new QueryBuilder(httpClient, serverUrl);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Create a simple query with just field selection (no filtering)
|
|
39
|
+
static select(builderFn: (builder: SelectionBuilder) => SelectionBuilder): QueryBuilder {
|
|
40
|
+
const query = new QueryBuilder(this.httpClient, this.serverUrl);
|
|
41
|
+
query.select(builderFn);
|
|
42
|
+
return query;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Execute a raw query using HTTP
|
|
46
|
+
static async rawQuery(
|
|
47
|
+
queryJson: string,
|
|
48
|
+
httpClient?: HttpClient,
|
|
49
|
+
serverUrl?: string,
|
|
50
|
+
fieldMap?: FieldMap
|
|
51
|
+
): Promise<QueryResponse> {
|
|
52
|
+
const client = httpClient || this.httpClient;
|
|
53
|
+
const url = serverUrl || this.serverUrl;
|
|
54
|
+
|
|
55
|
+
if (!client) {
|
|
56
|
+
throw new Error('HTTP client is required for raw query execution');
|
|
57
|
+
}
|
|
58
|
+
if (!url) {
|
|
59
|
+
throw new Error('Server URL is required for raw query execution');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const queryValue: QueryValue = JSON.parse(queryJson);
|
|
64
|
+
const request: QueryRequest = {
|
|
65
|
+
...queryValue,
|
|
66
|
+
// Include fieldMap if provided (for server-side field mapping)
|
|
67
|
+
...(fieldMap && {fieldMap})
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const response = await client.post(
|
|
71
|
+
`${url}/list`,
|
|
72
|
+
request,
|
|
73
|
+
{'Content-Type': 'application/json'}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return response as QueryResponse;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error instanceof SyntaxError) {
|
|
79
|
+
throw new Error(`Invalid query JSON: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`Raw query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Execute a query from a JSON object (useful for dynamic queries)
|
|
86
|
+
static async queryFromJson(
|
|
87
|
+
queryObject: any,
|
|
88
|
+
httpClient?: HttpClient,
|
|
89
|
+
serverUrl?: string
|
|
90
|
+
): Promise<QueryResponse> {
|
|
91
|
+
const client = httpClient || this.httpClient;
|
|
92
|
+
const url = serverUrl || this.serverUrl;
|
|
93
|
+
|
|
94
|
+
if (!client) {
|
|
95
|
+
throw new Error('HTTP client is required for JSON query execution');
|
|
96
|
+
}
|
|
97
|
+
if (!url) {
|
|
98
|
+
throw new Error('Server URL is required for JSON query execution');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const request: QueryRequest = queryObject
|
|
103
|
+
|
|
104
|
+
const response = await client.post(
|
|
105
|
+
`${url}/list`,
|
|
106
|
+
request,
|
|
107
|
+
{'Content-Type': 'application/json'}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return response as QueryResponse;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw new Error(`JSON query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Health check for the server
|
|
117
|
+
static async healthCheck(httpClient?: HttpClient, serverUrl?: string): Promise<boolean> {
|
|
118
|
+
const client = httpClient || this.httpClient;
|
|
119
|
+
const url = serverUrl || this.serverUrl;
|
|
120
|
+
|
|
121
|
+
if (!client || !url) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
await client.post(`${url}/health`, {}, {'Content-Type': 'application/json'});
|
|
127
|
+
return true;
|
|
128
|
+
} catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Get server information
|
|
134
|
+
static async serverInfo(httpClient?: HttpClient, serverUrl?: string): Promise<any> {
|
|
135
|
+
const client = httpClient || this.httpClient;
|
|
136
|
+
const url = serverUrl || this.serverUrl;
|
|
137
|
+
|
|
138
|
+
if (!client) {
|
|
139
|
+
throw new Error('HTTP client is required for server info');
|
|
140
|
+
}
|
|
141
|
+
if (!url) {
|
|
142
|
+
throw new Error('Server URL is required for server info');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await client.post(
|
|
147
|
+
`${url}/info`,
|
|
148
|
+
{},
|
|
149
|
+
{'Content-Type': 'application/json'}
|
|
150
|
+
);
|
|
151
|
+
return response;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`Failed to get server info: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Reset SDK configuration
|
|
158
|
+
static reset(): void {
|
|
159
|
+
this.httpClient = undefined;
|
|
160
|
+
this.serverUrl = undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check if SDK is configured
|
|
164
|
+
static isConfigured(): boolean {
|
|
165
|
+
return this.httpClient !== undefined && this.serverUrl !== undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ===== INDEX MANAGEMENT =====
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Create a regular index on a field for query optimization
|
|
172
|
+
* @param appId - Application ID
|
|
173
|
+
* @param collection - Collection name
|
|
174
|
+
* @param fieldName - Field to index
|
|
175
|
+
* @param options - Optional: store values for fast retrieval
|
|
176
|
+
*/
|
|
177
|
+
static async createIndex(
|
|
178
|
+
appId: string,
|
|
179
|
+
collection: string,
|
|
180
|
+
fieldName: string,
|
|
181
|
+
options?: {
|
|
182
|
+
storeValues?: boolean;
|
|
183
|
+
}
|
|
184
|
+
): Promise<any> {
|
|
185
|
+
const client = this.httpClient;
|
|
186
|
+
const url = this.serverUrl;
|
|
187
|
+
|
|
188
|
+
if (!client) {
|
|
189
|
+
throw new Error('HTTP client is required for index creation');
|
|
190
|
+
}
|
|
191
|
+
if (!url) {
|
|
192
|
+
throw new Error('Server URL is required for index creation');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const request = {
|
|
196
|
+
app_id: appId,
|
|
197
|
+
collection_name: collection,
|
|
198
|
+
field_name: fieldName,
|
|
199
|
+
index_config: {
|
|
200
|
+
index_type: "Secondary",
|
|
201
|
+
store_values: options?.storeValues !== undefined ? options?.storeValues : true,
|
|
202
|
+
compression: "None",
|
|
203
|
+
cache_priority: "Medium",
|
|
204
|
+
relationship_hints: [],
|
|
205
|
+
performance_tuning: {
|
|
206
|
+
memory_limit_mb: null,
|
|
207
|
+
cache_size_entries: null,
|
|
208
|
+
prefetch_depth: null,
|
|
209
|
+
update_batch_size: null,
|
|
210
|
+
background_optimization: true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const headers: Record<string, string> = {'Content-Type': 'application/json'};
|
|
216
|
+
if (this.apiKey) {
|
|
217
|
+
headers['X-API-Key'] = this.apiKey;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const response = await client.post(
|
|
222
|
+
`${url}/api/apps/${appId}/collections/${collection}/indexes`,
|
|
223
|
+
request,
|
|
224
|
+
headers
|
|
225
|
+
);
|
|
226
|
+
return response;
|
|
227
|
+
} catch (error) {
|
|
228
|
+
throw new Error(`Index creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Create a unique index on a field (acts as PRIMARY KEY)
|
|
234
|
+
* Ensures no duplicate values for this field and enables automatic version deduplication
|
|
235
|
+
* @param appId - Application ID
|
|
236
|
+
* @param collection - Collection name
|
|
237
|
+
* @param fieldName - Field to index with unique constraint
|
|
238
|
+
* @param options - Optional: store values for fast retrieval
|
|
239
|
+
*/
|
|
240
|
+
static async createUniqueIndex(
|
|
241
|
+
appId: string,
|
|
242
|
+
collection: string,
|
|
243
|
+
fieldName: string,
|
|
244
|
+
options?: {
|
|
245
|
+
storeValues?: boolean;
|
|
246
|
+
}
|
|
247
|
+
): Promise<any> {
|
|
248
|
+
const client = this.httpClient;
|
|
249
|
+
const url = this.serverUrl;
|
|
250
|
+
|
|
251
|
+
if (!client) {
|
|
252
|
+
throw new Error('HTTP client is required for index creation');
|
|
253
|
+
}
|
|
254
|
+
if (!url) {
|
|
255
|
+
throw new Error('Server URL is required for index creation');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const request = {
|
|
259
|
+
app_id: appId,
|
|
260
|
+
collection_name: collection,
|
|
261
|
+
field_name: fieldName,
|
|
262
|
+
index_config: {
|
|
263
|
+
index_type: "Primary", // Primary = unique constraint
|
|
264
|
+
store_values: options?.storeValues !== undefined ? options?.storeValues : true,
|
|
265
|
+
compression: "None",
|
|
266
|
+
cache_priority: "Medium",
|
|
267
|
+
relationship_hints: [],
|
|
268
|
+
performance_tuning: {
|
|
269
|
+
memory_limit_mb: null,
|
|
270
|
+
cache_size_entries: null,
|
|
271
|
+
prefetch_depth: null,
|
|
272
|
+
update_batch_size: null,
|
|
273
|
+
background_optimization: true
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const headers: Record<string, string> = {'Content-Type': 'application/json'};
|
|
279
|
+
if (this.apiKey) {
|
|
280
|
+
headers['X-API-Key'] = this.apiKey;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
const response = await client.post(
|
|
285
|
+
`${url}/api/apps/${appId}/collections/${collection}/indexes`,
|
|
286
|
+
request,
|
|
287
|
+
headers
|
|
288
|
+
);
|
|
289
|
+
return response;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
throw new Error(`Index creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|