Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions __fixtures__/codegen-example/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import path from 'node:path';
import { generate } from '@constructive-io/graphql-codegen';

async function main() {
const result = await generate({
schemaFile: path.resolve(__dirname, 'schema.graphql'),
output: path.resolve(__dirname, 'output'),
orm: true,
});

if (!result.success) {
console.error('Generation failed:', result.message);
result.errors?.forEach((e) => console.error(' -', e));
process.exit(1);
}

console.log(result.message);
if (result.tables?.length) {
console.log('Tables:', result.tables.join(', '));
}
}

main().catch((err) => {
console.error('Fatal error:', err);
process.exit(1);
});
5 changes: 5 additions & 0 deletions __fixtures__/codegen-example/output/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Generated SDK - auto-generated, do not edit
* @generated by @constructive-io/graphql-codegen
*/
export * from './orm';
137 changes: 137 additions & 0 deletions __fixtures__/codegen-example/output/orm/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* ORM Client - Runtime GraphQL executor
* @generated by @constructive-io/graphql-codegen
* DO NOT EDIT - changes will be overwritten
*/
import type { GraphQLAdapter, GraphQLError, QueryResult } from '@constructive-io/graphql-types';

export type { GraphQLAdapter, GraphQLError, QueryResult } from '@constructive-io/graphql-types';

/**
* Default adapter that uses fetch for HTTP requests.
* This is used when no custom adapter is provided.
*/
export class FetchAdapter implements GraphQLAdapter {
private headers: Record<string, string>;

constructor(
private endpoint: string,
headers?: Record<string, string>
) {
this.headers = headers ?? {};
}

async execute<T>(document: string, variables?: Record<string, unknown>): Promise<QueryResult<T>> {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...this.headers,
},
body: JSON.stringify({
query: document,
variables: variables ?? {},
}),
});

if (!response.ok) {
return {
ok: false,
data: null,
errors: [{ message: `HTTP ${response.status}: ${response.statusText}` }],
};
}

const json = (await response.json()) as {
data?: T;
errors?: GraphQLError[];
};

if (json.errors && json.errors.length > 0) {
return {
ok: false,
data: null,
errors: json.errors,
};
}

return {
ok: true,
data: json.data as T,
errors: undefined,
};
}

setHeaders(headers: Record<string, string>): void {
this.headers = { ...this.headers, ...headers };
}

getEndpoint(): string {
return this.endpoint;
}
}

/**
* Configuration for creating an ORM client.
* Either provide endpoint (and optional headers) for HTTP requests,
* or provide a custom adapter for alternative execution strategies.
*/
export interface OrmClientConfig {
/** GraphQL endpoint URL (required if adapter not provided) */
endpoint?: string;
/** Default headers for HTTP requests (only used with endpoint) */
headers?: Record<string, string>;
/** Custom adapter for GraphQL execution (overrides endpoint/headers) */
adapter?: GraphQLAdapter;
}

/**
* Error thrown when GraphQL request fails
*/
export class GraphQLRequestError extends Error {
constructor(
public readonly errors: GraphQLError[],
public readonly data: unknown = null
) {
const messages = errors.map((e) => e.message).join('; ');
super(`GraphQL Error: ${messages}`);
this.name = 'GraphQLRequestError';
}
}

export class OrmClient {
private adapter: GraphQLAdapter;

constructor(config: OrmClientConfig) {
if (config.adapter) {
this.adapter = config.adapter;
} else if (config.endpoint) {
this.adapter = new FetchAdapter(config.endpoint, config.headers);
} else {
throw new Error('OrmClientConfig requires either an endpoint or a custom adapter');
}
}

async execute<T>(document: string, variables?: Record<string, unknown>): Promise<QueryResult<T>> {
return this.adapter.execute<T>(document, variables);
}

/**
* Set headers for requests.
* Only works if the adapter supports headers.
*/
setHeaders(headers: Record<string, string>): void {
if (this.adapter.setHeaders) {
this.adapter.setHeaders(headers);
}
}

/**
* Get the endpoint URL.
* Returns empty string if the adapter doesn't have an endpoint.
*/
getEndpoint(): string {
return this.adapter.getEndpoint?.() ?? '';
}
}
48 changes: 48 additions & 0 deletions __fixtures__/codegen-example/output/orm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* ORM Client - createClient factory
* @generated by @constructive-io/graphql-codegen
* DO NOT EDIT - changes will be overwritten
*/
import { OrmClient } from './client';
import type { OrmClientConfig } from './client';
import { UserModel } from './models/user';
import { PostModel } from './models/post';
import { CommentModel } from './models/comment';
import { CategoryModel } from './models/category';
export type { OrmClientConfig, QueryResult, GraphQLError, GraphQLAdapter } from './client';
export { GraphQLRequestError } from './client';
export { QueryBuilder } from './query-builder';
export * from './select-types';
export * from './models';
/**
* Create an ORM client instance
*
* @example
* ```typescript
* const db = createClient({
* endpoint: 'https://api.example.com/graphql',
* headers: { Authorization: 'Bearer token' },
* });
*
* // Query users
* const users = await db.user.findMany({
* select: { id: true, name: true },
* first: 10,
* }).execute();
*
* // Create a user
* const newUser = await db.user.create({
* data: { name: 'John', email: 'john@example.com' },
* select: { id: true },
* }).execute();
* ```
*/
export function createClient(config: OrmClientConfig) {
const client = new OrmClient(config);
return {
user: new UserModel(client),
post: new PostModel(client),
comment: new CommentModel(client),
category: new CategoryModel(client),
};
}
Loading