@xata.io/client
Advanced tools
Comparing version 0.0.0-beta.bbcb88d to 0.0.0-beta.c9e08d0
@@ -57,11 +57,47 @@ export interface XataRecord { | ||
}; | ||
declare type CursorNavigationOptions = { | ||
first?: string; | ||
} | { | ||
last?: string; | ||
} | { | ||
after?: string; | ||
before?: string; | ||
}; | ||
declare type OffsetNavigationOptions = { | ||
size?: number; | ||
offset?: number; | ||
}; | ||
declare type PaginationOptions = CursorNavigationOptions & OffsetNavigationOptions; | ||
declare type BulkQueryOptions<T> = { | ||
filter?: FilterConstraints<T>; | ||
sort?: { | ||
column: keyof T; | ||
direction?: SortDirection; | ||
} | keyof T; | ||
page?: PaginationOptions; | ||
}; | ||
declare type QueryOrConstraint<T, R> = Query<T, R> | Constraint<T>; | ||
export declare class Query<T, R = T> { | ||
declare type QueryMeta = { | ||
page: { | ||
cursor: string; | ||
more: boolean; | ||
}; | ||
}; | ||
interface BasePage<T, R> { | ||
query: Query<T, R>; | ||
meta: QueryMeta; | ||
records: R[]; | ||
nextPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
previousPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
firstPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
lastPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
hasNextPage(): boolean; | ||
} | ||
declare class Page<T, R> implements BasePage<T, R> { | ||
readonly query: Query<T, R>; | ||
readonly meta: QueryMeta; | ||
readonly records: R[]; | ||
constructor(query: Query<T, R>, meta: QueryMeta, records?: R[]); | ||
nextPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
previousPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
firstPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
lastPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
hasNextPage(): boolean; | ||
} | ||
export declare class Query<T, R = T> implements BasePage<T, R> { | ||
table: string; | ||
@@ -74,2 +110,5 @@ repository: Repository<T>; | ||
readonly $sort?: Record<string, SortDirection>; | ||
readonly query: Query<T, R>; | ||
readonly meta: QueryMeta; | ||
readonly records: R[]; | ||
constructor(repository: Repository<T> | null, table: string, data: Partial<Query<T, R>>, parent?: Query<T, R>); | ||
@@ -83,6 +122,14 @@ any(...queries: Query<T, R>[]): Query<T, R>; | ||
sort<F extends keyof T>(column: F, direction: SortDirection): Query<T, R>; | ||
getPaginated(options?: BulkQueryOptions<T>): Promise<Page<T, R>>; | ||
[Symbol.asyncIterator](): AsyncIterableIterator<R>; | ||
getIterator(chunk: number, options?: Omit<BulkQueryOptions<T>, 'page'>): AsyncGenerator<R[]>; | ||
getMany(options?: BulkQueryOptions<T>): Promise<R[]>; | ||
getOne(options?: BulkQueryOptions<T>): Promise<R | null>; | ||
getOne(options?: Omit<BulkQueryOptions<T>, 'page'>): Promise<R | null>; | ||
deleteAll(): Promise<number>; | ||
include(columns: Include<T>): this; | ||
nextPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
previousPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
firstPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
lastPage(size?: number, offset?: number): Promise<Page<T, R>>; | ||
hasNextPage(): boolean; | ||
} | ||
@@ -92,6 +139,7 @@ export declare abstract class Repository<T> extends Query<T, Selectable<T>> { | ||
abstract create(object: Selectable<T>): Promise<T>; | ||
abstract createMany(objects: Selectable<T>[]): Promise<T[]>; | ||
abstract read(id: string): Promise<T | null>; | ||
abstract update(id: string, object: Partial<T>): Promise<T>; | ||
abstract delete(id: string): void; | ||
abstract query<R>(query: Query<T, R>): Promise<R[]>; | ||
abstract _runQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>>; | ||
} | ||
@@ -102,9 +150,10 @@ export declare class RestRepository<T> extends Repository<T> { | ||
constructor(client: BaseClient<any>, table: string); | ||
request(method: string, path: string, body?: unknown): Promise<any>; | ||
request<T>(method: string, path: string, body?: unknown): Promise<T | undefined>; | ||
select<K extends keyof T>(...columns: K[]): Query<T, Select<T, K>>; | ||
create(object: T): Promise<T>; | ||
createMany(objects: T[]): Promise<T[]>; | ||
read(id: string): Promise<T | null>; | ||
update(id: string, object: Partial<T>): Promise<T>; | ||
delete(id: string): Promise<void>; | ||
query<R>(query: Query<T, R>): Promise<R[]>; | ||
_runQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>>; | ||
} | ||
@@ -123,3 +172,3 @@ interface RepositoryFactory { | ||
fetch?: unknown; | ||
databaseURL: string; | ||
databaseURL?: string; | ||
branch: BranchStrategyOption; | ||
@@ -126,0 +175,0 @@ apiKey: string; |
@@ -18,2 +18,14 @@ "use strict"; | ||
}; | ||
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } | ||
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { | ||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); | ||
var g = generator.apply(thisArg, _arguments || []), i, q = []; | ||
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } | ||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } | ||
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } | ||
function fulfill(value) { resume("next", value); } | ||
function reject(value) { resume("throw", value); } | ||
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -59,4 +71,39 @@ exports.XataError = exports.BaseClient = exports.RestRespositoryFactory = exports.RestRepository = exports.Repository = exports.Query = exports.includesAll = exports.includesPattern = exports.includesSubstring = exports.includes = exports.contains = exports.isNot = exports.is = exports.pattern = exports.endsWith = exports.startsWith = exports.notExists = exports.exists = exports.le = exports.lte = exports.lt = exports.gte = exports.ge = exports.gt = void 0; | ||
exports.includesAll = includesAll; | ||
class Page { | ||
constructor(query, meta, records = []) { | ||
this.query = query; | ||
this.meta = meta; | ||
this.records = records; | ||
} | ||
nextPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.query.getPaginated({ page: { size, offset, after: this.meta.page.cursor } }); | ||
}); | ||
} | ||
previousPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.query.getPaginated({ page: { size, offset, before: this.meta.page.cursor } }); | ||
}); | ||
} | ||
firstPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.query.getPaginated({ page: { size, offset, first: this.meta.page.cursor } }); | ||
}); | ||
} | ||
lastPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.query.getPaginated({ page: { size, offset, last: this.meta.page.cursor } }); | ||
}); | ||
} | ||
// TODO: We need to add something on the backend if we want a hasPreviousPage | ||
hasNextPage() { | ||
return this.meta.page.more; | ||
} | ||
} | ||
class Query { | ||
constructor(repository, table, data, parent) { | ||
// Cursor pagination | ||
this.query = this; | ||
this.meta = { page: { cursor: 'start', more: true } }; | ||
this.records = []; | ||
if (repository) { | ||
@@ -134,15 +181,47 @@ this.repository = repository; | ||
} | ||
// TODO: pagination. Maybe implement different methods for different type of paginations | ||
// and one to simply get the first records returned by the query with no pagination. | ||
getPaginated(options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.repository._runQuery(this, options); | ||
}); | ||
} | ||
[Symbol.asyncIterator]() { | ||
return __asyncGenerator(this, arguments, function* _a() { | ||
var e_1, _b; | ||
try { | ||
for (var _c = __asyncValues(this.getIterator(1)), _d; _d = yield __await(_c.next()), !_d.done;) { | ||
const [record] = _d.value; | ||
yield yield __await(record); | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_d && !_d.done && (_b = _c.return)) yield __await(_b.call(_c)); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}); | ||
} | ||
getIterator(chunk, options = {}) { | ||
return __asyncGenerator(this, arguments, function* getIterator_1() { | ||
let offset = 0; | ||
let end = false; | ||
while (!end) { | ||
const { records, meta } = yield __await(this.getPaginated(Object.assign(Object.assign({}, options), { page: { size: chunk, offset } }))); | ||
yield yield __await(records); | ||
offset += chunk; | ||
end = !meta.page.more; | ||
} | ||
}); | ||
} | ||
getMany(options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// TODO: use options | ||
return this.repository.query(this); | ||
const { records } = yield this.getPaginated(options); | ||
return records; | ||
}); | ||
} | ||
getOne(options) { | ||
getOne(options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// TODO: use options | ||
const arr = yield this.getMany(); // TODO, limit to 1 | ||
return arr[0] || null; | ||
const records = yield this.getMany(Object.assign(Object.assign({}, options), { page: { size: 1 } })); | ||
return records[0] || null; | ||
}); | ||
@@ -152,3 +231,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Return number of affected rows | ||
// TODO: Return number of affected rows | ||
return 0; | ||
@@ -161,2 +240,25 @@ }); | ||
} | ||
nextPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.firstPage(size, offset); | ||
}); | ||
} | ||
previousPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.firstPage(size, offset); | ||
}); | ||
} | ||
firstPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.getPaginated({ page: { size, offset } }); | ||
}); | ||
} | ||
lastPage(size, offset) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.getPaginated({ page: { size, offset, before: 'end' } }); | ||
}); | ||
} | ||
hasNextPage() { | ||
return this.meta.page.more; | ||
} | ||
} | ||
@@ -219,3 +321,3 @@ exports.Query = Query; | ||
if (resp.status === 204) | ||
return; | ||
return undefined; | ||
return resp.json(); | ||
@@ -229,18 +331,36 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const body = Object.assign({}, object); | ||
for (const key of Object.keys(body)) { | ||
const value = body[key]; | ||
if (value && typeof value === 'object' && typeof value.id === 'string') { | ||
body[key] = value.id; | ||
} | ||
const record = transformObjectLinks(object); | ||
const response = yield this.request('POST', `/tables/${this.table}/data`, record); | ||
if (!response) { | ||
throw new Error("The server didn't return any data for the query"); | ||
} | ||
const obj = yield this.request('POST', `/tables/${this.table}/data`, body); | ||
return this.client.initObject(this.table, obj); | ||
const finalObject = yield this.read(response.id); | ||
if (!finalObject) { | ||
throw new Error('The server failed to save the record'); | ||
} | ||
return finalObject; | ||
}); | ||
} | ||
createMany(objects) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const records = objects.map((object) => transformObjectLinks(object)); | ||
const response = yield this.request('POST', `/tables/${this.table}/bulk`, { records }); | ||
if (!response) { | ||
throw new Error("The server didn't return any data for the query"); | ||
} | ||
// TODO: Use filer.$any() to get all the records | ||
const finalObjects = yield Promise.all(response.recordIDs.map((id) => this.read(id))); | ||
if (finalObjects.some((object) => !object)) { | ||
throw new Error('The server failed to save the record'); | ||
} | ||
return finalObjects; | ||
}); | ||
} | ||
read(id) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const obj = yield this.request('GET', `/tables/${this.table}/data/${id}`); | ||
return this.client.initObject(this.table, obj); | ||
const response = yield this.request('GET', `/tables/${this.table}/data/${id}`); | ||
if (!response) | ||
return null; | ||
return this.client.initObject(this.table, response); | ||
} | ||
@@ -256,4 +376,8 @@ catch (err) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const obj = yield this.request('PUT', `/tables/${this.table}/data/${id}`, object); | ||
return this.client.initObject(this.table, obj); | ||
const response = yield this.request('PUT', `/tables/${this.table}/data/${id}`, object); | ||
if (!response) { | ||
throw new Error("The server didn't return any data for the query"); | ||
} | ||
// TODO: Review this, not sure we are properly initializing the object | ||
return this.client.initObject(this.table, response); | ||
}); | ||
@@ -266,3 +390,3 @@ } | ||
} | ||
query(query) { | ||
_runQuery(query, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -277,6 +401,12 @@ const filter = { | ||
filter: Object.values(filter).some(Boolean) ? filter : undefined, | ||
sort: query.$sort | ||
sort: query.$sort, | ||
page: options === null || options === void 0 ? void 0 : options.page | ||
}; | ||
const result = yield this.request('POST', `/tables/${this.table}/query`, body); | ||
return result.records.map((record) => this.client.initObject(this.table, record)); | ||
const response = yield this.request('POST', `/tables/${this.table}/query`, body); | ||
if (!response) { | ||
throw new Error("The server didn't return any data for the query"); | ||
} | ||
const { meta, records: objects } = response; | ||
const records = objects.map((record) => this.client.initObject(this.table, record)); | ||
return new Page(query, meta, records); | ||
}); | ||
@@ -340,3 +470,3 @@ } | ||
getBranch() { | ||
var e_1, _a; | ||
var e_2, _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -360,3 +490,3 @@ if (this.branch) | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
@@ -366,3 +496,3 @@ try { | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
@@ -384,1 +514,10 @@ throw new Error('Unable to resolve branch value'); | ||
}; | ||
// TODO: We can find a better implementation for links | ||
const transformObjectLinks = (object) => { | ||
return Object.entries(object).reduce((acc, [key, value]) => { | ||
if (value && typeof value === 'object' && typeof value.id === 'string') { | ||
return Object.assign(Object.assign({}, acc), { [key]: value.id }); | ||
} | ||
return Object.assign(Object.assign({}, acc), { [key]: value }); | ||
}, {}); | ||
}; |
{ | ||
"name": "@xata.io/client", | ||
"version": "0.0.0-beta.bbcb88d", | ||
"version": "0.0.0-beta.c9e08d0", | ||
"description": "Xata.io SDK for TypeScript and JavaScript", | ||
@@ -9,3 +9,3 @@ "main": "./dist/index.js", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"build": "tsc", | ||
"build": "tsc -p tsconfig.build.json", | ||
"prepack": "npm run build" | ||
@@ -24,3 +24,3 @@ }, | ||
"homepage": "https://github.com/xataio/client-ts/blob/main/client/README.md", | ||
"gitHead": "bbcb88d6cb878b39c43ee6c564496f362796baa9" | ||
"gitHead": "c9e08d07e1a7e7b07d118b2b459b9843edb341c3" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
0
3
42346
7
707