@simtlix/simfinity-js 1.6.0 → 1.7.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.
Files changed (3) hide show
  1. package/README.md +271 -0
  2. package/package.json +1 -1
  3. package/src/index.js +25 -10
package/README.md CHANGED
@@ -1232,6 +1232,11 @@ const newBook = await simfinity.saveObject('Book', {
1232
1232
  const BookModel = simfinity.getModel(BookType);
1233
1233
  const books = await BookModel.find({ author: 'Douglas Adams' });
1234
1234
 
1235
+ // Get the GraphQL type definition by name
1236
+ const UserType = simfinity.getType('User');
1237
+ console.log(UserType.name); // 'User'
1238
+ console.log(UserType.getFields()); // Access GraphQL fields
1239
+
1235
1240
  // Get the input type for a GraphQL type
1236
1241
  const BookInput = simfinity.getInputType(BookType);
1237
1242
  ```
@@ -2122,4 +2127,270 @@ When the plugin is correctly set up, your GraphQL response will include the coun
2122
2127
 
2123
2128
  This setup allows you to efficiently manage and display pagination information in your GraphQL applications.
2124
2129
 
2130
+ ## 📖 API Reference
2131
+
2132
+ Simfinity.js provides several utility methods for programmatic access to your GraphQL types and data:
2133
+
2134
+ ### `getType(typeName)`
2135
+
2136
+ Retrieves a GraphQL type definition from the internal types registry.
2137
+
2138
+ **Parameters:**
2139
+ - `typeName` (string | GraphQLObjectType): The name of the type or a GraphQL type object
2140
+
2141
+ **Returns:**
2142
+ - `GraphQLObjectType | null`: The GraphQL type definition, or null if not found
2143
+
2144
+ **Examples:**
2145
+
2146
+ ```javascript
2147
+ import { getType } from '@simtlix/simfinity-js';
2148
+
2149
+ // Get type by string name
2150
+ const UserType = getType('User');
2151
+ if (UserType) {
2152
+ console.log(UserType.name); // 'User'
2153
+
2154
+ // Access field definitions
2155
+ const fields = UserType.getFields();
2156
+ console.log(Object.keys(fields)); // ['id', 'name', 'email', ...]
2157
+
2158
+ // Check specific field
2159
+ const nameField = fields.name;
2160
+ console.log(nameField.type); // GraphQLString
2161
+ }
2162
+
2163
+ // Get type by GraphQL type object
2164
+ const BookType = getType(SomeBookType);
2165
+
2166
+ // Safe access - returns null if not found
2167
+ const nonExistentType = getType('NonExistent');
2168
+ console.log(nonExistentType); // null
2169
+ ```
2170
+
2171
+ **Use Cases:**
2172
+ - **Type introspection**: Examine type definitions programmatically
2173
+ - **Dynamic schema analysis**: Build tools that analyze your GraphQL schema
2174
+ - **Runtime type checking**: Validate types exist before operations
2175
+ - **Admin interfaces**: Build dynamic forms based on type definitions
2176
+ - **Circular reference resolution**: Prevent import cycles when types reference each other
2177
+
2178
+ ### Preventing Circular References with `getType`
2179
+
2180
+ When you have types that reference each other (like User and Group), using `getType` prevents circular import issues:
2181
+
2182
+ ```javascript
2183
+ import { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLList } from 'graphql';
2184
+ import { getType } from '@simtlix/simfinity-js';
2185
+
2186
+ // User type that references Group
2187
+ const UserType = new GraphQLObjectType({
2188
+ name: 'User',
2189
+ fields: () => ({
2190
+ id: { type: GraphQLID },
2191
+ name: { type: GraphQLString },
2192
+ email: { type: GraphQLString },
2193
+
2194
+ // Reference Group type by name to avoid circular imports
2195
+ groups: {
2196
+ type: new GraphQLList(() => getType('Group')), // Use getType instead of direct import
2197
+ extensions: {
2198
+ relation: {
2199
+ connectionField: 'members',
2200
+ displayField: 'name'
2201
+ }
2202
+ }
2203
+ },
2204
+
2205
+ // Single group reference
2206
+ primaryGroup: {
2207
+ type: () => getType('Group'), // Lazy evaluation with getType
2208
+ extensions: {
2209
+ relation: {
2210
+ connectionField: 'primaryGroupId',
2211
+ displayField: 'name'
2212
+ }
2213
+ }
2214
+ }
2215
+ })
2216
+ });
2217
+
2218
+ // Group type that references User
2219
+ const GroupType = new GraphQLObjectType({
2220
+ name: 'Group',
2221
+ fields: () => ({
2222
+ id: { type: GraphQLID },
2223
+ name: { type: GraphQLString },
2224
+ description: { type: GraphQLString },
2225
+
2226
+ // Reference User type by name to avoid circular imports
2227
+ members: {
2228
+ type: new GraphQLList(() => getType('User')), // Use getType instead of direct import
2229
+ extensions: {
2230
+ relation: {
2231
+ connectionField: 'groups',
2232
+ displayField: 'name'
2233
+ }
2234
+ }
2235
+ },
2236
+
2237
+ // Single user reference (admin)
2238
+ admin: {
2239
+ type: () => getType('User'), // Lazy evaluation with getType
2240
+ extensions: {
2241
+ relation: {
2242
+ connectionField: 'adminId',
2243
+ displayField: 'name'
2244
+ }
2245
+ }
2246
+ }
2247
+ })
2248
+ });
2249
+
2250
+ // Register types with simfinity
2251
+ simfinity.connect(null, UserType, 'user', 'users');
2252
+ simfinity.connect(null, GroupType, 'group', 'groups');
2253
+
2254
+ // Create schema - resolvers will be auto-generated for all relationships
2255
+ const schema = simfinity.createSchema();
2256
+ ```
2257
+
2258
+ **Benefits of this approach:**
2259
+
2260
+ 1. **🔄 No Circular Imports**: Each file can import `getType` without importing other type definitions
2261
+ 2. **⚡ Lazy Resolution**: Types are resolved at schema creation time when all types are registered
2262
+ 3. **🛡️ Type Safety**: Still maintains GraphQL type checking and validation
2263
+ 4. **🧹 Clean Architecture**: Separates type definitions from type relationships
2264
+ 5. **📦 Better Modularity**: Each type can be in its own file without import dependencies
2265
+
2266
+ **File Structure Example:**
2267
+
2268
+ ```
2269
+ types/
2270
+ ├── User.js // Defines UserType using getType('Group')
2271
+ ├── Group.js // Defines GroupType using getType('User')
2272
+ └── index.js // Registers all types and creates schema
2273
+ ```
2274
+
2275
+ ```javascript
2276
+ // types/User.js
2277
+ import { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLList } from 'graphql';
2278
+ import { getType } from '@simtlix/simfinity-js';
2279
+
2280
+ export const UserType = new GraphQLObjectType({
2281
+ name: 'User',
2282
+ fields: () => ({
2283
+ id: { type: GraphQLID },
2284
+ name: { type: GraphQLString },
2285
+ groups: {
2286
+ type: new GraphQLList(() => getType('Group')),
2287
+ extensions: { relation: { connectionField: 'members' } }
2288
+ }
2289
+ })
2290
+ });
2291
+
2292
+ // types/Group.js
2293
+ import { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLList } from 'graphql';
2294
+ import { getType } from '@simtlix/simfinity-js';
2295
+
2296
+ export const GroupType = new GraphQLObjectType({
2297
+ name: 'Group',
2298
+ fields: () => ({
2299
+ id: { type: GraphQLID },
2300
+ name: { type: GraphQLString },
2301
+ members: {
2302
+ type: new GraphQLList(() => getType('User')),
2303
+ extensions: { relation: { connectionField: 'groups' } }
2304
+ }
2305
+ })
2306
+ });
2307
+
2308
+ // types/index.js
2309
+ import { UserType } from './User.js';
2310
+ import { GroupType } from './Group.js';
2311
+ import simfinity from '@simtlix/simfinity-js';
2312
+
2313
+ // Register all types
2314
+ simfinity.connect(null, UserType, 'user', 'users');
2315
+ simfinity.connect(null, GroupType, 'group', 'groups');
2316
+
2317
+ // Create schema with auto-generated resolvers
2318
+ export const schema = simfinity.createSchema();
2319
+ ```
2320
+
2321
+ ### `getModel(gqltype)`
2322
+
2323
+ Retrieves the Mongoose model associated with a GraphQL type.
2324
+
2325
+ **Parameters:**
2326
+ - `gqltype` (GraphQLObjectType): The GraphQL type object
2327
+
2328
+ **Returns:**
2329
+ - `MongooseModel`: The associated Mongoose model
2330
+
2331
+ **Example:**
2332
+
2333
+ ```javascript
2334
+ const BookModel = simfinity.getModel(BookType);
2335
+ const books = await BookModel.find({ author: 'Douglas Adams' });
2336
+ ```
2337
+
2338
+ ### `getInputType(type)`
2339
+
2340
+ Retrieves the input type for mutations associated with a GraphQL type.
2341
+
2342
+ **Parameters:**
2343
+ - `type` (GraphQLObjectType): The GraphQL type object
2344
+
2345
+ **Returns:**
2346
+ - `GraphQLInputObjectType`: The input type for mutations
2347
+
2348
+ **Example:**
2349
+
2350
+ ```javascript
2351
+ const BookInput = simfinity.getInputType(BookType);
2352
+ console.log(BookInput.getFields()); // Input fields for mutations
2353
+ ```
2354
+
2355
+ ### `saveObject(typeName, args, session?)`
2356
+
2357
+ Programmatically save an object outside of GraphQL mutations.
2358
+
2359
+ **Parameters:**
2360
+ - `typeName` (string): The name of the GraphQL type
2361
+ - `args` (object): The data to save
2362
+ - `session` (MongooseSession, optional): Database session for transactions
2363
+
2364
+ **Returns:**
2365
+ - `Promise<object>`: The saved object
2366
+
2367
+ **Example:**
2368
+
2369
+ ```javascript
2370
+ const newBook = await simfinity.saveObject('Book', {
2371
+ title: 'New Book',
2372
+ author: 'Author Name'
2373
+ }, session);
2374
+ ```
2375
+
2376
+ ### `createSchema(includedQueryTypes?, includedMutationTypes?, includedCustomMutations?)`
2377
+
2378
+ Creates the final GraphQL schema with all connected types.
2379
+
2380
+ **Parameters:**
2381
+ - `includedQueryTypes` (array, optional): Limit query types to include
2382
+ - `includedMutationTypes` (array, optional): Limit mutation types to include
2383
+ - `includedCustomMutations` (array, optional): Limit custom mutations to include
2384
+
2385
+ **Returns:**
2386
+ - `GraphQLSchema`: The complete GraphQL schema
2387
+
2388
+ **Example:**
2389
+
2390
+ ```javascript
2391
+ const schema = simfinity.createSchema();
2392
+ ```
2393
+
2394
+ *Built with ❤️ by [Simtlix](https://github.com/simtlix)*
2395
+
2125
2396
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simtlix/simfinity-js",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -1535,13 +1535,34 @@ const buildRootQuery = (name, includedTypes) => {
1535
1535
  /* Creating a new GraphQL Schema, with options query which defines query
1536
1536
  we will allow users to use when they are making request. */
1537
1537
  export const createSchema = (includedQueryTypes,
1538
- includedMutationTypes, includedCustomMutations) => new GraphQLSchema({
1539
- query: buildRootQuery('RootQueryType', includedQueryTypes),
1540
- mutation: buildMutation('Mutation', includedMutationTypes, includedCustomMutations),
1541
- });
1538
+ includedMutationTypes, includedCustomMutations) => {
1539
+
1540
+ // Auto-generate resolvers for all registered types now that all types are available
1541
+ Object.values(typesDict.types).forEach(typeInfo => {
1542
+ if (typeInfo.gqltype) {
1543
+ autoGenerateResolvers(typeInfo.gqltype);
1544
+ }
1545
+ });
1546
+
1547
+ return new GraphQLSchema({
1548
+ query: buildRootQuery('RootQueryType', includedQueryTypes),
1549
+ mutation: buildMutation('Mutation', includedMutationTypes, includedCustomMutations),
1550
+ });
1551
+ };
1542
1552
 
1543
1553
  export const getModel = (gqltype) => typesDict.types[gqltype.name].model;
1544
1554
 
1555
+ export const getType = (typeName) => {
1556
+ if (typeof typeName === 'string') {
1557
+ return typesDict.types[typeName]?.gqltype;
1558
+ }
1559
+ // If it's already a GraphQL type object, get by its name
1560
+ if (typeName && typeName.name) {
1561
+ return typesDict.types[typeName.name]?.gqltype;
1562
+ }
1563
+ return null;
1564
+ };
1565
+
1545
1566
  export const registerMutation = (name, description, inputModel, outputModel, callback) => {
1546
1567
  registeredMutations[name] = {
1547
1568
  description,
@@ -1617,9 +1638,6 @@ export const connect = (model, gqltype, simpleEntityEndpointName,
1617
1638
  };
1618
1639
 
1619
1640
  typesDictForUpdate.types[gqltype.name] = { ...typesDict.types[gqltype.name] };
1620
-
1621
- // Auto-generate resolve methods for relationship fields if not already defined
1622
- autoGenerateResolvers(gqltype);
1623
1641
  };
1624
1642
 
1625
1643
  export const addNoEndpointType = (gqltype) => {
@@ -1648,9 +1666,6 @@ export const addNoEndpointType = (gqltype) => {
1648
1666
  };
1649
1667
 
1650
1668
  typesDictForUpdate.types[gqltype.name] = { ...typesDict.types[gqltype.name] };
1651
-
1652
- // Auto-generate resolve methods for relationship fields if not already defined
1653
- autoGenerateResolvers(gqltype);
1654
1669
  };
1655
1670
 
1656
1671
  export { createValidatedScalar };