@@ -2,6 +2,7 @@ package mssqlstore
22
33import (
44 "database/sql"
5+ "fmt"
56 "log"
67 "time"
78)
@@ -10,31 +11,59 @@ import (
1011type MSSQLStore struct {
1112 db * sql.DB
1213 stopCleanup chan bool
14+ tableName string
15+ }
16+
17+ type Config struct {
18+ // CleanUpInterval is the interval between each cleanup operation.
19+ // If set to 0, the cleanup operation is disabled.
20+ CleanUpInterval time.Duration
21+
22+ // TableName is the name of the table where the session data will be stored.
23+ // If not set, it will default to "sessions".
24+ TableName string
1325}
1426
1527// New returns a new MSSQLStore instance, with a background cleanup goroutine
1628// that runs every 5 minutes to remove expired session data.
1729func New (db * sql.DB ) * MSSQLStore {
18- return NewWithCleanupInterval (db , 5 * time .Minute )
30+ return NewWithConfig (db , Config {
31+ CleanUpInterval : 5 * time .Minute ,
32+ })
1933}
2034
2135// NewWithCleanupInterval returns a new MSSQLStore instance. The cleanupInterval
2236// parameter controls how frequently expired session data is removed by the
2337// background cleanup goroutine. Setting it to 0 prevents the cleanup goroutine
2438// from running (i.e. expired sessions will not be removed).
2539func NewWithCleanupInterval (db * sql.DB , cleanupInterval time.Duration ) * MSSQLStore {
26- m := & MSSQLStore {db : db }
27- if cleanupInterval > 0 {
28- go m .startCleanup (cleanupInterval )
40+ return NewWithConfig (db , Config {
41+ CleanUpInterval : cleanupInterval ,
42+ })
43+ }
44+
45+ // NewWithConfig returns a new MSSQLStore instance with the given configuration.
46+ // If the TableName field is empty, it will be set to "sessions".
47+ // If the CleanUpInterval field is 0, the cleanup goroutine will not be started.
48+ func NewWithConfig (db * sql.DB , config Config ) * MSSQLStore {
49+ if config .TableName == "" {
50+ config .TableName = "sessions"
2951 }
52+
53+ m := & MSSQLStore {db : db , tableName : config .TableName }
54+ if config .CleanUpInterval > 0 {
55+ go m .startCleanup (config .CleanUpInterval )
56+ }
57+
3058 return m
3159}
3260
3361// Find returns the data for a given session token from the MSSQLStore instance.
3462// If the session token is not found or is expired, the returned exists flag will
3563// be set to false.
3664func (m * MSSQLStore ) Find (token string ) (b []byte , exists bool , err error ) {
37- row := m .db .QueryRow ("SELECT data FROM sessions WHERE token = @p1 AND GETUTCDATE() < expiry" , token )
65+ query := fmt .Sprintf ("SELECT data FROM %s WHERE token = @p1 AND GETUTCDATE() < expiry" , m .tableName )
66+ row := m .db .QueryRow (query , token )
3867 err = row .Scan (& b )
3968 if err == sql .ErrNoRows {
4069 return nil , false , nil
@@ -48,26 +77,26 @@ func (m *MSSQLStore) Find(token string) (b []byte, exists bool, err error) {
4877// given expiry time. If the session token already exists, then the data and expiry
4978// time are updated.
5079func (m * MSSQLStore ) Commit (token string , b []byte , expiry time.Time ) error {
51- _ , err := m .db .Exec (`MERGE INTO sessions WITH (HOLDLOCK) AS T USING (VALUES(@p1)) AS S (token) ON (T.token = S.token)
52- WHEN MATCHED THEN UPDATE SET data = @p2, expiry = @p3
53- WHEN NOT MATCHED THEN INSERT (token, data, expiry) VALUES(@p1, @p2, @p3);` , token , b , expiry .UTC ())
54- if err != nil {
55- return err
56- }
57- return nil
80+ query := fmt .Sprintf (`MERGE INTO %s WITH (HOLDLOCK) AS T USING (VALUES(@p1)) AS S (token) ON (T.token = S.token)
81+ WHEN MATCHED THEN UPDATE SET data = @p2, expiry = @p3
82+ WHEN NOT MATCHED THEN INSERT (token, data, expiry) VALUES(@p1, @p2, @p3);` , m .tableName )
83+ _ , err := m .db .Exec (query , token , b , expiry .UTC ())
84+ return err
5885}
5986
6087// Delete removes a session token and corresponding data from the MSSQLStore
6188// instance.
6289func (m * MSSQLStore ) Delete (token string ) error {
63- _ , err := m .db .Exec ("DELETE FROM sessions WHERE token = @p1" , token )
90+ query := fmt .Sprintf ("DELETE FROM %s WHERE token = @p1" , m .tableName )
91+ _ , err := m .db .Exec (query , token )
6492 return err
6593}
6694
6795// All returns a map containing the token and data for all active (i.e.
6896// not expired) sessions in the MSSQLStore instance.
6997func (m * MSSQLStore ) All () (map [string ][]byte , error ) {
70- rows , err := m .db .Query ("SELECT token, data FROM sessions WHERE GETUTCDATE() < expiry" )
98+ query := fmt .Sprintf ("SELECT token, data FROM %s WHERE GETUTCDATE() < expiry" , m .tableName )
99+ rows , err := m .db .Query (query )
71100 if err != nil {
72101 return nil , err
73102 }
@@ -115,7 +144,7 @@ func (m *MSSQLStore) startCleanup(interval time.Duration) {
115144}
116145
117146// StopCleanup terminates the background cleanup goroutine for the MSSQLStore
118- // instance. It's rare to terminate this; generally MSSQLStore instances and
147+ // instance. It's rare to terminate this; generally MSSQLStore instances and // instance.
119148// their cleanup goroutines are intended to be long-lived and run for the lifetime
120149// of your application.
121150//
@@ -131,6 +160,7 @@ func (m *MSSQLStore) StopCleanup() {
131160}
132161
133162func (m * MSSQLStore ) deleteExpired () error {
134- _ , err := m .db .Exec ("DELETE FROM sessions WHERE expiry < GETUTCDATE()" )
163+ query := fmt .Sprintf ("DELETE FROM %s WHERE expiry < GETUTCDATE()" , m .tableName )
164+ _ , err := m .db .Exec (query )
135165 return err
136166}
0 commit comments