2022-10-09 18:54:14 +00:00
package couchbase
import (
2022-12-18 06:04:03 +00:00
"context"
"errors"
2022-12-17 10:35:13 +00:00
"fmt"
2022-10-09 18:54:14 +00:00
"os"
2022-12-18 06:04:03 +00:00
"reflect"
2022-10-09 18:54:14 +00:00
"github.com/authorizerdev/authorizer/server/constants"
2022-12-18 06:04:03 +00:00
"github.com/authorizerdev/authorizer/server/db/models"
2022-10-09 18:54:14 +00:00
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/couchbase/gocb/v2"
)
// TODO change following provider to new db provider
type provider struct {
2022-12-17 10:35:13 +00:00
db * gocb . Scope
scopeName string
2022-10-09 18:54:14 +00:00
}
// NewProvider returns a new SQL provider
// TODO change following provider to new db provider
func NewProvider ( ) ( * provider , error ) {
2022-12-01 09:28:35 +00:00
// scopeName := os.Getenv(constants.EnvCouchbaseScope)
2022-10-09 18:54:14 +00:00
bucketName := os . Getenv ( constants . EnvCouchbaseBucket )
2022-12-17 10:35:13 +00:00
scopeName := os . Getenv ( constants . EnvCouchbaseScope )
2022-10-09 18:54:14 +00:00
dbURL := memorystore . RequiredEnvStoreObj . GetRequiredEnv ( ) . DatabaseURL
userName := memorystore . RequiredEnvStoreObj . GetRequiredEnv ( ) . DatabaseUsername
password := memorystore . RequiredEnvStoreObj . GetRequiredEnv ( ) . DatabasePassword
2022-12-18 06:04:03 +00:00
2022-10-09 18:54:14 +00:00
opts := gocb . ClusterOptions {
Username : userName ,
Password : password ,
}
cluster , err := gocb . Connect ( dbURL , opts )
2022-12-18 06:04:03 +00:00
if err != nil {
return nil , err
}
// To create the bucket and scope if not exist
bucket , err := CreateBucketAndScope ( cluster , bucketName , scopeName )
2022-10-09 18:54:14 +00:00
if err != nil {
return nil , err
}
2022-12-01 09:28:35 +00:00
2022-12-18 06:04:03 +00:00
scope := bucket . Scope ( scopeName )
2022-12-01 09:28:35 +00:00
2022-12-18 06:04:03 +00:00
scopeIdentifier := fmt . Sprintf ( "%s.%s" , bucketName , scopeName )
2022-12-01 09:28:35 +00:00
2022-12-18 06:04:03 +00:00
v := reflect . ValueOf ( models . Collections )
for i := 0 ; i < v . NumField ( ) ; i ++ {
field := v . Field ( i )
user := gocb . CollectionSpec {
Name : field . String ( ) ,
ScopeName : scopeName ,
}
collectionOpts := gocb . CreateCollectionOptions {
Context : context . TODO ( ) ,
}
_ = bucket . Collections ( ) . CreateCollection ( user , & collectionOpts )
// if err != nil && !errors.Is(err, gocb.ErrCollectionExists) {
// return nil, err
// }
indexQuery := fmt . Sprintf ( "CREATE PRIMARY INDEX ON %s.%s" , scopeIdentifier , field . String ( ) )
scope . Query ( indexQuery , nil )
}
2022-11-26 12:13:39 +00:00
2022-12-18 06:04:03 +00:00
indices := GetIndex ( scopeIdentifier )
for i := 0 ; i < v . NumField ( ) ; i ++ {
field := v . Field ( i )
for _ , indexQuery := range indices [ field . String ( ) ] {
scope . Query ( indexQuery , nil )
}
}
2022-10-09 18:54:14 +00:00
return & provider {
2022-12-18 06:04:03 +00:00
db : scope ,
scopeName : scopeIdentifier ,
2022-10-09 18:54:14 +00:00
} , nil
}
2022-12-18 06:04:03 +00:00
func CreateBucketAndScope ( cluster * gocb . Cluster , bucketName string , scopeName string ) ( * gocb . Bucket , error ) {
settings := gocb . BucketSettings {
Name : bucketName ,
RAMQuotaMB : 1000 ,
NumReplicas : 1 ,
BucketType : gocb . CouchbaseBucketType ,
EvictionPolicy : gocb . EvictionPolicyTypeValueOnly ,
FlushEnabled : true ,
CompressionMode : gocb . CompressionModeActive ,
}
err := cluster . Buckets ( ) . CreateBucket ( gocb . CreateBucketSettings {
BucketSettings : settings ,
ConflictResolutionType : gocb . ConflictResolutionTypeSequenceNumber ,
} , nil )
bucket := cluster . Bucket ( bucketName )
if err != nil && ! errors . Is ( err , gocb . ErrBucketExists ) {
return bucket , err
}
err = bucket . Collections ( ) . CreateScope ( scopeName , nil )
if err != nil && ! errors . Is ( err , gocb . ErrScopeExists ) {
return bucket , err
}
return bucket , nil
}
func GetIndex ( scopeName string ) map [ string ] [ ] string {
indices := make ( map [ string ] [ ] string )
// User Index
userIndex1 := fmt . Sprintf ( "CREATE INDEX userEmailIndex ON %s.%s(email)" , scopeName , models . Collections . User )
userIndex2 := fmt . Sprintf ( "CREATE INDEX userPhoneIndex ON %s.%s(phone_number)" , scopeName , models . Collections . User )
indices [ models . Collections . User ] = [ ] string { userIndex1 , userIndex2 }
// VerificationRequest
verificationIndex1 := fmt . Sprintf ( "CREATE INDEX verificationRequestTokenIndex ON %s.%s(token)" , scopeName , models . Collections . VerificationRequest )
verificationIndex2 := fmt . Sprintf ( "CREATE INDEX verificationRequestEmailAndIdentifierIndex ON %s.%s(email,identifier)" , scopeName , models . Collections . VerificationRequest )
indices [ models . Collections . VerificationRequest ] = [ ] string { verificationIndex1 , verificationIndex2 }
// Session index
sessionIndex1 := fmt . Sprintf ( "CREATE INDEX SessionUserIdIndex ON %s.%s(user_id)" , scopeName , models . Collections . Session )
indices [ models . Collections . Session ] = [ ] string { sessionIndex1 }
// Webhook index
webhookIndex1 := fmt . Sprintf ( "CREATE INDEX webhookEventNameIndex ON %s.%s(event_name)" , scopeName , models . Collections . Webhook )
indices [ models . Collections . Webhook ] = [ ] string { webhookIndex1 }
// WebhookLog index
webhookLogIndex1 := fmt . Sprintf ( "CREATE INDEX webhookLogIdIndex ON %s.%s(webhook_id)" , scopeName , models . Collections . WebhookLog )
indices [ models . Collections . Webhook ] = [ ] string { webhookLogIndex1 }
// WebhookLog index
emailTempIndex1 := fmt . Sprintf ( "CREATE INDEX EmailTemplateEventNameIndex ON %s.%s(event_name)" , scopeName , models . Collections . EmailTemplate )
indices [ models . Collections . EmailTemplate ] = [ ] string { emailTempIndex1 }
// OTP index
otpIndex1 := fmt . Sprintf ( "CREATE INDEX OTPEmailIndex ON %s.%s(email)" , scopeName , models . Collections . OTP )
indices [ models . Collections . OTP ] = [ ] string { otpIndex1 }
return indices
}