@simtlix/simfinity-js 2.0.1 → 2.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.
@@ -1,65 +0,0 @@
1
- name: Generate Release
2
-
3
- on:
4
- push:
5
- branches:
6
- - release/*
7
-
8
- jobs:
9
- generate_release:
10
- runs-on: ubuntu-24.04
11
- steps:
12
- - name: Inject slug/short variables
13
- uses: rlespinasse/github-slug-action@3.1.0
14
- - uses: actions/checkout@v2.3.4
15
- - uses: actions/setup-node@v1.4.4
16
- with:
17
- node-version: 14
18
- - run: npm ci
19
- - run: npx json -f package.json peerDependencies | npx json -ka | xargs -i{} bash -c 'echo $0@$(npx json -f package.json peerDependencies.$0)' {} | xargs -i{} npm install --save-optional {}
20
- - run: npm run lint
21
- - run: npm test
22
- - run: npm version --no-git-tag-version $(echo ${{ env.GITHUB_REF_SLUG }} | cut -d"-" -f 2)
23
- - name: Set release version
24
- uses: stefanzweifel/git-auto-commit-action@v4
25
- with:
26
- commit_message: "Set Release version to ${{ env.GITHUB_REF_SLUG }}"
27
- - name: Push changes to master
28
- uses: ad-m/github-push-action@master
29
- with:
30
- github_token: ${{ secrets.GITHUB_TOKEN }}
31
- branch: ${{ env.GITHUB_REF_SLUG }}
32
- - name: Create tag
33
- uses: Klemensas/action-autotag@stable
34
- id: update_tag
35
- with:
36
- GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
37
- tag_prefix: "v"
38
- - name: Create Release
39
- if: steps.update_tag.outputs.tagname
40
- id: create_release
41
- uses: actions/create-release@v1
42
- env:
43
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44
- with:
45
- tag_name: ${{ steps.update_tag.outputs.tagname }}
46
- release_name: Release ${{ steps.update_tag.outputs.tagname }}
47
- body: |
48
- Changes in this Release
49
- draft: false
50
- prerelease: false
51
-
52
- - name: "Set next development version"
53
- uses: actions/setup-node@v1.4.4
54
- with:
55
- node-version: 14
56
- - run: npm version --no-git-tag-version preminor --preid alpha
57
- - name: "Push next development version to master"
58
- uses: stefanzweifel/git-auto-commit-action@v4
59
- with:
60
- commit_message: "Set next development version"
61
- - name: Push changes
62
- uses: ad-m/github-push-action@master
63
- with:
64
- github_token: ${{ secrets.GITHUB_TOKEN }}
65
- branch: master
package/BACKUP_README.md DELETED
@@ -1,26 +0,0 @@
1
- [![npm version](https://badge.fury.io/js/%40simtlix%2Fsimfinity-js.svg)](https://badge.fury.io/js/%40simtlix%2Fsimfinity-js)
2
-
3
- # How to
4
- ## Install
5
- ```bash
6
- npm install @simtlix/simfinity-js --save
7
- ```
8
-
9
- To use this lib:
10
- * Define your mongoose models
11
- * Define your GraphQL types
12
- * Register models and types using `connect` function for **non embedded** types and `addNoEndpointType` function for **embedded** ones
13
- * Create the GraphQL schema using `createSchema` function
14
-
15
- ## Test
16
- On this project root directory
17
- `npm link`
18
-
19
- On the test project root directory
20
- `npm link @simtlix/simfinity-js`
21
-
22
- Run test project with *preserve-symlinks* flag. E.g.:
23
- `node --preserve-symlinks app.js`
24
-
25
- # Example
26
- There is a sample of an app using this lib at [simfinity.js-samples](https://github.com/simtlix/simfinity.js-samples)
@@ -1,252 +0,0 @@
1
- # Automatic ObjectId Index Creation
2
-
3
- This feature automatically creates MongoDB indexes for all ObjectId fields when models are generated, including nested embedded objects.
4
-
5
- ## How it works
6
-
7
- When you define GraphQL types with ObjectId fields (GraphQLID), the system will automatically:
8
-
9
- 1. Analyze the schema definition to find all ObjectId fields
10
- 2. Create indexes for each ObjectId field found
11
- 3. Handle nested embedded objects recursively
12
- 4. Create indexes for arrays of embedded objects
13
- 5. Create indexes for relationship fields (foreign keys between types)
14
-
15
- ## Examples
16
-
17
- ### Simple ObjectId fields
18
-
19
- ```javascript
20
- import { GraphQLObjectType, GraphQLString, GraphQLID } from 'graphql';
21
- import * as simfinity from '@simtlix/simfinity-js';
22
-
23
- const UserType = new GraphQLObjectType({
24
- name: 'User',
25
- fields: () => ({
26
- id: { type: GraphQLID },
27
- name: { type: GraphQLString },
28
- email: { type: GraphQLString },
29
- managerId: { type: GraphQLID }, // This will get an index
30
- }),
31
- });
32
-
33
- simfinity.connect(null, UserType, 'user', 'users');
34
- simfinity.createSchema();
35
- ```
36
-
37
- This will create indexes for:
38
- - `id` field
39
- - `managerId` field
40
-
41
- ### Relationship fields (non-embedded)
42
-
43
- ```javascript
44
- const DepartmentType = new GraphQLObjectType({
45
- name: 'Department',
46
- fields: () => ({
47
- id: { type: GraphQLID },
48
- name: { type: GraphQLString },
49
- }),
50
- });
51
-
52
- const UserType = new GraphQLObjectType({
53
- name: 'User',
54
- fields: () => ({
55
- id: { type: GraphQLID },
56
- name: { type: GraphQLString },
57
- email: { type: GraphQLString },
58
- department: {
59
- type: DepartmentType,
60
- extensions: {
61
- relation: { embedded: false } // or omit this line (default is false)
62
- }
63
- },
64
- }),
65
- });
66
-
67
- // Register both types
68
- simfinity.connect(null, DepartmentType, 'department', 'departments');
69
- simfinity.connect(null, UserType, 'user', 'users');
70
- simfinity.createSchema();
71
- ```
72
-
73
- This will create indexes for:
74
- - `id` field (in both User and Department)
75
- - `department` field (the foreign key field that references Department)
76
-
77
- ### One-to-Many relationships
78
-
79
- ```javascript
80
- const OrderType = new GraphQLObjectType({
81
- name: 'Order',
82
- fields: () => ({
83
- id: { type: GraphQLID },
84
- orderNumber: { type: GraphQLString },
85
- customerId: { type: GraphQLID }, // This will get an index
86
- items: {
87
- type: new GraphQLList(OrderItemType),
88
- extensions: {
89
- relation: { embedded: false }
90
- }
91
- },
92
- }),
93
- });
94
-
95
- const OrderItemType = new GraphQLObjectType({
96
- name: 'OrderItem',
97
- fields: () => ({
98
- id: { type: GraphQLID },
99
- productId: { type: GraphQLID }, // This will get an index
100
- quantity: { type: GraphQLString },
101
- orderId: { type: GraphQLID }, // This will get an index (foreign key)
102
- }),
103
- });
104
-
105
- // Register both types
106
- simfinity.connect(null, OrderItemType, 'orderItem', 'orderItems');
107
- simfinity.connect(null, OrderType, 'order', 'orders');
108
- simfinity.createSchema();
109
- ```
110
-
111
- This will create indexes for:
112
- - `id` field (in both Order and OrderItem)
113
- - `customerId` field (in Order)
114
- - `productId` field (in OrderItem)
115
- - `orderId` field (in OrderItem - the foreign key that references Order)
116
-
117
- ### Embedded objects with ObjectId
118
-
119
- ```javascript
120
- const AddressType = new GraphQLObjectType({
121
- name: 'Address',
122
- fields: () => ({
123
- street: { type: GraphQLString },
124
- city: { type: GraphQLString },
125
- countryId: { type: GraphQLID }, // This will get an index
126
- }),
127
- });
128
-
129
- const UserType = new GraphQLObjectType({
130
- name: 'User',
131
- fields: () => ({
132
- id: { type: GraphQLID },
133
- name: { type: GraphQLString },
134
- address: {
135
- type: AddressType,
136
- extensions: {
137
- relation: { embedded: true }
138
- }
139
- },
140
- }),
141
- });
142
-
143
- // Register the embedded type
144
- simfinity.addNoEndpointType(AddressType);
145
- simfinity.connect(null, UserType, 'user', 'users');
146
- simfinity.createSchema();
147
- ```
148
-
149
- This will create indexes for:
150
- - `id` field
151
- - `countryId` field (from AddressType)
152
- - `address.countryId` field (embedded path)
153
-
154
- ### Nested embedded objects
155
-
156
- ```javascript
157
- const CityType = new GraphQLObjectType({
158
- name: 'City',
159
- fields: () => ({
160
- name: { type: GraphQLString },
161
- stateId: { type: GraphQLID }, // This will get an index
162
- }),
163
- });
164
-
165
- const AddressType = new GraphQLObjectType({
166
- name: 'Address',
167
- fields: () => ({
168
- street: { type: GraphQLString },
169
- city: {
170
- type: CityType,
171
- extensions: {
172
- relation: { embedded: true }
173
- }
174
- },
175
- }),
176
- });
177
-
178
- const UserType = new GraphQLObjectType({
179
- name: 'User',
180
- fields: () => ({
181
- id: { type: GraphQLID },
182
- name: { type: GraphQLString },
183
- address: {
184
- type: AddressType,
185
- extensions: {
186
- relation: { embedded: true }
187
- }
188
- },
189
- }),
190
- });
191
-
192
- // Register the embedded types
193
- simfinity.addNoEndpointType(CityType);
194
- simfinity.addNoEndpointType(AddressType);
195
- simfinity.connect(null, UserType, 'user', 'users');
196
- simfinity.createSchema();
197
- ```
198
-
199
- This will create indexes for:
200
- - `id` field
201
- - `stateId` field (from CityType)
202
- - `city.stateId` field (from AddressType)
203
- - `address.city.stateId` field (nested embedded path)
204
-
205
- ### Arrays of embedded objects
206
-
207
- ```javascript
208
- const OrderItemType = new GraphQLObjectType({
209
- name: 'OrderItem',
210
- fields: () => ({
211
- productId: { type: GraphQLID }, // This will get an index
212
- quantity: { type: GraphQLString },
213
- }),
214
- });
215
-
216
- const OrderType = new GraphQLObjectType({
217
- name: 'Order',
218
- fields: () => ({
219
- id: { type: GraphQLID },
220
- customerId: { type: GraphQLID },
221
- items: {
222
- type: new GraphQLList(OrderItemType),
223
- extensions: {
224
- relation: { embedded: true }
225
- }
226
- },
227
- }),
228
- });
229
-
230
- // Register the embedded type
231
- simfinity.addNoEndpointType(OrderItemType);
232
- simfinity.connect(null, OrderType, 'order', 'orders');
233
- simfinity.createSchema();
234
- ```
235
-
236
- This will create indexes for:
237
- - `id` field
238
- - `customerId` field
239
- - `productId` field (from OrderItemType)
240
- - `items.productId` field (array embedded path)
241
-
242
- ## Benefits
243
-
244
- 1. **Automatic Performance Optimization**: ObjectId fields are automatically indexed for better query performance
245
- 2. **Relationship Optimization**: Foreign key fields are automatically indexed for efficient joins and lookups
246
- 3. **No Manual Configuration**: No need to manually specify which fields should be indexed
247
- 4. **Handles Complex Schemas**: Works with nested embedded objects and arrays
248
- 5. **Consistent**: All ObjectId fields get the same treatment regardless of their location in the schema
249
-
250
- ## Technical Details
251
-
252
- The system uses the `mongoose.Schema` constructor to create schemas and then calls `schema.index()` for each ObjectId field found. The index creation happens during model generation, so it's transparent to the application code.
Binary file
@@ -1,215 +0,0 @@
1
- import {
2
- describe, test, expect, beforeEach, afterEach, vi,
3
- } from 'vitest';
4
- import mongoose from 'mongoose';
5
- import { GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList } from 'graphql';
6
- import * as simfinity from '../src/index.js';
7
-
8
- describe('ObjectId Index Creation', () => {
9
- let indexSpy;
10
-
11
- beforeEach(() => {
12
- // Spy on the index method of mongoose Schema
13
- indexSpy = vi.spyOn(mongoose.Schema.prototype, 'index').mockImplementation(() => {});
14
- // Prevent collection creation to avoid database connection issues
15
- simfinity.preventCreatingCollection(true);
16
- });
17
-
18
- afterEach(() => {
19
- // Restore the original implementation
20
- indexSpy.mockRestore();
21
- });
22
-
23
- test('should create index for direct ObjectId field', () => {
24
- const TestType = new GraphQLObjectType({
25
- name: 'TestTypeWithObjectId',
26
- fields: () => ({
27
- id: { type: GraphQLID },
28
- name: { type: GraphQLString },
29
- userId: { type: GraphQLID },
30
- }),
31
- });
32
-
33
- simfinity.connect(null, TestType, 'testTypeWithObjectId', 'testTypesWithObjectId');
34
- simfinity.createSchema();
35
-
36
- // Should create indexes for both id and userId fields
37
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 });
38
- expect(indexSpy).toHaveBeenCalledWith({ userId: 1 });
39
- expect(indexSpy).toHaveBeenCalledTimes(2);
40
- });
41
-
42
- test('should create index for embedded ObjectId field', () => {
43
- const EmbeddedType = new GraphQLObjectType({
44
- name: 'EmbeddedType',
45
- fields: () => ({
46
- embeddedId: { type: GraphQLID },
47
- embeddedName: { type: GraphQLString },
48
- }),
49
- });
50
-
51
- const TestType = new GraphQLObjectType({
52
- name: 'TestTypeWithEmbedded',
53
- fields: () => ({
54
- id: { type: GraphQLID },
55
- name: { type: GraphQLString },
56
- embedded: {
57
- type: EmbeddedType,
58
- extensions: {
59
- relation: { embedded: true },
60
- },
61
- },
62
- }),
63
- });
64
-
65
- // Register the embedded type first
66
- simfinity.addNoEndpointType(EmbeddedType);
67
- simfinity.connect(null, TestType, 'testTypeWithEmbedded', 'testTypesWithEmbedded');
68
- simfinity.createSchema();
69
-
70
- // Should create indexes for id and embedded.embeddedId fields
71
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 });
72
- expect(indexSpy).toHaveBeenCalledWith({ 'embedded.embeddedId': 1 });
73
- expect(indexSpy).toHaveBeenCalledTimes(2);
74
- });
75
-
76
- test('should create index for nested embedded ObjectId field', () => {
77
- const DeepEmbeddedType = new GraphQLObjectType({
78
- name: 'DeepEmbeddedType',
79
- fields: () => ({
80
- deepId: { type: GraphQLID },
81
- deepName: { type: GraphQLString },
82
- }),
83
- });
84
-
85
- const EmbeddedType = new GraphQLObjectType({
86
- name: 'EmbeddedTypeWithDeep',
87
- fields: () => ({
88
- embeddedId: { type: GraphQLID },
89
- embeddedName: { type: GraphQLString },
90
- deep: {
91
- type: DeepEmbeddedType,
92
- extensions: {
93
- relation: { embedded: true },
94
- },
95
- },
96
- }),
97
- });
98
-
99
- const TestType = new GraphQLObjectType({
100
- name: 'TestTypeWithNestedEmbedded',
101
- fields: () => ({
102
- id: { type: GraphQLID },
103
- name: { type: GraphQLString },
104
- embedded: {
105
- type: EmbeddedType,
106
- extensions: {
107
- relation: { embedded: true },
108
- },
109
- },
110
- }),
111
- });
112
-
113
- // Register the embedded types first
114
- simfinity.addNoEndpointType(DeepEmbeddedType);
115
- simfinity.addNoEndpointType(EmbeddedType);
116
- simfinity.connect(null, TestType, 'testTypeWithNestedEmbedded', 'testTypesWithNestedEmbedded');
117
- simfinity.createSchema();
118
-
119
- // Should create indexes for all ObjectId fields at all levels
120
- expect(indexSpy).toHaveBeenCalledWith({ embeddedId: 1 }); // EmbeddedType
121
- expect(indexSpy).toHaveBeenCalledWith({ 'deep.deepId': 1 }); // DeepEmbeddedType
122
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 }); // TestType
123
- expect(indexSpy).toHaveBeenCalledWith({ 'embedded.embeddedId': 1 }); // embedded field in TestType
124
- expect(indexSpy).toHaveBeenCalledWith({ 'embedded.deep.deepId': 1 }); // nested embedded field in TestType
125
- expect(indexSpy).toHaveBeenCalledTimes(5);
126
- });
127
-
128
- test('should create index for array of embedded objects with ObjectId', () => {
129
- const EmbeddedType = new GraphQLObjectType({
130
- name: 'EmbeddedTypeForArray',
131
- fields: () => ({
132
- embeddedId: { type: GraphQLID },
133
- embeddedName: { type: GraphQLString },
134
- }),
135
- });
136
-
137
- const TestType = new GraphQLObjectType({
138
- name: 'TestTypeWithEmbeddedArray',
139
- fields: () => ({
140
- id: { type: GraphQLID },
141
- name: { type: GraphQLString },
142
- embeddedArray: {
143
- type: new GraphQLList(EmbeddedType),
144
- extensions: {
145
- relation: { embedded: true },
146
- },
147
- },
148
- }),
149
- });
150
-
151
- // Register the embedded type first
152
- simfinity.addNoEndpointType(EmbeddedType);
153
- simfinity.connect(null, TestType, 'testTypeWithEmbeddedArray', 'testTypesWithEmbeddedArray');
154
- simfinity.createSchema();
155
-
156
- // Should create indexes for id and embeddedArray.embeddedId fields
157
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 });
158
- expect(indexSpy).toHaveBeenCalledWith({ 'embeddedArray.embeddedId': 1 });
159
- expect(indexSpy).toHaveBeenCalledTimes(2);
160
- });
161
-
162
- test('should not create index for non-ObjectId fields', () => {
163
- const TestType = new GraphQLObjectType({
164
- name: 'TestTypeWithoutObjectId',
165
- fields: () => ({
166
- id: { type: GraphQLID },
167
- name: { type: GraphQLString },
168
- age: { type: GraphQLString },
169
- active: { type: GraphQLString },
170
- }),
171
- });
172
-
173
- simfinity.connect(null, TestType, 'testTypeWithoutObjectId', 'testTypesWithoutObjectId');
174
- simfinity.createSchema();
175
-
176
- // Should only create index for id field (ObjectId), not for other fields
177
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 });
178
- expect(indexSpy).toHaveBeenCalledTimes(1);
179
- });
180
-
181
- test('should create index for relationship fields (non-embedded)', () => {
182
- const DepartmentType = new GraphQLObjectType({
183
- name: 'DepartmentType',
184
- fields: () => ({
185
- id: { type: GraphQLID },
186
- name: { type: GraphQLString },
187
- }),
188
- });
189
-
190
- const UserType = new GraphQLObjectType({
191
- name: 'TestTypeWithRelationship',
192
- fields: () => ({
193
- id: { type: GraphQLID },
194
- name: { type: GraphQLString },
195
- department: {
196
- type: DepartmentType,
197
- extensions: {
198
- relation: { embedded: false },
199
- },
200
- },
201
- }),
202
- });
203
-
204
- // Register both types
205
- simfinity.connect(null, DepartmentType, 'department', 'departments');
206
- simfinity.connect(null, UserType, 'testTypeWithRelationship', 'testTypesWithRelationship');
207
- simfinity.createSchema();
208
-
209
- // Should create indexes for id fields in both types and the relationship field
210
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 }); // DepartmentType
211
- expect(indexSpy).toHaveBeenCalledWith({ id: 1 }); // UserType
212
- expect(indexSpy).toHaveBeenCalledWith({ department: 1 }); // relationship field
213
- expect(indexSpy).toHaveBeenCalledTimes(3);
214
- });
215
- });
@@ -1,67 +0,0 @@
1
- import {
2
- describe, test, expect, beforeEach, afterEach, vi,
3
- } from 'vitest';
4
- import mongoose from 'mongoose';
5
- import { GraphQLObjectType, GraphQLString, GraphQLID } from 'graphql';
6
- import * as simfinity from '../src/index.js';
7
-
8
- describe('preventCreatingCollection option', () => {
9
- let createCollectionSpy;
10
-
11
- beforeEach(() => {
12
- // Spy on the createCollection method of the mongoose model prototype
13
- createCollectionSpy = vi.spyOn(mongoose.Model, 'createCollection').mockImplementation(() => Promise.resolve());
14
- });
15
-
16
- afterEach(() => {
17
- // Restore the original implementation
18
- createCollectionSpy.mockRestore();
19
- });
20
-
21
- test('should create collection by default', () => {
22
- const TestType = new GraphQLObjectType({
23
- name: 'TestTypeDefault',
24
- fields: () => ({
25
- id: { type: GraphQLID },
26
- name: { type: GraphQLString },
27
- }),
28
- });
29
-
30
- simfinity.connect(null, TestType, 'testTypeDefault', 'testTypesDefault');
31
- simfinity.createSchema(); // Models are now generated during schema creation
32
- expect(createCollectionSpy).toHaveBeenCalledTimes(1);
33
- });
34
-
35
- test('should NOT create collection when preventCreatingCollection is true', () => {
36
- simfinity.preventCreatingCollection(true);
37
-
38
- const TestType = new GraphQLObjectType({
39
- name: 'TestTypePrevent',
40
- fields: () => ({
41
- id: { type: GraphQLID },
42
- name: { type: GraphQLString },
43
- }),
44
- });
45
-
46
- simfinity.connect(null, TestType, 'testTypePrevent', 'testTypesPrevent');
47
- simfinity.createSchema(); // Models are now generated during schema creation
48
- expect(createCollectionSpy).not.toHaveBeenCalled();
49
- });
50
-
51
- test('should create collection when preventCreatingCollection is set back to false', () => {
52
- simfinity.preventCreatingCollection(true); // first prevent
53
- simfinity.preventCreatingCollection(false); // then allow
54
-
55
- const TestType = new GraphQLObjectType({
56
- name: 'TestTypeAllow',
57
- fields: () => ({
58
- id: { type: GraphQLID },
59
- name: { type: GraphQLString },
60
- }),
61
- });
62
-
63
- simfinity.connect(null, TestType, 'testTypeAllow', 'testTypesAllow');
64
- simfinity.createSchema(); // Models are now generated during schema creation
65
- expect(createCollectionSpy).toHaveBeenCalledTimes(1);
66
- });
67
- });