prisma-nestjs-graphql 21.0.1 → 21.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -361,6 +361,28 @@ export class BigIntFilter {
361
361
 
362
362
  It will affect all inputs and outputs types (including models).
363
363
 
364
+ #### `customImport`
365
+
366
+ Allow to declare custom import statements. (Only works with emitSingle = true)
367
+
368
+ ```sh
369
+ generator nestgraphql {
370
+ decorate_{key}_from = "module specifier"
371
+ decorate_{key}_name = "import name"
372
+ decorate_{key}_defaultImport = "default import name" | true
373
+ decorate_{key}_namespaceImport = "namespace import name"
374
+ decorate_{key}_namedImport = "import name" | true
375
+ }
376
+ ```
377
+
378
+ Where `{key}` any identifier to group values (written in [flatten](https://github.com/hughsk/flat) style)
379
+
380
+ - `decorate_{key}_from` - module specifier to import from (e.g `class-validator`)
381
+ - `decorate_{key}_name` - import name or name with namespace
382
+ - `decorate_{key}_defaultImport` - import as default
383
+ - `decorate_{key}_namespaceImport` - use this name as import namespace
384
+ - `decorate_{key}_namedImport` - named import (without namespace)
385
+
364
386
  ## Documentation and field options
365
387
 
366
388
  Comments with triple slash will projected to typescript code comments
@@ -736,30 +758,35 @@ import { generate } from 'prisma-nestjs-graphql/generate';
736
758
 
737
759
  ## Similar Projects
738
760
 
739
- - https://github.com/jasonraimondi/prisma-generator-nestjs-graphql
740
- - https://github.com/omar-dulaimi/prisma-class-validator-generator
741
- - https://github.com/kimjbstar/prisma-class-generator
742
- - https://github.com/odroe/nest-gql-mix
743
- - https://github.com/rfermann/nestjs-prisma-graphql-generator
744
- - https://github.com/madscience/graphql-codegen-nestjs
745
- - https://github.com/wSedlacek/prisma-generators/tree/master/libs/nestjs
746
- - https://github.com/EndyKaufman/typegraphql-prisma-nestjs
747
- - https://github.com/MichalLytek/typegraphql-prisma
748
- - https://github.com/mk668a/nestjs-prisma-graphql-crud-gen
761
+ - <https://github.com/jasonraimondi/prisma-generator-nestjs-graphql>
762
+ - <https://github.com/omar-dulaimi/prisma-class-validator-generator>
763
+ - <https://github.com/kimjbstar/prisma-class-generator>
764
+ - <https://github.com/odroe/nest-gql-mix>
765
+ - <https://github.com/rfermann/nestjs-prisma-graphql-generator>
766
+ - <https://github.com/madscience/graphql-codegen-nestjs>
767
+ - <https://github.com/wSedlacek/prisma-generators/tree/master/libs/nestjs>
768
+ - <https://github.com/EndyKaufman/typegraphql-prisma-nestjs>
769
+ - <https://github.com/MichalLytek/typegraphql-prisma>
770
+ - <https://github.com/mk668a/nestjs-prisma-graphql-crud-gen>
749
771
 
750
772
  ## Resources
751
773
 
752
- - Todo - https://github.com/unlight/prisma-nestjs-graphql/issues/2
753
- - https://github.com/prisma/prisma/blob/main/packages/client/src/generation/TSClient/TSClient.ts
754
- - https://ts-ast-viewer.com/
755
- - https://github.com/unlight/nestjs-graphql-prisma-realworld-example-app
756
- - https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model
757
- - JSON type for the code first approach - https://github.com/nestjs/graphql/issues/111#issuecomment-631452899
758
- - https://github.com/paljs/prisma-tools/tree/master/packages/plugins
759
- - https://github.com/wasp-lang/wasp
774
+ - Todo - <https://github.com/unlight/prisma-nestjs-graphql/issues/2>
775
+ - <https://github.com/prisma/prisma/blob/main/packages/client/src/generation/TSClient/TSClient.ts>
776
+ - <https://ts-ast-viewer.com/>
777
+ - <https://github.com/unlight/nestjs-graphql-prisma-realworld-example-app>
778
+ - <https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model>
779
+ - JSON type for the code first approach - <https://github.com/nestjs/graphql/issues/111#issuecomment-631452899>
780
+ - <https://github.com/paljs/prisma-tools/tree/master/packages/plugins>
781
+ - <https://github.com/wasp-lang/wasp>
760
782
 
761
783
  ## TODO
762
784
 
763
785
  - keyof typeof SortOrder -> `SortOrder`
764
786
  - dummy-createfriends.input.ts -> `create-friends`
765
787
  - check 'TODO FIXME'
788
+ - 22.12 node require esm (update all deps to latest)
789
+
790
+ ## License
791
+
792
+ [MIT License](https://opensource.org/licenses/MIT) (c) 2025
package/generate.cjs CHANGED
@@ -281,7 +281,7 @@ class ImportDeclarationMap extends Map {
281
281
  }
282
282
 
283
283
  async function generateFiles(args) {
284
- const { project, config, output, eventEmitter } = args;
284
+ const { config, eventEmitter, output, project } = args;
285
285
  if (config.emitSingle) {
286
286
  const rootDirectory = project.getDirectory(output) || project.createDirectory(output);
287
287
  const sourceFile = rootDirectory.getSourceFile("index.ts") || rootDirectory.createSourceFile("index.ts", undefined, { overwrite: true });
@@ -332,9 +332,9 @@ async function generateFiles(args) {
332
332
  }
333
333
  if (statement.defaultImport) {
334
334
  imports.create({
335
+ defaultImport: statement.defaultImport,
335
336
  from: statement.moduleSpecifier,
336
- name: statement.defaultImport,
337
- defaultImport: statement.defaultImport
337
+ name: statement.defaultImport
338
338
  });
339
339
  }
340
340
  if (statement.namespaceImport) {
@@ -356,6 +356,9 @@ async function generateFiles(args) {
356
356
  }
357
357
  }
358
358
  }
359
+ for (const customImport of config.customImport) {
360
+ imports.create(customImport);
361
+ }
359
362
  sourceFile.set({
360
363
  kind: tsMorph.StructureKind.SourceFile,
361
364
  statements: [...imports.toStatements(), ...enums, ...classes]
@@ -365,9 +368,9 @@ async function generateFiles(args) {
365
368
  project.compilerOptions.set({
366
369
  declaration: true,
367
370
  declarationDir: output,
368
- rootDir: output,
369
- outDir: output,
370
371
  emitDecoratorMetadata: false,
372
+ outDir: output,
373
+ rootDir: output,
371
374
  skipLibCheck: true
372
375
  });
373
376
  const emitResult = await project.emit();
@@ -416,12 +419,12 @@ function getGraphqlImport(args) {
416
419
  const {
417
420
  config,
418
421
  fileType,
419
- location,
420
- typeName,
422
+ getSourceFile,
421
423
  isId,
424
+ location,
422
425
  noTypeId,
423
426
  sourceFile,
424
- getSourceFile
427
+ typeName
425
428
  } = args;
426
429
  if (location === "scalar") {
427
430
  if (isId && !noTypeId) {
@@ -462,8 +465,8 @@ function getGraphqlImport(args) {
462
465
  const specifier = relativePath(
463
466
  sourceFile.getFilePath(),
464
467
  getSourceFile({
465
- type: sourceFileType,
466
- name: typeName
468
+ name: typeName,
469
+ type: sourceFileType
467
470
  }).getFilePath()
468
471
  );
469
472
  return { name: typeName, specifier };
@@ -564,7 +567,8 @@ function getPropertyType(args) {
564
567
  return [type];
565
568
  }
566
569
  if (location === "enumTypes") {
567
- return [`keyof typeof ${type}`];
570
+ const enumType = "`${" + type + "}`";
571
+ return [enumType];
568
572
  }
569
573
  if (location === "scalar") {
570
574
  return [type];
@@ -1360,9 +1364,13 @@ function isListInput(typeName, model, field) {
1360
1364
  return typeName === `${model}Create${field}Input` || typeName === `${model}Update${field}Input`;
1361
1365
  }
1362
1366
 
1367
+ function getEnumName(referenceName) {
1368
+ return referenceName.slice(3, -2);
1369
+ }
1370
+
1363
1371
  const nestjsGraphql = "@nestjs/graphql";
1364
1372
  function outputType(outputType2, args) {
1365
- const { getSourceFile, models, eventEmitter, fieldSettings, getModelName, config } = args;
1373
+ const { config, eventEmitter, fieldSettings, getModelName, getSourceFile, models } = args;
1366
1374
  const importDeclarations = new ImportDeclarationMap();
1367
1375
  const fileType = "output";
1368
1376
  const modelName = getModelName(outputType2.name) || "";
@@ -1379,21 +1387,21 @@ function outputType(outputType2, args) {
1379
1387
  type: fileType
1380
1388
  });
1381
1389
  const classStructure = {
1382
- kind: tsMorph.StructureKind.Class,
1383
- isExported: true,
1384
- name: outputType2.name,
1385
1390
  decorators: [
1386
1391
  {
1387
- name: "ObjectType",
1388
- arguments: []
1392
+ arguments: [],
1393
+ name: "ObjectType"
1389
1394
  }
1390
1395
  ],
1396
+ isExported: true,
1397
+ kind: tsMorph.StructureKind.Class,
1398
+ name: outputType2.name,
1391
1399
  properties: []
1392
1400
  };
1393
1401
  importDeclarations.add("Field", nestjsGraphql);
1394
1402
  importDeclarations.add("ObjectType", nestjsGraphql);
1395
1403
  for (const field of outputType2.fields) {
1396
- const { location, isList, type } = field.outputType;
1404
+ const { isList, location, type } = field.outputType;
1397
1405
  const outputTypeName = getOutputTypeName(String(type));
1398
1406
  const settings = isCountOutput ? undefined : model && fieldSettings.get(model.name)?.get(field.name);
1399
1407
  const propertySettings = settings?.getPropertyType({
@@ -1409,11 +1417,11 @@ function outputType(outputType2, args) {
1409
1417
  })
1410
1418
  );
1411
1419
  const property = propertyStructure({
1412
- name: field.name,
1413
- isNullable: field.isNullable,
1414
1420
  hasQuestionToken: isCountOutput ? true : undefined,
1415
- propertyType,
1416
- isList
1421
+ isList,
1422
+ isNullable: field.isNullable,
1423
+ name: field.name,
1424
+ propertyType
1417
1425
  });
1418
1426
  classStructure.properties?.push(property);
1419
1427
  if (propertySettings) {
@@ -1438,46 +1446,43 @@ function outputType(outputType2, args) {
1438
1446
  } else {
1439
1447
  const graphqlImport = getGraphqlImport({
1440
1448
  config,
1441
- sourceFile,
1442
1449
  fileType,
1443
- location,
1450
+ getSourceFile,
1444
1451
  isId: false,
1445
- typeName: outputTypeName,
1446
- getSourceFile
1452
+ location,
1453
+ sourceFile,
1454
+ typeName: outputTypeName
1447
1455
  });
1456
+ const referenceName = location === "enumTypes" ? getEnumName(propertyType[0]) : propertyType[0];
1448
1457
  graphqlType = graphqlImport.name;
1449
- let referenceName = propertyType[0];
1450
- if (location === "enumTypes") {
1451
- referenceName = lodash.last(referenceName.split(" "));
1452
- }
1453
1458
  if (graphqlImport.specifier && !importDeclarations.has(graphqlImport.name) && (graphqlImport.name !== outputType2.name && !shouldHideField || shouldHideField && referenceName === graphqlImport.name)) {
1454
1459
  importDeclarations.set(graphqlImport.name, {
1455
- namedImports: [{ name: graphqlImport.name }],
1456
- moduleSpecifier: graphqlImport.specifier
1460
+ moduleSpecifier: graphqlImport.specifier,
1461
+ namedImports: [{ name: graphqlImport.name }]
1457
1462
  });
1458
1463
  }
1459
1464
  }
1460
1465
  assert.ok(property.decorators, "property.decorators is undefined");
1461
1466
  if (shouldHideField) {
1462
1467
  importDeclarations.add("HideField", nestjsGraphql);
1463
- property.decorators.push({ name: "HideField", arguments: [] });
1468
+ property.decorators.push({ arguments: [], name: "HideField" });
1464
1469
  } else {
1465
1470
  property.decorators.push({
1466
- name: "Field",
1467
1471
  arguments: [
1468
1472
  isList ? `() => [${graphqlType}]` : `() => ${graphqlType}`,
1469
1473
  JSON5.stringify({
1470
1474
  ...settings?.fieldArguments(),
1471
1475
  nullable: Boolean(field.isNullable)
1472
1476
  })
1473
- ]
1477
+ ],
1478
+ name: "Field"
1474
1479
  });
1475
1480
  if (isCustomsApplicable) {
1476
1481
  for (const options of settings || []) {
1477
1482
  if ((options.kind === "Decorator" && options.output && options.match?.(field.name)) ?? true) {
1478
1483
  property.decorators.push({
1479
- name: options.name,
1480
- arguments: options.arguments
1484
+ arguments: options.arguments,
1485
+ name: options.name
1481
1486
  });
1482
1487
  assert.ok(options.from, "Missed 'from' part in configuration or field setting");
1483
1488
  importDeclarations.create(options);
@@ -1486,8 +1491,8 @@ function outputType(outputType2, args) {
1486
1491
  }
1487
1492
  }
1488
1493
  eventEmitter.emitSync("ClassProperty", property, {
1489
- location,
1490
1494
  isList,
1495
+ location,
1491
1496
  propertyType
1492
1497
  });
1493
1498
  }
@@ -1756,6 +1761,24 @@ function createConfig(data) {
1756
1761
  arguments: element.arguments ? JSON5.parse(element.arguments) : undefined
1757
1762
  });
1758
1763
  }
1764
+ const customImport = [];
1765
+ const configCustomImport = Object.values(
1766
+ config.customImport || {}
1767
+ );
1768
+ for (const element of configCustomImport) {
1769
+ if (!element) continue;
1770
+ assert.ok(
1771
+ element.from && element.name,
1772
+ `Missed 'from' or 'name' part in configuration for customImport`
1773
+ );
1774
+ customImport.push({
1775
+ from: element.from,
1776
+ name: element.name,
1777
+ namedImport: toBoolean(element.namedImport),
1778
+ defaultImport: toBoolean(element.defaultImport) ? true : element.defaultImport,
1779
+ namespaceImport: element.namespaceImport
1780
+ });
1781
+ }
1759
1782
  return {
1760
1783
  outputFilePattern,
1761
1784
  tsConfigFilePath: createTsConfigFilePathValue(config.tsConfigFilePath),
@@ -1779,7 +1802,8 @@ function createConfig(data) {
1779
1802
  config.unsafeCompatibleWhereUniqueInput
1780
1803
  ),
1781
1804
  graphqlScalars: config.graphqlScalars || {},
1782
- decorate
1805
+ decorate,
1806
+ customImport
1783
1807
  };
1784
1808
  }
1785
1809
  const tsConfigFileExists = lodash.memoize((filePath) => {
@@ -1819,9 +1843,8 @@ function toBoolean(value) {
1819
1843
  }
1820
1844
 
1821
1845
  function generateFileName(args) {
1822
- const { template, type, name, getModelName } = args;
1846
+ const { getModelName, name, template, type } = args;
1823
1847
  return pupa(template, {
1824
- type,
1825
1848
  get model() {
1826
1849
  const result = getModelName(name) || "prisma";
1827
1850
  return lodash.kebabCase(result);
@@ -1840,7 +1863,8 @@ function generateFileName(args) {
1840
1863
  get type() {
1841
1864
  return pluralize(type);
1842
1865
  }
1843
- }
1866
+ },
1867
+ type
1844
1868
  });
1845
1869
  }
1846
1870
 
@@ -1983,7 +2007,7 @@ const middleKeywords = [
1983
2007
 
1984
2008
  const AwaitEventEmitter = require$1("await-event-emitter").default;
1985
2009
  async function generate(args) {
1986
- const { connectCallback, generator, skipAddOutputSourceFiles, dmmf } = args;
2010
+ const { connectCallback, dmmf, generator, skipAddOutputSourceFiles } = args;
1987
2011
  const generatorOutputValue = generator.output?.value;
1988
2012
  assert.ok(generatorOutputValue, "Missing generator configuration: output");
1989
2013
  const config = createConfig(generator.config);
@@ -2005,12 +2029,12 @@ async function generate(args) {
2005
2029
  eventEmitter.emitSync("Warning", message);
2006
2030
  }
2007
2031
  const project = new tsMorph.Project({
2008
- tsConfigFilePath: config.tsConfigFilePath,
2009
- skipAddingFilesFromTsConfig: true,
2010
- skipLoadingLibFiles: !config.emitCompiled,
2011
2032
  manipulationSettings: {
2012
2033
  quoteKind: tsMorph.QuoteKind.Single
2013
- }
2034
+ },
2035
+ skipAddingFilesFromTsConfig: true,
2036
+ skipLoadingLibFiles: !config.emitCompiled,
2037
+ tsConfigFilePath: config.tsConfigFilePath
2014
2038
  });
2015
2039
  if (!skipAddOutputSourceFiles) {
2016
2040
  project.addSourceFilesAtPaths([
@@ -2030,30 +2054,30 @@ async function generate(args) {
2030
2054
  const fieldSettings = /* @__PURE__ */ new Map();
2031
2055
  const getModelName = createGetModelName(modelNames);
2032
2056
  const getSourceFile = factoryGetSourceFile({
2033
- output: generatorOutputValue,
2034
- project,
2057
+ eventEmitter,
2035
2058
  getModelName,
2059
+ output: generatorOutputValue,
2036
2060
  outputFilePattern: config.outputFilePattern,
2037
- eventEmitter
2061
+ project
2038
2062
  });
2039
2063
  const { datamodel, schema } = JSON.parse(JSON.stringify(dmmf));
2040
2064
  const removeTypes = /* @__PURE__ */ new Set();
2041
2065
  const eventArguments = {
2042
- schema,
2043
- models,
2066
+ classTransformerTypeModels: /* @__PURE__ */ new Set(),
2044
2067
  config,
2045
- modelNames,
2046
- modelFields,
2047
- fieldSettings,
2048
- project,
2049
- output: generatorOutputValue,
2050
- getSourceFile,
2051
- eventEmitter,
2052
- typeNames: /* @__PURE__ */ new Set(),
2053
2068
  enums: lodash.mapKeys(datamodel.enums, (x) => x.name),
2069
+ eventEmitter,
2070
+ fieldSettings,
2054
2071
  getModelName,
2072
+ getSourceFile,
2073
+ modelFields,
2074
+ modelNames,
2075
+ models,
2076
+ output: generatorOutputValue,
2077
+ project,
2055
2078
  removeTypes,
2056
- classTransformerTypeModels: /* @__PURE__ */ new Set()
2079
+ schema,
2080
+ typeNames: /* @__PURE__ */ new Set()
2057
2081
  };
2058
2082
  if (connectCallback) {
2059
2083
  await connectCallback(eventEmitter, eventArguments);
@@ -2065,7 +2089,7 @@ async function generate(args) {
2065
2089
  for (const model of datamodel.types || []) {
2066
2090
  await eventEmitter.emit("Model", model, eventArguments);
2067
2091
  }
2068
- const { inputObjectTypes, outputObjectTypes, enumTypes } = schema;
2092
+ const { enumTypes, inputObjectTypes, outputObjectTypes } = schema;
2069
2093
  await eventEmitter.emit("PostBegin", eventArguments);
2070
2094
  for (const enumType of enumTypes.prisma.concat(enumTypes.model || [])) {
2071
2095
  await eventEmitter.emit("EnumType", enumType, eventArguments);
@@ -2085,9 +2109,9 @@ async function generate(args) {
2085
2109
  for (const inputType2 of inputTypes) {
2086
2110
  const event = {
2087
2111
  ...eventArguments,
2088
- inputType: inputType2,
2112
+ classDecoratorName: "InputType",
2089
2113
  fileType: "input",
2090
- classDecoratorName: "InputType"
2114
+ inputType: inputType2
2091
2115
  };
2092
2116
  if (inputType2.fields.length === 0) {
2093
2117
  removeTypes.add(inputType2.name);
package/generate.d.ts CHANGED
@@ -385,6 +385,13 @@ type DecorateElement = {
385
385
  defaultImport?: string | true;
386
386
  namespaceImport?: string;
387
387
  };
388
+ type CustomImport = {
389
+ from: string;
390
+ name: string;
391
+ namedImport: boolean;
392
+ defaultImport?: string | true;
393
+ namespaceImport?: string;
394
+ };
388
395
  declare function createConfig(data: Record<string, unknown>): {
389
396
  outputFilePattern: string;
390
397
  tsConfigFilePath: string | undefined;
@@ -405,6 +412,7 @@ declare function createConfig(data: Record<string, unknown>): {
405
412
  unsafeCompatibleWhereUniqueInput: boolean;
406
413
  graphqlScalars: Record<string, ImportNameSpec | undefined>;
407
414
  decorate: DecorateElement[];
415
+ customImport: CustomImport[];
408
416
  };
409
417
  type ConfigInputItem = {
410
418
  typeName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-nestjs-graphql",
3
- "version": "21.0.1",
3
+ "version": "21.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Generate object types, inputs, args, etc. from prisma schema file for usage with @nestjs/graphql module",
6
6
  "bin": "bin.js",
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2023
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.