@ekodb/ekodb-client 0.7.1 → 0.8.0
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/dist/client.d.ts +179 -12
- package/dist/client.js +256 -31
- package/dist/client.test.d.ts +7 -0
- package/dist/client.test.js +702 -0
- package/dist/search.d.ts +12 -0
- package/dist/search.js +14 -0
- package/package.json +1 -1
- package/src/client.test.ts +961 -0
- package/src/client.ts +366 -41
- package/src/search.ts +22 -0
package/src/client.ts
CHANGED
|
@@ -78,6 +78,62 @@ export interface BatchOperationResult {
|
|
|
78
78
|
failed: Array<{ id?: string; error: string }>;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// ========== Operation Options Interfaces ==========
|
|
82
|
+
|
|
83
|
+
export interface InsertOptions {
|
|
84
|
+
ttl?: string;
|
|
85
|
+
bypassRipple?: boolean;
|
|
86
|
+
transactionId?: string;
|
|
87
|
+
bypassCache?: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface UpdateOptions {
|
|
91
|
+
bypassRipple?: boolean;
|
|
92
|
+
transactionId?: string;
|
|
93
|
+
bypassCache?: boolean;
|
|
94
|
+
selectFields?: string[];
|
|
95
|
+
excludeFields?: string[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface DeleteOptions {
|
|
99
|
+
bypassRipple?: boolean;
|
|
100
|
+
transactionId?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface UpsertOptions {
|
|
104
|
+
ttl?: string;
|
|
105
|
+
bypassRipple?: boolean;
|
|
106
|
+
transactionId?: string;
|
|
107
|
+
bypassCache?: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface FindOptions {
|
|
111
|
+
filter?: any;
|
|
112
|
+
sort?: any;
|
|
113
|
+
limit?: number;
|
|
114
|
+
skip?: number;
|
|
115
|
+
join?: any;
|
|
116
|
+
bypassRipple?: boolean;
|
|
117
|
+
bypassCache?: boolean;
|
|
118
|
+
selectFields?: string[];
|
|
119
|
+
excludeFields?: string[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface BatchInsertOptions {
|
|
123
|
+
bypassRipple?: boolean;
|
|
124
|
+
transactionId?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface BatchUpdateOptions {
|
|
128
|
+
bypassRipple?: boolean;
|
|
129
|
+
transactionId?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface BatchDeleteOptions {
|
|
133
|
+
bypassRipple?: boolean;
|
|
134
|
+
transactionId?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
81
137
|
// ========== Chat Interfaces ==========
|
|
82
138
|
|
|
83
139
|
export interface CollectionConfig {
|
|
@@ -254,7 +310,16 @@ export class EkoDBClient {
|
|
|
254
310
|
});
|
|
255
311
|
|
|
256
312
|
if (!response.ok) {
|
|
257
|
-
|
|
313
|
+
let errorMsg = `Auth failed with status: ${response.status}`;
|
|
314
|
+
try {
|
|
315
|
+
const errorBody = (await response.json()) as { error?: string };
|
|
316
|
+
if (errorBody.error) {
|
|
317
|
+
errorMsg = errorBody.error;
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
// Ignore JSON parse errors, use default message
|
|
321
|
+
}
|
|
322
|
+
throw new Error(errorMsg);
|
|
258
323
|
}
|
|
259
324
|
|
|
260
325
|
const result = (await response.json()) as { token: string };
|
|
@@ -443,18 +508,31 @@ export class EkoDBClient {
|
|
|
443
508
|
* Insert a document into a collection
|
|
444
509
|
* @param collection - Collection name
|
|
445
510
|
* @param record - Document to insert
|
|
446
|
-
* @param
|
|
511
|
+
* @param options - Optional parameters (ttl, bypassRipple, transactionId, bypassCache)
|
|
447
512
|
*/
|
|
448
513
|
async insert(
|
|
449
514
|
collection: string,
|
|
450
515
|
record: Record,
|
|
451
|
-
|
|
516
|
+
options?: InsertOptions,
|
|
452
517
|
): Promise<Record> {
|
|
453
518
|
const data = { ...record };
|
|
454
|
-
if (ttl) {
|
|
455
|
-
data.ttl = ttl;
|
|
519
|
+
if (options?.ttl) {
|
|
520
|
+
data.ttl = options.ttl;
|
|
456
521
|
}
|
|
457
|
-
|
|
522
|
+
|
|
523
|
+
const params = new URLSearchParams();
|
|
524
|
+
if (options?.bypassRipple !== undefined) {
|
|
525
|
+
params.append("bypass_ripple", String(options.bypassRipple));
|
|
526
|
+
}
|
|
527
|
+
if (options?.transactionId) {
|
|
528
|
+
params.append("transaction_id", options.transactionId);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const url = params.toString()
|
|
532
|
+
? `/api/insert/${collection}?${params.toString()}`
|
|
533
|
+
: `/api/insert/${collection}`;
|
|
534
|
+
|
|
535
|
+
return this.makeRequest<Record>("POST", url, data);
|
|
458
536
|
}
|
|
459
537
|
|
|
460
538
|
/**
|
|
@@ -500,43 +578,83 @@ export class EkoDBClient {
|
|
|
500
578
|
|
|
501
579
|
/**
|
|
502
580
|
* Update a document
|
|
581
|
+
* @param collection - Collection name
|
|
582
|
+
* @param id - Document ID
|
|
583
|
+
* @param record - Update data
|
|
584
|
+
* @param options - Optional parameters (bypassRipple, transactionId, bypassCache, selectFields, excludeFields)
|
|
503
585
|
*/
|
|
504
586
|
async update(
|
|
505
587
|
collection: string,
|
|
506
588
|
id: string,
|
|
507
589
|
record: Record,
|
|
590
|
+
options?: UpdateOptions,
|
|
508
591
|
): Promise<Record> {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
)
|
|
592
|
+
const params = new URLSearchParams();
|
|
593
|
+
if (options?.bypassRipple !== undefined) {
|
|
594
|
+
params.append("bypass_ripple", String(options.bypassRipple));
|
|
595
|
+
}
|
|
596
|
+
if (options?.transactionId) {
|
|
597
|
+
params.append("transaction_id", options.transactionId);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const url = params.toString()
|
|
601
|
+
? `/api/update/${collection}/${id}?${params.toString()}`
|
|
602
|
+
: `/api/update/${collection}/${id}`;
|
|
603
|
+
|
|
604
|
+
return this.makeRequest<Record>("PUT", url, record);
|
|
514
605
|
}
|
|
515
606
|
|
|
516
607
|
/**
|
|
517
608
|
* Delete a document
|
|
609
|
+
* @param collection - Collection name
|
|
610
|
+
* @param id - Document ID
|
|
611
|
+
* @param options - Optional parameters (bypassRipple, transactionId)
|
|
518
612
|
*/
|
|
519
|
-
async delete(
|
|
520
|
-
|
|
613
|
+
async delete(
|
|
614
|
+
collection: string,
|
|
615
|
+
id: string,
|
|
616
|
+
options?: DeleteOptions,
|
|
617
|
+
): Promise<void> {
|
|
618
|
+
const params = new URLSearchParams();
|
|
619
|
+
if (options?.bypassRipple !== undefined) {
|
|
620
|
+
params.append("bypass_ripple", String(options.bypassRipple));
|
|
621
|
+
}
|
|
622
|
+
if (options?.transactionId) {
|
|
623
|
+
params.append("transaction_id", options.transactionId);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const url = params.toString()
|
|
627
|
+
? `/api/delete/${collection}/${id}?${params.toString()}`
|
|
628
|
+
: `/api/delete/${collection}/${id}`;
|
|
629
|
+
|
|
630
|
+
await this.makeRequest<void>("DELETE", url);
|
|
521
631
|
}
|
|
522
632
|
|
|
523
633
|
/**
|
|
524
634
|
* Batch insert multiple documents
|
|
635
|
+
* @param collection - Collection name
|
|
636
|
+
* @param records - Array of documents to insert
|
|
637
|
+
* @param options - Optional parameters (bypassRipple, transactionId)
|
|
525
638
|
*/
|
|
526
639
|
async batchInsert(
|
|
527
640
|
collection: string,
|
|
528
641
|
records: Record[],
|
|
529
|
-
|
|
642
|
+
options?: BatchInsertOptions,
|
|
530
643
|
): Promise<BatchOperationResult> {
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
bypass_ripple
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
"
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
);
|
|
644
|
+
const params = new URLSearchParams();
|
|
645
|
+
if (options?.bypassRipple !== undefined) {
|
|
646
|
+
params.append("bypass_ripple", String(options.bypassRipple));
|
|
647
|
+
}
|
|
648
|
+
if (options?.transactionId) {
|
|
649
|
+
params.append("transaction_id", options.transactionId);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const inserts = records.map((data) => ({ data }));
|
|
653
|
+
const url = params.toString()
|
|
654
|
+
? `/api/batch/insert/${collection}?${params.toString()}`
|
|
655
|
+
: `/api/batch/insert/${collection}`;
|
|
656
|
+
|
|
657
|
+
return this.makeRequest<BatchOperationResult>("POST", url, { inserts });
|
|
540
658
|
}
|
|
541
659
|
|
|
542
660
|
/**
|
|
@@ -734,6 +852,159 @@ export class EkoDBClient {
|
|
|
734
852
|
);
|
|
735
853
|
}
|
|
736
854
|
|
|
855
|
+
// ============================================================================
|
|
856
|
+
// Convenience Methods
|
|
857
|
+
// ============================================================================
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Insert or update a record (upsert operation)
|
|
861
|
+
*
|
|
862
|
+
* Attempts to update the record first. If the record doesn't exist (404 error),
|
|
863
|
+
* it will be inserted instead. This provides atomic insert-or-update semantics.
|
|
864
|
+
*
|
|
865
|
+
* @param collection - Collection name
|
|
866
|
+
* @param id - Record ID
|
|
867
|
+
* @param record - Record data to insert or update
|
|
868
|
+
* @param bypassRipple - Optional flag to bypass ripple effects
|
|
869
|
+
* @returns The inserted or updated record
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* ```typescript
|
|
873
|
+
* const record = { name: "John Doe", email: "john@example.com" };
|
|
874
|
+
* // Will update if exists, insert if not
|
|
875
|
+
* const result = await client.upsert("users", "user123", record);
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
/**
|
|
879
|
+
* Upsert a document (insert or update)
|
|
880
|
+
* @param collection - Collection name
|
|
881
|
+
* @param id - Document ID
|
|
882
|
+
* @param record - Document data
|
|
883
|
+
* @param options - Optional parameters (ttl, bypassRipple, transactionId, bypassCache)
|
|
884
|
+
*/
|
|
885
|
+
async upsert(
|
|
886
|
+
collection: string,
|
|
887
|
+
id: string,
|
|
888
|
+
record: Record,
|
|
889
|
+
options?: UpsertOptions,
|
|
890
|
+
): Promise<Record> {
|
|
891
|
+
try {
|
|
892
|
+
// Try update first
|
|
893
|
+
return await this.update(collection, id, record, {
|
|
894
|
+
bypassRipple: options?.bypassRipple,
|
|
895
|
+
transactionId: options?.transactionId,
|
|
896
|
+
bypassCache: options?.bypassCache,
|
|
897
|
+
});
|
|
898
|
+
} catch (error: any) {
|
|
899
|
+
// If not found, insert instead
|
|
900
|
+
if (
|
|
901
|
+
error.message?.includes("404") ||
|
|
902
|
+
error.message?.includes("Not found")
|
|
903
|
+
) {
|
|
904
|
+
return await this.insert(collection, record, {
|
|
905
|
+
ttl: options?.ttl,
|
|
906
|
+
bypassRipple: options?.bypassRipple,
|
|
907
|
+
transactionId: options?.transactionId,
|
|
908
|
+
bypassCache: options?.bypassCache,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
throw error;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Find a single record by field value
|
|
917
|
+
*
|
|
918
|
+
* Convenience method for finding one record matching a specific field value.
|
|
919
|
+
* Returns null if no record matches, or the first matching record.
|
|
920
|
+
*
|
|
921
|
+
* @param collection - Collection name
|
|
922
|
+
* @param field - Field name to search
|
|
923
|
+
* @param value - Value to match
|
|
924
|
+
* @returns The matching record or null if not found
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```typescript
|
|
928
|
+
* // Find user by email
|
|
929
|
+
* const user = await client.findOne("users", "email", "john@example.com");
|
|
930
|
+
* if (user) {
|
|
931
|
+
* console.log("Found user:", user);
|
|
932
|
+
* }
|
|
933
|
+
* ```
|
|
934
|
+
*/
|
|
935
|
+
async findOne(
|
|
936
|
+
collection: string,
|
|
937
|
+
field: string,
|
|
938
|
+
value: any,
|
|
939
|
+
): Promise<Record | null> {
|
|
940
|
+
const query = new QueryBuilder().eq(field, value).limit(1).build();
|
|
941
|
+
const results = await this.find(collection, query);
|
|
942
|
+
return results.length > 0 ? results[0] : null;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Check if a record exists by ID
|
|
947
|
+
*
|
|
948
|
+
* This is more efficient than fetching the record when you only need to check existence.
|
|
949
|
+
*
|
|
950
|
+
* @param collection - Collection name
|
|
951
|
+
* @param id - Record ID to check
|
|
952
|
+
* @returns true if the record exists, false if it doesn't
|
|
953
|
+
*
|
|
954
|
+
* @example
|
|
955
|
+
* ```typescript
|
|
956
|
+
* if (await client.exists("users", "user123")) {
|
|
957
|
+
* console.log("User exists");
|
|
958
|
+
* } else {
|
|
959
|
+
* console.log("User not found");
|
|
960
|
+
* }
|
|
961
|
+
* ```
|
|
962
|
+
*/
|
|
963
|
+
async exists(collection: string, id: string): Promise<boolean> {
|
|
964
|
+
try {
|
|
965
|
+
await this.findById(collection, id);
|
|
966
|
+
return true;
|
|
967
|
+
} catch (error: any) {
|
|
968
|
+
if (
|
|
969
|
+
error.message?.includes("404") ||
|
|
970
|
+
error.message?.includes("Not found")
|
|
971
|
+
) {
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
throw error;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Paginate through records
|
|
980
|
+
*
|
|
981
|
+
* Convenience method for pagination with page numbers (1-indexed).
|
|
982
|
+
*
|
|
983
|
+
* @param collection - Collection name
|
|
984
|
+
* @param page - Page number (1-indexed, i.e., first page is 1)
|
|
985
|
+
* @param pageSize - Number of records per page
|
|
986
|
+
* @returns Array of records for the requested page
|
|
987
|
+
*
|
|
988
|
+
* @example
|
|
989
|
+
* ```typescript
|
|
990
|
+
* // Get page 2 with 10 records per page
|
|
991
|
+
* const records = await client.paginate("users", 2, 10);
|
|
992
|
+
* ```
|
|
993
|
+
*/
|
|
994
|
+
async paginate(
|
|
995
|
+
collection: string,
|
|
996
|
+
page: number,
|
|
997
|
+
pageSize: number,
|
|
998
|
+
): Promise<Record[]> {
|
|
999
|
+
// Page 1 = skip 0, Page 2 = skip pageSize, etc.
|
|
1000
|
+
const skip = page > 0 ? (page - 1) * pageSize : 0;
|
|
1001
|
+
const query: QueryBuilderQuery = {
|
|
1002
|
+
limit: pageSize,
|
|
1003
|
+
skip: skip,
|
|
1004
|
+
};
|
|
1005
|
+
return this.find(collection, query);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
737
1008
|
/**
|
|
738
1009
|
* List all collections
|
|
739
1010
|
*/
|
|
@@ -761,6 +1032,43 @@ export class EkoDBClient {
|
|
|
761
1032
|
);
|
|
762
1033
|
}
|
|
763
1034
|
|
|
1035
|
+
/**
|
|
1036
|
+
* Restore a deleted record from trash
|
|
1037
|
+
* Records remain in trash for 30 days before permanent deletion
|
|
1038
|
+
*
|
|
1039
|
+
* @param collection - Collection name
|
|
1040
|
+
* @param id - Record ID to restore
|
|
1041
|
+
* @returns true if restored successfully
|
|
1042
|
+
*/
|
|
1043
|
+
async restoreRecord(collection: string, id: string): Promise<boolean> {
|
|
1044
|
+
const result = await this.makeRequest<{ status: string }>(
|
|
1045
|
+
"POST",
|
|
1046
|
+
`/api/trash/${collection}/${id}`,
|
|
1047
|
+
undefined,
|
|
1048
|
+
0,
|
|
1049
|
+
true,
|
|
1050
|
+
);
|
|
1051
|
+
return result.status === "restored";
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Restore all deleted records in a collection from trash
|
|
1056
|
+
* Records remain in trash for 30 days before permanent deletion
|
|
1057
|
+
*
|
|
1058
|
+
* @param collection - Collection name
|
|
1059
|
+
* @returns Number of records restored
|
|
1060
|
+
*/
|
|
1061
|
+
async restoreCollection(
|
|
1062
|
+
collection: string,
|
|
1063
|
+
): Promise<{ recordsRestored: number }> {
|
|
1064
|
+
const result = await this.makeRequest<{
|
|
1065
|
+
status: string;
|
|
1066
|
+
collection: string;
|
|
1067
|
+
records_restored: number;
|
|
1068
|
+
}>("POST", `/api/trash/${collection}`, undefined, 0, true);
|
|
1069
|
+
return { recordsRestored: result.records_restored };
|
|
1070
|
+
}
|
|
1071
|
+
|
|
764
1072
|
/**
|
|
765
1073
|
* Create a collection with schema
|
|
766
1074
|
*
|
|
@@ -853,21 +1161,36 @@ export class EkoDBClient {
|
|
|
853
1161
|
*/
|
|
854
1162
|
async search(
|
|
855
1163
|
collection: string,
|
|
856
|
-
|
|
1164
|
+
query: SearchQuery,
|
|
857
1165
|
): Promise<SearchResponse> {
|
|
858
|
-
|
|
859
|
-
searchQuery instanceof SearchQueryBuilder
|
|
860
|
-
? searchQuery.build()
|
|
861
|
-
: searchQuery;
|
|
1166
|
+
// Ensure all parameters from SearchQuery are sent to server
|
|
862
1167
|
return this.makeRequest<SearchResponse>(
|
|
863
1168
|
"POST",
|
|
864
1169
|
`/api/search/${collection}`,
|
|
865
|
-
|
|
1170
|
+
query,
|
|
866
1171
|
0,
|
|
867
1172
|
true, // Force JSON for search operations
|
|
868
1173
|
);
|
|
869
1174
|
}
|
|
870
1175
|
|
|
1176
|
+
/**
|
|
1177
|
+
* Health check - verify the ekoDB server is responding
|
|
1178
|
+
*/
|
|
1179
|
+
async health(): Promise<boolean> {
|
|
1180
|
+
try {
|
|
1181
|
+
const result = await this.makeRequest<{ status: string }>(
|
|
1182
|
+
"GET",
|
|
1183
|
+
"/api/health",
|
|
1184
|
+
undefined,
|
|
1185
|
+
0,
|
|
1186
|
+
true,
|
|
1187
|
+
);
|
|
1188
|
+
return result.status === "ok";
|
|
1189
|
+
} catch {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
871
1194
|
// ========== Chat Methods ==========
|
|
872
1195
|
|
|
873
1196
|
/**
|
|
@@ -1233,31 +1556,33 @@ export class EkoDBClient {
|
|
|
1233
1556
|
* Simplified text search with full-text matching, fuzzy search, and stemming.
|
|
1234
1557
|
*
|
|
1235
1558
|
* @param collection - Collection name to search
|
|
1236
|
-
* @param
|
|
1237
|
-
* @param
|
|
1238
|
-
* @returns
|
|
1559
|
+
* @param query - Search query text
|
|
1560
|
+
* @param options - Additional search options
|
|
1561
|
+
* @returns Search response with results and metadata
|
|
1239
1562
|
*
|
|
1240
1563
|
* @example
|
|
1241
1564
|
* ```typescript
|
|
1242
1565
|
* const results = await client.textSearch(
|
|
1243
1566
|
* "documents",
|
|
1244
1567
|
* "ownership system",
|
|
1245
|
-
*
|
|
1568
|
+
* {
|
|
1569
|
+
* limit: 10,
|
|
1570
|
+
* select_fields: ["title", "content"],
|
|
1571
|
+
* exclude_fields: ["author"]
|
|
1572
|
+
* }
|
|
1246
1573
|
* );
|
|
1247
1574
|
* ```
|
|
1248
1575
|
*/
|
|
1249
1576
|
async textSearch(
|
|
1250
1577
|
collection: string,
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
): Promise<
|
|
1578
|
+
query: string,
|
|
1579
|
+
options?: Partial<SearchQuery>,
|
|
1580
|
+
): Promise<SearchResponse> {
|
|
1254
1581
|
const searchQuery: SearchQuery = {
|
|
1255
|
-
query
|
|
1256
|
-
|
|
1582
|
+
query,
|
|
1583
|
+
...options,
|
|
1257
1584
|
};
|
|
1258
|
-
|
|
1259
|
-
const response = await this.search(collection, searchQuery);
|
|
1260
|
-
return response.results.map((r) => r.record);
|
|
1585
|
+
return this.search(collection, searchQuery);
|
|
1261
1586
|
}
|
|
1262
1587
|
|
|
1263
1588
|
/**
|
package/src/search.ts
CHANGED
|
@@ -53,6 +53,12 @@ export interface SearchQuery {
|
|
|
53
53
|
text_weight?: number;
|
|
54
54
|
/** Weight for vector search (0.0-1.0) */
|
|
55
55
|
vector_weight?: number;
|
|
56
|
+
|
|
57
|
+
// Field projection parameters
|
|
58
|
+
/** Only return these fields (plus 'id') */
|
|
59
|
+
select_fields?: string[];
|
|
60
|
+
/** Exclude these fields from results */
|
|
61
|
+
exclude_fields?: string[];
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/**
|
|
@@ -253,6 +259,22 @@ export class SearchQueryBuilder {
|
|
|
253
259
|
return this;
|
|
254
260
|
}
|
|
255
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Select specific fields to return
|
|
264
|
+
*/
|
|
265
|
+
selectFields(fields: string[]): this {
|
|
266
|
+
this.query.select_fields = fields;
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Exclude specific fields from results
|
|
272
|
+
*/
|
|
273
|
+
excludeFields(fields: string[]): this {
|
|
274
|
+
this.query.exclude_fields = fields;
|
|
275
|
+
return this;
|
|
276
|
+
}
|
|
277
|
+
|
|
256
278
|
/**
|
|
257
279
|
* Build the final SearchQuery object
|
|
258
280
|
*/
|