Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Allow non-optional generation of params with optionalNullParams #582

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions docs-new/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ For a full list of options, see the [Configuration file format](#configuration-f
"srcDir": "./src/", // Directory to scan or watch for query files
"failOnError": false, // Whether to fail on a file processing error and abort generation (can be omitted - default is false)
"camelCaseColumnNames": false, // convert to camelCase column names of result interface
"optionalNullParams": true, // Whether nullable parameters are made optional
"dbUrl": "postgres://user:password@host/database", // DB URL (optional - will be merged with db if provided)
"db": {
"dbName": "testdb", // DB name
Expand Down Expand Up @@ -92,6 +93,7 @@ Configuration file can be also be written in CommonJS format and default exporte
| `failOnError?` | `boolean` | Whether to fail on a file processing error and abort generation. **Default:** `false` |
| `dbUrl?` | `string` | A connection string to the database. Example: `postgres://user:password@host/database`. Overrides (merged) with `db` config. |
| `camelCaseColumnNames?` | `boolean` | Whether to convert column names to camelCase. _Note that this only coverts the types. You need to do this at runtime independently using a library like `pg-camelcase`_. |
| `optionalNullParams?` | `boolean` | Whether nullable parameters are automatically marked as optional. **Default:** `true` |
| `typesOverrides?` | `Record<string, string>` | A map of type overrides. Similarly to `camelCaseColumnNames`, this only affects the types. _You need to do this at runtime independently using a library like `pg-types`._ |
| `maxWorkerThreads` | `number` | The maximum number of worker threads to use for type generation. **The default is based on the number of available CPUs.** |

Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const configParser = t.type({
failOnError: t.union([t.boolean, t.undefined]),
camelCaseColumnNames: t.union([t.boolean, t.undefined]),
hungarianNotation: t.union([t.boolean, t.undefined]),
optionalNullParams: t.union([t.boolean, t.undefined]),
dbUrl: t.union([t.string, t.undefined]),
db: t.union([
t.type({
Expand Down Expand Up @@ -99,6 +100,7 @@ export interface ParsedConfig {
failOnError: boolean;
camelCaseColumnNames: boolean;
hungarianNotation: boolean;
optionalNullParams: boolean;
transforms: IConfig['transforms'];
srcDir: IConfig['srcDir'];
typesOverrides: Record<string, Partial<TypeDefinition>>;
Expand Down Expand Up @@ -198,6 +200,7 @@ export function parseConfig(
failOnError,
camelCaseColumnNames,
hungarianNotation,
optionalNullParams,
typesOverrides,
} = configObject as IConfig;

Expand Down Expand Up @@ -242,6 +245,7 @@ export function parseConfig(
failOnError: failOnError ?? false,
camelCaseColumnNames: camelCaseColumnNames ?? false,
hungarianNotation: hungarianNotation ?? true,
optionalNullParams: optionalNullParams ?? true,
typesOverrides: parsedTypesOverrides,
maxWorkerThreads,
};
Expand Down
76 changes: 76 additions & 0 deletions packages/cli/src/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,82 @@ export interface IGetNotificationsResult {
typeCamelCase: PayloadType;
}

/** 'GetNotifications' query type */
export interface IGetNotificationsQuery {
params: IGetNotificationsParams;
result: IGetNotificationsResult;
}\n\n`;
expect(result).toEqual(expected);
});

test(`Null parameters generation as required (${mode})`, async () => {
const queryStringSQL = `
/* @name GetNotifications */
SELECT payload, type FROM notifications WHERE id = :userId;
`;
const queryStringTS = `
const getNotifications = sql\`SELECT payload, type FROM notifications WHERE id = $userId\`;
`;
const queryString =
mode === ProcessingMode.SQL ? queryStringSQL : queryStringTS;
const mockTypes: IQueryTypes = {
returnTypes: [
{
returnName: 'payload',
columnName: 'payload',
type: 'json',
nullable: false,
},
{
returnName: 'type',
columnName: 'type',
type: { name: 'PayloadType', enumValues: ['message', 'dynamite'] },
nullable: false,
},
],
paramMetadata: {
params: ['uuid'],
mapping: [
{
name: 'userId',
type: ParameterTransform.Scalar,
required: false,
assignedIndex: 1,
},
],
},
};
const typeSource = async (_: any) => mockTypes;
const types = new TypeAllocator(TypeMapping());
// Test out imports
types.use(
{ name: 'PreparedQuery', from: '@pgtyped/runtime' },
TypeScope.Return,
);
const result = await queryToTypeDeclarations(
parsedQuery(mode, queryString),
typeSource,
types,
{ optionalNullParams: false, hungarianNotation: true } as ParsedConfig,
);
const expectedTypes = `import { PreparedQuery } from '@pgtyped/runtime';

export type PayloadType = 'dynamite' | 'message';

export type Json = null | boolean | number | string | Json[] | { [key: string]: Json };\n`;

expect(types.declaration('file.ts')).toEqual(expectedTypes);
const expected = `/** 'GetNotifications' parameters type */
export interface IGetNotificationsParams {
userId: string | null | void;
}

/** 'GetNotifications' return type */
export interface IGetNotificationsResult {
payload: Json;
type: PayloadType;
}

/** 'GetNotifications' query type */
export interface IGetNotificationsQuery {
params: IGetNotificationsParams;
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ export async function queryToTypeDeclarations(

// Allow optional scalar parameters to be missing from parameters object
const optional =
param.type === ParameterTransform.Scalar && !param.required;
param.type === ParameterTransform.Scalar &&
!param.required &&
config.optionalNullParams;

paramFieldTypes.push({
optional,
Expand Down