mirror of
https://github.com/Warky-Devs/ResolveSpec.git
synced 2025-05-18 12:47:29 +00:00
More clientside ideas
This commit is contained in:
parent
f284e55a5c
commit
6dd6abb2e8
71
resolvespec-js/package.json
Normal file
71
resolvespec-js/package.json
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "@warkypublic/resolvespec-js",
|
||||
"version": "1.0.0",
|
||||
"description": "Client side library for the ResolveSpec API",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"bin",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"clean": "rm -rf dist",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "vitest run",
|
||||
"lint": "eslint src"
|
||||
},
|
||||
"keywords": [
|
||||
"string",
|
||||
"blob",
|
||||
"dependencies",
|
||||
"workspace",
|
||||
"package",
|
||||
"cli",
|
||||
"tools",
|
||||
"npm",
|
||||
"yarn",
|
||||
"pnpm"
|
||||
],
|
||||
"author": "Hein (Warkanum) Puth",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.6.3",
|
||||
"uuid": "^11.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.10",
|
||||
"@eslint/js": "^9.16.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"eslint": "^9.16.0",
|
||||
"globals": "^15.13.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.17.0",
|
||||
"vite": "^6.0.2",
|
||||
"vite-plugin-dts": "^4.3.0",
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Warky-Devs/ResolveSpec"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Warky-Devs/ResolveSpec/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Warky-Devs/ResolveSpec#readme",
|
||||
"packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e"
|
||||
}
|
||||
|
132
resolvespec-js/src/api.ts
Normal file
132
resolvespec-js/src/api.ts
Normal file
@ -0,0 +1,132 @@
|
||||
import { ClientConfig, APIResponse, TableMetadata, Options, RequestBody } from "./types";
|
||||
|
||||
// Helper functions
|
||||
const getHeaders = (options?: Record<string,any>): HeadersInit => {
|
||||
const headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (options?.token) {
|
||||
headers['Authorization'] = `Bearer ${options.token}`;
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
const buildUrl = (config: ClientConfig, schema: string, entity: string, id?: string): string => {
|
||||
let url = `${config.baseUrl}/${schema}/${entity}`;
|
||||
if (id) {
|
||||
url += `/${id}`;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
const fetchWithError = async <T>(url: string, options: RequestInit): Promise<APIResponse<T>> => {
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'An error occurred');
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// API Functions
|
||||
export const getMetadata = async (
|
||||
config: ClientConfig,
|
||||
schema: string,
|
||||
entity: string
|
||||
): Promise<APIResponse<TableMetadata>> => {
|
||||
const url = buildUrl(config, schema, entity);
|
||||
return fetchWithError<TableMetadata>(url, {
|
||||
method: 'GET',
|
||||
headers: getHeaders(config),
|
||||
});
|
||||
};
|
||||
|
||||
export const read = async <T = any>(
|
||||
config: ClientConfig,
|
||||
schema: string,
|
||||
entity: string,
|
||||
id?: string,
|
||||
options?: Options
|
||||
): Promise<APIResponse<T>> => {
|
||||
const url = buildUrl(config, schema, entity, id);
|
||||
const body: RequestBody = {
|
||||
operation: 'read',
|
||||
options,
|
||||
};
|
||||
|
||||
return fetchWithError<T>(url, {
|
||||
method: 'POST',
|
||||
headers: getHeaders(config),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
};
|
||||
|
||||
export const create = async <T = any>(
|
||||
config: ClientConfig,
|
||||
schema: string,
|
||||
entity: string,
|
||||
data: any | any[],
|
||||
options?: Options
|
||||
): Promise<APIResponse<T>> => {
|
||||
const url = buildUrl(config, schema, entity);
|
||||
const body: RequestBody = {
|
||||
operation: 'create',
|
||||
data,
|
||||
options,
|
||||
};
|
||||
|
||||
return fetchWithError<T>(url, {
|
||||
method: 'POST',
|
||||
headers: getHeaders(config),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async <T = any>(
|
||||
config: ClientConfig,
|
||||
schema: string,
|
||||
entity: string,
|
||||
data: any | any[],
|
||||
id?: string | string[],
|
||||
options?: Options
|
||||
): Promise<APIResponse<T>> => {
|
||||
const url = buildUrl(config, schema, entity, typeof id === 'string' ? id : undefined);
|
||||
const body: RequestBody = {
|
||||
operation: 'update',
|
||||
id: typeof id === 'string' ? undefined : id,
|
||||
data,
|
||||
options,
|
||||
};
|
||||
|
||||
return fetchWithError<T>(url, {
|
||||
method: 'POST',
|
||||
headers: getHeaders(config),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteEntity = async (
|
||||
config: ClientConfig,
|
||||
schema: string,
|
||||
entity: string,
|
||||
id: string
|
||||
): Promise<APIResponse<void>> => {
|
||||
const url = buildUrl(config, schema, entity, id);
|
||||
const body: RequestBody = {
|
||||
operation: 'delete',
|
||||
};
|
||||
|
||||
return fetchWithError<void>(url, {
|
||||
method: 'POST',
|
||||
headers: getHeaders(config),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
};
|
68
resolvespec-js/src/examples.ts
Normal file
68
resolvespec-js/src/examples.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { getMetadata, read, create, update, deleteEntity } from "./api";
|
||||
import { ClientConfig } from "./types";
|
||||
|
||||
// Usage Examples
|
||||
const config: ClientConfig = {
|
||||
baseUrl: 'http://api.example.com/v1',
|
||||
token: 'your-token-here'
|
||||
};
|
||||
|
||||
// Example usage
|
||||
const examples = async () => {
|
||||
// Get metadata
|
||||
const metadata = await getMetadata(config, 'test', 'employees');
|
||||
|
||||
|
||||
// Read with relations
|
||||
const employees = await read(config, 'test', 'employees', undefined, {
|
||||
preload: [
|
||||
{
|
||||
relation: 'department',
|
||||
columns: ['id', 'name']
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
column: 'status',
|
||||
operator: 'eq',
|
||||
value: 'active'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Create single record
|
||||
const newEmployee = await create(config, 'test', 'employees', {
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
email: 'john@example.com'
|
||||
});
|
||||
|
||||
// Bulk create
|
||||
const newEmployees = await create(config, 'test', 'employees', [
|
||||
{
|
||||
first_name: 'Jane',
|
||||
last_name: 'Smith',
|
||||
email: 'jane@example.com'
|
||||
},
|
||||
{
|
||||
first_name: 'Bob',
|
||||
last_name: 'Johnson',
|
||||
email: 'bob@example.com'
|
||||
}
|
||||
]);
|
||||
|
||||
// Update single record
|
||||
const updatedEmployee = await update(config, 'test', 'employees',
|
||||
{ status: 'inactive' },
|
||||
'emp123'
|
||||
);
|
||||
|
||||
// Bulk update
|
||||
const updatedEmployees = await update(config, 'test', 'employees',
|
||||
{ department_id: 'dept2' },
|
||||
['emp1', 'emp2', 'emp3']
|
||||
);
|
||||
|
||||
// Delete
|
||||
await deleteEntity(config, 'test', 'employees', 'emp123');
|
||||
};
|
0
resolvespec-js/src/index.ts
Normal file
0
resolvespec-js/src/index.ts
Normal file
86
resolvespec-js/src/types.ts
Normal file
86
resolvespec-js/src/types.ts
Normal file
@ -0,0 +1,86 @@
|
||||
// Types
|
||||
export type Operator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'ilike' | 'in';
|
||||
export type Operation = 'read' | 'create' | 'update' | 'delete';
|
||||
export type SortDirection = 'asc' | 'desc';
|
||||
|
||||
export interface PreloadOption {
|
||||
relation: string;
|
||||
columns?: string[];
|
||||
filters?: FilterOption[];
|
||||
}
|
||||
|
||||
export interface FilterOption {
|
||||
column: string;
|
||||
operator: Operator;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export interface SortOption {
|
||||
column: string;
|
||||
direction: SortDirection;
|
||||
}
|
||||
|
||||
export interface CustomOperator {
|
||||
name: string;
|
||||
sql: string;
|
||||
}
|
||||
|
||||
export interface ComputedColumn {
|
||||
name: string;
|
||||
expression: string;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
preload?: PreloadOption[];
|
||||
columns?: string[];
|
||||
filters?: FilterOption[];
|
||||
sort?: SortOption[];
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
customOperators?: CustomOperator[];
|
||||
computedColumns?: ComputedColumn[];
|
||||
}
|
||||
|
||||
export interface RequestBody {
|
||||
operation: Operation;
|
||||
id?: string | string[];
|
||||
data?: any | any[];
|
||||
options?: Options;
|
||||
}
|
||||
|
||||
export interface APIResponse<T = any> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
metadata?: {
|
||||
total: number;
|
||||
filtered: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
};
|
||||
error?: {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Column {
|
||||
name: string;
|
||||
type: string;
|
||||
is_nullable: boolean;
|
||||
is_primary: boolean;
|
||||
is_unique: boolean;
|
||||
has_index: boolean;
|
||||
}
|
||||
|
||||
export interface TableMetadata {
|
||||
schema: string;
|
||||
table: string;
|
||||
columns: Column[];
|
||||
relations: string[];
|
||||
}
|
||||
|
||||
export interface ClientConfig {
|
||||
baseUrl: string;
|
||||
token?: string;
|
||||
}
|
5
resolvespec-python/todo.md
Normal file
5
resolvespec-python/todo.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Python Implementation of the ResolveSpec API
|
||||
|
||||
# Server
|
||||
|
||||
# Client
|
Loading…
Reference in New Issue
Block a user