Passed
Pull Request — master (#2609)
by Tolga
02:58
created

factories.DatabaseFactory   F

Complexity

Conditions 16

Size

Total Lines 76
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 44
nop 1
dl 0
loc 76
rs 2.4
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like factories.DatabaseFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package factories
2
3
import (
4
	"fmt"
5
6
	"github.com/Permify/permify/internal/config"
7
	"github.com/Permify/permify/internal/storage/memory/migrations"
8
	"github.com/Permify/permify/internal/storage/postgres/utils" // Postgres utilities
9
	"github.com/Permify/permify/pkg/database"
10
	IMDatabase "github.com/Permify/permify/pkg/database/memory"
11
	PQDatabase "github.com/Permify/permify/pkg/database/postgres"
12
)
13
14
// DatabaseFactory is a factory function that creates a database instance according to the given configuration.
15
// It supports different types of databases, such as PostgreSQL and in-memory databases.
16
//
17
// conf: the configuration object containing the necessary information to create a database connection.
18
//
19
//	It should have the following properties:
20
//	- Engine: the type of the database, e.g., POSTGRES or MEMORY
21
//	- URI: the connection string for the database (only required for some database engines, e.g., POSTGRES)
22
//	- MaxConns: the maximum number of connections in the pool (maps to pgxpool MaxConns)
23
//	- MaxOpenConnections: deprecated, use MaxConns instead
24
//	- MinConns: the minimum number of connections in the pool (maps to pgxpool MinConns)
25
//	- MinIdleConns: the minimum number of idle connections in the pool (maps to pgxpool MinIdleConns)
26
//	- MaxIdleConnections: deprecated, use MinConns instead (maps to MinConns if MinConns is not set)
27
//	- MaxConnectionIdleTime: the maximum amount of time a connection can be idle before being closed
28
//	- MaxConnectionLifetime: the maximum amount of time a connection can be reused before being closed
29
//	- WatchBufferSize: specifies the buffer size for database watch operations, impacting how many changes can be queued
30
//	- MaxDataPerWrite: sets the maximum amount of data per write operation to the database
31
//	- MaxRetries: defines the maximum number of retries for database operations in case of failure
32
//
33
// Returns a database.Database instance if the database connection is successfully created, or an error if the
34
// creation fails or the specified database engine is unsupported.
35
func DatabaseFactory(conf config.Database) (db database.Database, err error) {
36
	switch conf.Engine {
37
	case database.POSTGRES.String():
38
39
		opts := []PQDatabase.Option{
40
			PQDatabase.MaxConnectionIdleTime(conf.MaxConnectionIdleTime),
41
			PQDatabase.MaxConnectionLifeTime(conf.MaxConnectionLifetime),
42
			PQDatabase.WatchBufferSize(conf.WatchBufferSize),
43
			PQDatabase.MaxDataPerWrite(conf.MaxDataPerWrite),
44
			PQDatabase.MaxRetries(conf.MaxRetries),
45
		}
46
47
		// Add MinConns if set (takes precedence over MaxIdleConnections for backward compatibility)
48
		if conf.MinConns > 0 {
49
			opts = append(opts, PQDatabase.MinConns(conf.MinConns))
50
		}
51
52
		// Use MaxConns if set, otherwise fall back to MaxOpenConnections for backward compatibility
53
		// Note: MaxConns defaults to 0 in config, so we check MaxOpenConnections if MaxConns is 0
54
		if conf.MaxConns > 0 {
55
			opts = append(opts, PQDatabase.MaxConns(conf.MaxConns))
56
		} else {
57
			// Backward compatibility: if MaxConns is not set, use MaxOpenConnections
58
			opts = append(opts, PQDatabase.MaxOpenConnections(conf.MaxOpenConnections))
59
		}
60
61
		// Kept for backward compatibility
62
		if conf.MaxIdleConnections > 0 {
63
			opts = append(opts, PQDatabase.MaxIdleConnections(conf.MaxIdleConnections))
64
		}
65
66
		// Add MinIdleConns if set (takes precedence over MaxIdleConnections)
67
		if conf.MinIdleConns > 0 {
68
			opts = append(opts, PQDatabase.MinIdleConns(conf.MinIdleConns))
69
		}
70
71
		// Add optional pool configuration options if set
72
		if conf.HealthCheckPeriod > 0 {
73
			opts = append(opts, PQDatabase.HealthCheckPeriod(conf.HealthCheckPeriod))
74
		}
75
		if conf.MaxConnLifetimeJitter > 0 {
76
			opts = append(opts, PQDatabase.MaxConnLifetimeJitter(conf.MaxConnLifetimeJitter))
77
		}
78
		if conf.ConnectTimeout > 0 {
79
			opts = append(opts, PQDatabase.ConnectTimeout(conf.ConnectTimeout))
80
		}
81
82
		if conf.URI == "" {
83
			db, err = PQDatabase.NewWithSeparateURIs(conf.Writer.URI, conf.Reader.URI, opts...)
84
			if err != nil {
85
				return nil, err
86
			}
87
		} else {
88
			db, err = PQDatabase.New(conf.URI, opts...)
89
			if err != nil {
90
				return nil, err
91
			}
92
		}
93
94
		// Verify postgres version compatibility
95
		// Check postgres version compatibility with the database
96
		_, err = utils.EnsureDBVersion(db.(*PQDatabase.Postgres).ReadPool)
97
		if err != nil { // Version check failed
98
			return nil, err // Return version error
99
		}
100
		// Return database instance
101
102
		return db, err
103
	case database.MEMORY.String():
104
		db, err = IMDatabase.New(migrations.Schema)
105
		if err != nil {
106
			return nil, err
107
		}
108
		return db, err
109
	default:
110
		return nil, fmt.Errorf("%s connection is unsupported", conf.Engine)
111
	}
112
}
113