Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@xata.io/client

Package Overview
Dependencies
Maintainers
4
Versions
4351
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xata.io/client - npm Package Compare versions

Comparing version 0.0.0-alpha.28117a9 to 0.0.0-alpha.2b59725

67

dist/index.d.ts

@@ -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(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
previousPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
firstPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
lastPage(options?: OffsetNavigationOptions): 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(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
previousPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
firstPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
lastPage(options?: OffsetNavigationOptions): 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,12 @@ 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>>;
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(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
previousPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
firstPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
lastPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
hasNextPage(): boolean;
}

@@ -92,6 +137,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 executeQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>>;
}

@@ -102,9 +148,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(records: 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[]>;
executeQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>>;
}

@@ -111,0 +158,0 @@ interface RepositoryFactory {

@@ -57,4 +57,43 @@ "use strict";

exports.includesAll = includesAll;
class Page {
constructor(query, meta, records = []) {
this.query = query;
this.meta = meta;
this.records = records;
}
nextPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, after: this.meta.page.cursor } });
});
}
previousPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, before: this.meta.page.cursor } });
});
}
firstPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, first: this.meta.page.cursor } });
});
}
lastPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size, offset } = options;
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) {

@@ -132,15 +171,17 @@ 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.executeQuery(this, options);
});
}
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;
});

@@ -150,3 +191,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
// Return number of affected rows
// TODO: Return number of affected rows
return 0;

@@ -159,2 +200,27 @@ });

}
nextPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
return this.firstPage(options);
});
}
previousPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
return this.firstPage(options);
});
}
firstPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size } = options;
return this.getPaginated({ page: { size, offset: 0 } });
});
}
lastPage(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { size } = options;
return this.getPaginated({ page: { size, before: 'end' } });
});
}
hasNextPage() {
return this.meta.page.more;
}
}

@@ -226,3 +292,3 @@ exports.Query = Query;

if (resp.status === 204)
return;
return undefined;
return resp.json();

@@ -243,11 +309,28 @@ });

}
const obj = yield this.request('POST', `/tables/${this.table}/data`, body);
return this.client.initObject(this.table, obj);
const response = yield this.request('POST', `/tables/${this.table}/data`, body);
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);
});
}
createMany(records) {
return __awaiter(this, void 0, void 0, function* () {
// TODO: Review the id of the records
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: Review this, not sure we are properly initializing the object
return response.recordIDs.map((record) => this.client.initObject(this.table, { id: record }));
});
}
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);
}

@@ -263,4 +346,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);
});

@@ -270,6 +357,7 @@ }

return __awaiter(this, void 0, void 0, function* () {
// TODO: Return boolean?
yield this.request('DELETE', `/tables/${this.table}/data/${id}`);
});
}
query(query) {
executeQuery(query, options) {
return __awaiter(this, void 0, void 0, function* () {

@@ -284,6 +372,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);
});

@@ -290,0 +384,0 @@ }

18

dist/index.test.js

@@ -234,3 +234,6 @@ "use strict";

const expected = { method: 'POST', path: '/tables/users/query', body: {} };
expectRequest(users, expected, () => users.getMany(), { records: [] });
expectRequest(users, expected, () => users.getMany(), {
records: [],
meta: { page: { cursor: '', more: false } }
});
}));

@@ -240,3 +243,6 @@ test('query with one filter', () => __awaiter(void 0, void 0, void 0, function* () {

const expected = { method: 'POST', path: '/tables/users/query', body: { filter: { $all: [{ name: 'foo' }] } } };
expectRequest(users, expected, () => users.filter('name', 'foo').getMany(), { records: [] });
expectRequest(users, expected, () => users.filter('name', 'foo').getMany(), {
records: [],
meta: { page: { cursor: '', more: false } }
});
}));

@@ -247,4 +253,4 @@ });

const { users } = buildClient();
const result = { records: [{ id: '1234' }] };
const expected = { method: 'POST', path: '/tables/users/query', body: {} };
const result = { records: [{ id: '1234' }], meta: { page: { cursor: '', more: false } } };
const expected = { method: 'POST', path: '/tables/users/query', body: { page: { size: 1 } } };
expectRequest(users, expected, () => __awaiter(void 0, void 0, void 0, function* () {

@@ -257,4 +263,4 @@ const first = yield users.select().getOne();

const { users } = buildClient();
const result = { records: [] };
const expected = { method: 'POST', path: '/tables/users/query', body: {} };
const result = { records: [], meta: { page: { cursor: '', more: false } } };
const expected = { method: 'POST', path: '/tables/users/query', body: { page: { size: 1 } } };
expectRequest(users, expected, () => __awaiter(void 0, void 0, void 0, function* () {

@@ -261,0 +267,0 @@ const first = yield users.getOne();

{
"name": "@xata.io/client",
"version": "0.0.0-alpha.28117a9",
"version": "0.0.0-alpha.2b59725",
"description": "Xata.io SDK for TypeScript and JavaScript",

@@ -23,3 +23,3 @@ "main": "./dist/index.js",

"homepage": "https://github.com/xataio/client-ts/blob/main/client/README.md",
"gitHead": "28117a93dc15003cbf09b3b098a1556ceeed22db"
"gitHead": "2b59725e5305b5f9b4e3f1caccdd17cd5b98a357"
}

@@ -267,3 +267,3 @@ import { BaseClient, RestRepository, XataClientOptions, XataError, XataRecord } from './';

callback: () => void,
response?: unknown
response?: any
) {

@@ -289,3 +289,6 @@ const request = jest.fn(async () => response);

const expected = { method: 'POST', path: '/tables/users/query', body: {} };
expectRequest(users, expected, () => users.getMany(), { records: [] });
expectRequest(users, expected, () => users.getMany(), {
records: [],
meta: { page: { cursor: '', more: false } }
});
});

@@ -297,3 +300,6 @@

const expected = { method: 'POST', path: '/tables/users/query', body: { filter: { $all: [{ name: 'foo' }] } } };
expectRequest(users, expected, () => users.filter('name', 'foo').getMany(), { records: [] });
expectRequest(users, expected, () => users.filter('name', 'foo').getMany(), {
records: [],
meta: { page: { cursor: '', more: false } }
});
});

@@ -306,4 +312,4 @@ });

const result = { records: [{ id: '1234' }] };
const expected = { method: 'POST', path: '/tables/users/query', body: {} };
const result = { records: [{ id: '1234' }], meta: { page: { cursor: '', more: false } } };
const expected = { method: 'POST', path: '/tables/users/query', body: { page: { size: 1 } } };
expectRequest(

@@ -323,4 +329,4 @@ users,

const result = { records: [] };
const expected = { method: 'POST', path: '/tables/users/query', body: {} };
const result = { records: [], meta: { page: { cursor: '', more: false } } };
const expected = { method: 'POST', path: '/tables/users/query', body: { page: { size: 1 } } };
expectRequest(

@@ -327,0 +333,0 @@ users,

@@ -93,3 +93,9 @@ export interface XataRecord {

type CursorNavigationOptions = { first?: string } | { last?: string } | { after?: string; before?: string };
type OffsetNavigationOptions = { size?: number; offset?: number };
type PaginationOptions = CursorNavigationOptions & OffsetNavigationOptions;
type BulkQueryOptions<T> = {
page?: PaginationOptions;
/** TODO: Not implemented yet
filter?: FilterConstraints<T>;

@@ -102,2 +108,3 @@ sort?:

| keyof T;
**/
};

@@ -107,3 +114,55 @@

export class Query<T, R = T> {
type QueryMeta = { page: { cursor: string; more: boolean } };
interface BasePage<T, R> {
query: Query<T, R>;
meta: QueryMeta;
records: R[];
nextPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
previousPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
firstPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
lastPage(options?: OffsetNavigationOptions): Promise<Page<T, R>>;
hasNextPage(): boolean;
}
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[] = []) {
this.query = query;
this.meta = meta;
this.records = records;
}
async nextPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, after: this.meta.page.cursor } });
}
async previousPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, before: this.meta.page.cursor } });
}
async firstPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size, offset } = options;
return this.query.getPaginated({ page: { size, offset, first: this.meta.page.cursor } });
}
async lastPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size, offset } = options;
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(): boolean {
return this.meta.page.more;
}
}
export class Query<T, R = T> implements BasePage<T, R> {
table: string;

@@ -118,2 +177,7 @@ repository: Repository<T>;

// Cursor pagination
readonly query: Query<T, R> = this;
readonly meta: QueryMeta = { page: { cursor: 'start', more: true } };
readonly records: R[] = [];
constructor(repository: Repository<T> | null, table: string, data: Partial<Query<T, R>>, parent?: Query<T, R>) {

@@ -238,17 +302,18 @@ if (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.
async getPaginated(options?: BulkQueryOptions<T>): Promise<Page<T, R>> {
return this.repository.executeQuery(this, options);
}
async getMany(options?: BulkQueryOptions<T>): Promise<R[]> {
// TODO: use options
return this.repository.query(this);
const { records } = await this.getPaginated(options);
return records;
}
async getOne(options?: BulkQueryOptions<T>): Promise<R | null> {
// TODO: use options
const arr = await this.getMany(); // TODO, limit to 1
return arr[0] || null;
async getOne(options: Omit<BulkQueryOptions<T>, 'page'> = {}): Promise<R | null> {
const records = await this.getMany({ ...options, page: { size: 1 } });
return records[0] || null;
}
async deleteAll(): Promise<number> {
// Return number of affected rows
// TODO: Return number of affected rows
return 0;

@@ -261,2 +326,24 @@ }

}
async nextPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
return this.firstPage(options);
}
async previousPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
return this.firstPage(options);
}
async firstPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size } = options;
return this.getPaginated({ page: { size, offset: 0 } });
}
async lastPage(options: OffsetNavigationOptions = {}): Promise<Page<T, R>> {
const { size } = options;
return this.getPaginated({ page: { size, before: 'end' } });
}
hasNextPage(): boolean {
return this.meta.page.more;
}
}

@@ -271,2 +358,4 @@

abstract createMany(objects: Selectable<T>[]): Promise<T[]>;
abstract read(id: string): Promise<T | null>;

@@ -279,3 +368,3 @@

// Used by the Query object internally
abstract query<R>(query: Query<T, R>): Promise<R[]>;
abstract executeQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>>;
}

@@ -314,3 +403,3 @@

async request(method: string, path: string, body?: unknown) {
async request<T>(method: string, path: string, body?: unknown): Promise<T | undefined> {
const { databaseURL, apiKey } = this.client.options;

@@ -328,2 +417,3 @@ const branch = await this.client.getBranch();

});
if (!resp.ok) {

@@ -343,3 +433,4 @@ try {

}
if (resp.status === 204) return;
if (resp.status === 204) return undefined;
return resp.json();

@@ -360,10 +451,37 @@ }

}
const obj = await this.request('POST', `/tables/${this.table}/data`, body);
return this.client.initObject(this.table, obj);
const response = await this.request<{
id: string;
xata: { version: number };
}>('POST', `/tables/${this.table}/data`, body);
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);
}
async createMany(records: T[]): Promise<T[]> {
// TODO: Review the id of the records
const response = await this.request<{
recordIDs: string[];
}>('POST', `/tables/${this.table}/bulk`, { records });
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 response.recordIDs.map((record) => this.client.initObject(this.table, { id: record }));
}
async read(id: string): Promise<T | null> {
try {
const obj = await this.request('GET', `/tables/${this.table}/data/${id}`);
return this.client.initObject(this.table, obj);
const response = await this.request<
T & { id: string; xata: { version: number; table?: string; warnings?: string[] } }
>('GET', `/tables/${this.table}/data/${id}`);
if (!response) return null;
return this.client.initObject(this.table, response);
} catch (err) {

@@ -376,11 +494,20 @@ if ((err as XataError).status === 404) return null;

async update(id: string, object: Partial<T>): Promise<T> {
const obj = await this.request('PUT', `/tables/${this.table}/data/${id}`, object);
return this.client.initObject(this.table, obj);
const response = await this.request<{
id: string;
xata: { version: number };
}>('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);
}
async delete(id: string) {
// TODO: Return boolean?
await this.request('DELETE', `/tables/${this.table}/data/${id}`);
}
async query<R>(query: Query<T, R>): Promise<R[]> {
async executeQuery<R>(query: Query<T, R>, options?: BulkQueryOptions<T>): Promise<Page<T, R>> {
const filter = {

@@ -392,8 +519,21 @@ $any: query.$any,

};
const body = {
filter: Object.values(filter).some(Boolean) ? filter : undefined,
sort: query.$sort
sort: query.$sort,
page: options?.page
};
const result = await this.request('POST', `/tables/${this.table}/query`, body);
return result.records.map((record: object) => this.client.initObject(this.table, record));
const response = await this.request<{
records: object[];
meta: { page: { cursor: string; more: boolean } };
}>('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<R>(this.table, record));
return new Page(query, meta, records);
}

@@ -400,0 +540,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc