@simtlix/simfinity-js 1.2.0 → 1.3.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.
@@ -0,0 +1,63 @@
1
+ const mongoose = require('mongoose');
2
+ const { GraphQLObjectType, GraphQLString, GraphQLID } = require('graphql');
3
+ const simfinity = require('../src/index');
4
+
5
+ describe('preventCreatingCollection option', () => {
6
+ let createCollectionSpy;
7
+
8
+ beforeEach(() => {
9
+ // Reset modules to have a clean state for each test
10
+ jest.resetModules();
11
+ // Spy on the createCollection method of the mongoose model prototype
12
+ createCollectionSpy = jest.spyOn(mongoose.Model, 'createCollection').mockImplementation(() => Promise.resolve());
13
+ });
14
+
15
+ afterEach(() => {
16
+ // Restore the original implementation
17
+ createCollectionSpy.mockRestore();
18
+ });
19
+
20
+ test('should create collection by default', () => {
21
+ const TestType = new GraphQLObjectType({
22
+ name: 'TestTypeDefault',
23
+ fields: () => ({
24
+ id: { type: GraphQLID },
25
+ name: { type: GraphQLString },
26
+ }),
27
+ });
28
+
29
+ simfinity.connect(null, TestType, 'testTypeDefault', 'testTypesDefault');
30
+ expect(createCollectionSpy).toHaveBeenCalledTimes(1);
31
+ });
32
+
33
+ test('should NOT create collection when preventCreatingCollection is true', () => {
34
+ simfinity.preventCreatingCollection(true);
35
+
36
+ const TestType = new GraphQLObjectType({
37
+ name: 'TestTypePrevent',
38
+ fields: () => ({
39
+ id: { type: GraphQLID },
40
+ name: { type: GraphQLString },
41
+ }),
42
+ });
43
+
44
+ simfinity.connect(null, TestType, 'testTypePrevent', 'testTypesPrevent');
45
+ expect(createCollectionSpy).not.toHaveBeenCalled();
46
+ });
47
+
48
+ test('should create collection when preventCreatingCollection is set back to false', () => {
49
+ simfinity.preventCreatingCollection(true); // first prevent
50
+ simfinity.preventCreatingCollection(false); // then allow
51
+
52
+ const TestType = new GraphQLObjectType({
53
+ name: 'TestTypeAllow',
54
+ fields: () => ({
55
+ id: { type: GraphQLID },
56
+ name: { type: GraphQLString },
57
+ }),
58
+ });
59
+
60
+ simfinity.connect(null, TestType, 'testTypeAllow', 'testTypesAllow');
61
+ expect(createCollectionSpy).toHaveBeenCalledTimes(1);
62
+ });
63
+ });
@@ -0,0 +1,167 @@
1
+ const {
2
+ GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLID, GraphQLList, GraphQLNonNull,
3
+ } = require('graphql');
4
+ const { createValidatedScalar } = require('../src/index');
5
+ const simfinity = require('../src/index');
6
+
7
+ describe('Custom Validated Scalar Types', () => {
8
+ let EmailScalar;
9
+ let PositiveIntScalar;
10
+ let PhoneScalar;
11
+ let UserType;
12
+
13
+ beforeAll(() => {
14
+ simfinity.preventCreatingCollection(true);
15
+ // Create custom validated scalar types
16
+ EmailScalar = createValidatedScalar(
17
+ 'Email',
18
+ 'A valid email address',
19
+ GraphQLString,
20
+ (value) => {
21
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
22
+ if (!emailRegex.test(value)) {
23
+ throw new Error('Invalid email format');
24
+ }
25
+ },
26
+ );
27
+
28
+ PositiveIntScalar = createValidatedScalar(
29
+ 'PositiveInt',
30
+ 'A positive integer',
31
+ GraphQLInt,
32
+ (value) => {
33
+ if (value <= 0) {
34
+ throw new Error('Value must be positive');
35
+ }
36
+ },
37
+ );
38
+
39
+ PhoneScalar = createValidatedScalar(
40
+ 'Phone',
41
+ 'A valid phone number',
42
+ GraphQLString,
43
+ (value) => {
44
+ const phoneRegex = /^\+?[\d\s\-()]+$/;
45
+ if (!phoneRegex.test(value)) {
46
+ throw new Error('Invalid phone number format');
47
+ }
48
+ },
49
+ );
50
+
51
+ // Create a test type with custom scalars
52
+ UserType = new GraphQLObjectType({
53
+ name: 'User',
54
+ fields: () => ({
55
+ id: { type: GraphQLID },
56
+ name: { type: GraphQLString },
57
+ email: { type: EmailScalar },
58
+ age: { type: PositiveIntScalar },
59
+ phone: { type: PhoneScalar },
60
+ emails: { type: new GraphQLList(EmailScalar) },
61
+ requiredEmail: { type: new GraphQLNonNull(EmailScalar) },
62
+ ages: { type: new GraphQLList(PositiveIntScalar) },
63
+ }),
64
+ });
65
+ });
66
+
67
+ describe('createValidatedScalar function', () => {
68
+ test('should create a valid scalar type with baseScalarType property', () => {
69
+ expect(EmailScalar).toBeDefined();
70
+ expect(EmailScalar.name).toBe('Email');
71
+ expect(EmailScalar.baseScalarType).toBe(GraphQLString);
72
+ expect(EmailScalar.serialize).toBeDefined();
73
+ expect(EmailScalar.parseValue).toBeDefined();
74
+ expect(EmailScalar.parseLiteral).toBeDefined();
75
+ });
76
+
77
+ test('should validate baseScalarType parameter', () => {
78
+ expect(() => {
79
+ createValidatedScalar('Test', 'Test', null, () => {});
80
+ }).toThrow('baseScalarType is required');
81
+
82
+ expect(() => {
83
+ createValidatedScalar('Test', 'Test', 'not a scalar', () => {});
84
+ }).toThrow('baseScalarType must be a valid GraphQL scalar type');
85
+ });
86
+
87
+ test('should handle different base scalar types', () => {
88
+ expect(PositiveIntScalar.baseScalarType).toBe(GraphQLInt);
89
+ expect(PhoneScalar.baseScalarType).toBe(GraphQLString);
90
+ });
91
+ });
92
+
93
+ describe('Custom scalar validation', () => {
94
+ test('should validate email format correctly', () => {
95
+ expect(() => EmailScalar.serialize('test@example.com')).not.toThrow();
96
+ expect(() => EmailScalar.serialize('invalid-email')).toThrow('Invalid email format');
97
+ });
98
+
99
+ test('should validate positive integers correctly', () => {
100
+ expect(() => PositiveIntScalar.serialize(5)).not.toThrow();
101
+ expect(() => PositiveIntScalar.serialize(0)).toThrow('Value must be positive');
102
+ expect(() => PositiveIntScalar.serialize(-1)).toThrow('Value must be positive');
103
+ });
104
+
105
+ test('should validate phone numbers correctly', () => {
106
+ expect(() => PhoneScalar.serialize('+1-555-123-4567')).not.toThrow();
107
+ expect(() => PhoneScalar.serialize('555-123-4567')).not.toThrow();
108
+ expect(() => PhoneScalar.serialize('invalid phone')).toThrow('Invalid phone number format');
109
+ });
110
+ });
111
+
112
+ describe('Schema generation with custom scalars', () => {
113
+ let UserModel;
114
+
115
+ beforeAll(() => {
116
+ simfinity.connect(null, UserType, 'user', 'users');
117
+ UserModel = simfinity.getModel(UserType);
118
+ });
119
+
120
+ test('should generate schema with correct types for custom scalars', () => {
121
+ const schema = UserModel.schema.obj;
122
+
123
+ // Test individual fields
124
+ expect(schema.email).toBe(String);
125
+ expect(schema.age).toBe(Number);
126
+ expect(schema.phone).toBe(String);
127
+
128
+ // Test array fields
129
+ expect(Array.isArray(schema.emails)).toBe(true);
130
+ expect(schema.emails[0]).toBe(String);
131
+ expect(Array.isArray(schema.ages)).toBe(true);
132
+ expect(schema.ages[0]).toBe(Number);
133
+
134
+ // Test required fields
135
+ expect(schema.requiredEmail).toBe(String);
136
+ });
137
+
138
+ test('should preserve unique constraints', () => {
139
+ const UserWithUniqueType = new GraphQLObjectType({
140
+ name: 'UserWithUnique',
141
+ fields: () => ({
142
+ id: { type: GraphQLID },
143
+ email: {
144
+ type: EmailScalar,
145
+ extensions: { unique: true },
146
+ },
147
+ }),
148
+ });
149
+ simfinity.connect(null, UserWithUniqueType, 'userWithUnique', 'usersWithUnique');
150
+ const UserWithUniqueModel = simfinity.getModel(UserWithUniqueType);
151
+ const schema = UserWithUniqueModel.schema.obj;
152
+
153
+ expect(schema.email).toEqual({ type: String, unique: true });
154
+ });
155
+ });
156
+
157
+ describe('GraphQL schema integration', () => {
158
+ test('should create valid GraphQL schema with custom scalars', () => {
159
+ const schema = simfinity.createSchema();
160
+
161
+ // The schema should be created without errors
162
+ expect(schema).toBeDefined();
163
+ expect(schema.getQueryType()).toBeDefined();
164
+ expect(schema.getMutationType()).toBeDefined();
165
+ });
166
+ });
167
+ });
package/.eslintignore DELETED
@@ -1,2 +0,0 @@
1
- node_modules/*
2
- data/*
package/.eslintrc.json DELETED
@@ -1,38 +0,0 @@
1
- {
2
- "env": {
3
- "commonjs": true,
4
- "es2020": true,
5
- "node": true,
6
- "jest": true
7
- },
8
- "extends": [
9
- "airbnb-base"
10
- ],
11
- "parserOptions": {
12
- "ecmaVersion": 9
13
- },
14
- "rules": {
15
- "default-case": "off",
16
- "max-len": 0,
17
- "no-console":"off",
18
- "no-underscore-dangle": "off",
19
- "no-await-in-loop": "off",
20
- "no-param-reassign": ["error", { "props": false }],
21
- "no-restricted-syntax": [
22
- "error",
23
- {
24
- "selector": "ForInStatement",
25
- "message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array."
26
- },
27
- {
28
- "selector": "LabeledStatement",
29
- "message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand."
30
- },
31
- {
32
- "selector": "WithStatement",
33
- "message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
34
- }
35
- ],
36
- "import/no-unresolved": ["error", { "ignore": ["graphql", "mongoose"] }]
37
- }
38
- }