1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 05:09:42 +02:00
documize/edition/storage/postgresql.go
HarveyKandola 8a65567169 Implement PostgreSQL Full Text Search++
1. Full text search supports MySQL, MariaDB, Percona and now PostgreSQL.
2. Changed SQL Variant to typed enum.
3. Changed doc.Versioned from INT to BOOL.
4. Search Reindexer now parses all documents and attachments.
5. Site meta API call returns storage provider type.
6. README prep'ed for PostgreSQL support.
7. DELETE SQL statements ignore zero rows affected.

Closes #100 !!!

Co-Authored-By: Saul S <sauls8t@users.noreply.github.com>
Co-Authored-By: McMatts <matt@documize.com>
2018-09-28 16:33:15 +01:00

298 lines
8.9 KiB
Go

// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
// Package storage sets up database persistence providers.
package storage
import (
"fmt"
"strings"
"github.com/documize/community/core/env"
account "github.com/documize/community/domain/account"
activity "github.com/documize/community/domain/activity"
attachment "github.com/documize/community/domain/attachment"
audit "github.com/documize/community/domain/audit"
block "github.com/documize/community/domain/block"
category "github.com/documize/community/domain/category"
document "github.com/documize/community/domain/document"
group "github.com/documize/community/domain/group"
link "github.com/documize/community/domain/link"
meta "github.com/documize/community/domain/meta"
org "github.com/documize/community/domain/organization"
page "github.com/documize/community/domain/page"
permission "github.com/documize/community/domain/permission"
pin "github.com/documize/community/domain/pin"
search "github.com/documize/community/domain/search"
setting "github.com/documize/community/domain/setting"
space "github.com/documize/community/domain/space"
"github.com/documize/community/domain/store"
user "github.com/documize/community/domain/user"
_ "github.com/lib/pq" // the mysql driver is required behind the scenes
)
// PostgreSQLProvider supports by popular demand.
type PostgreSQLProvider struct {
// User specified connection string.
ConnectionString string
// Unused for this provider.
Variant env.StoreType
}
// SetPostgreSQLProvider creates PostgreSQL provider
func SetPostgreSQLProvider(r *env.Runtime, s *store.Store) {
// Set up provider specific details.
r.StoreProvider = PostgreSQLProvider{
ConnectionString: r.Flags.DBConn,
Variant: env.StoreTypePostgreSQL,
}
// Wire up data providers.
// Account
accountStore := account.Store{}
accountStore.Runtime = r
s.Account = accountStore
// Activity
activityStore := activity.Store{}
activityStore.Runtime = r
s.Activity = activityStore
// Attachment
attachmentStore := attachment.Store{}
attachmentStore.Runtime = r
s.Attachment = attachmentStore
// Audit
auditStore := audit.Store{}
auditStore.Runtime = r
s.Audit = auditStore
// Section Template
blockStore := block.Store{}
blockStore.Runtime = r
s.Block = blockStore
// Category
categoryStore := category.Store{}
categoryStore.Runtime = r
s.Category = categoryStore
// Document
documentStore := document.Store{}
documentStore.Runtime = r
s.Document = documentStore
// Group
groupStore := group.Store{}
groupStore.Runtime = r
s.Group = groupStore
// Link
linkStore := link.Store{}
linkStore.Runtime = r
s.Link = linkStore
// Meta
metaStore := meta.Store{}
metaStore.Runtime = r
s.Meta = metaStore
// Organization (tenant)
orgStore := org.Store{}
orgStore.Runtime = r
s.Organization = orgStore
// Page (section)
pageStore := page.Store{}
pageStore.Runtime = r
s.Page = pageStore
// Permission
permissionStore := permission.Store{}
permissionStore.Runtime = r
s.Permission = permissionStore
// Pin
pinStore := pin.Store{}
pinStore.Runtime = r
s.Pin = pinStore
// Search
searchStore := search.Store{}
searchStore.Runtime = r
s.Search = searchStore
// Setting
settingStore := setting.Store{}
settingStore.Runtime = r
s.Setting = settingStore
// Space
spaceStore := space.Store{}
spaceStore.Runtime = r
s.Space = spaceStore
// User
userStore := user.Store{}
userStore.Runtime = r
s.User = userStore
}
// Type returns name of provider
func (p PostgreSQLProvider) Type() env.StoreType {
return env.StoreTypePostgreSQL
}
// TypeVariant returns databse flavor
func (p PostgreSQLProvider) TypeVariant() env.StoreType {
return p.Variant
}
// DriverName returns database/sql driver name.
func (p PostgreSQLProvider) DriverName() string {
return "postgres"
}
// Params returns connection string parameters that must be present before connecting to DB.
func (p PostgreSQLProvider) Params() map[string]string {
// Not used for this provider.
return map[string]string{}
}
// Example holds storage provider specific connection string format.
// used in error messages
func (p PostgreSQLProvider) Example() string {
return "database connection string format is 'host=localhost port=5432 sslmode=disable user=admin password=secret dbname=documize'"
}
// DatabaseName holds the SQL database name where Documize tables live.
func (p PostgreSQLProvider) DatabaseName() string {
bits := strings.Split(p.ConnectionString, " ")
for _, s := range bits {
s = strings.TrimSpace(s)
if strings.Contains(s, "dbname=") {
s = strings.Replace(s, "dbname=", "", 1)
return s
}
}
return ""
}
// MakeConnectionString returns provider specific DB connection string
// complete with default parameters.
func (p PostgreSQLProvider) MakeConnectionString() string {
// No special processing so return as-is.
return p.ConnectionString
}
// QueryMeta is how to extract version number, collation, character set from database provider.
func (p PostgreSQLProvider) QueryMeta() string {
// SELECT version() as vstring, current_setting('server_version_num') as vnumber, pg_encoding_to_char(encoding) AS charset FROM pg_database WHERE datname = 'documize';
return fmt.Sprintf(`SELECT cast(current_setting('server_version_num') AS TEXT) AS version, version() AS comment, pg_encoding_to_char(encoding) AS charset, '' AS collation
FROM pg_database WHERE datname = '%s'`, p.DatabaseName())
}
// // QueryStartLock locks database tables.
// func (p PostgreSQLProvider) QueryStartLock() string {
// return ""
// }
// // QueryFinishLock unlocks database tables.
// func (p PostgreSQLProvider) QueryFinishLock() string {
// return ""
// }
// // QueryInsertProcessID returns database specific query that will
// // insert ID of this running process.
// func (p PostgreSQLProvider) QueryInsertProcessID() string {
// return ""
// }
// // QueryDeleteProcessID returns database specific query that will
// // delete ID of this running process.
// func (p PostgreSQLProvider) QueryDeleteProcessID() string {
// return ""
// }
// QueryRecordVersionUpgrade returns database specific insert statement
// that records the database version number.
func (p PostgreSQLProvider) QueryRecordVersionUpgrade(version int) string {
// Make record that holds new database version number.
json := fmt.Sprintf("{\"database\": \"%d\"}", version)
return fmt.Sprintf(`INSERT INTO dmz_config (c_key,c_config) VALUES ('META','%s')
ON CONFLICT (c_key) DO UPDATE SET c_config='%s' WHERE dmz_config.c_key='META'`, json, json)
}
// QueryRecordVersionUpgradeLegacy returns database specific insert statement
// that records the database version number.
func (p PostgreSQLProvider) QueryRecordVersionUpgradeLegacy(version int) string {
// This provider has no legacy schema.
return p.QueryRecordVersionUpgrade(version)
}
// QueryGetDatabaseVersion returns the schema version number.
func (p PostgreSQLProvider) QueryGetDatabaseVersion() string {
return "SELECT c_config -> 'database' FROM dmz_config WHERE c_key = 'META';"
}
// QueryGetDatabaseVersionLegacy returns the schema version number before The Great Schema Migration (v25, MySQL).
func (p PostgreSQLProvider) QueryGetDatabaseVersionLegacy() string {
// This provider has no legacy schema.
return p.QueryGetDatabaseVersion()
}
// QueryTableList returns a list tables in Documize database.
func (p PostgreSQLProvider) QueryTableList() string {
return fmt.Sprintf(`select table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') AND table_catalog='%s'`, p.DatabaseName())
}
// JSONEmpty returns empty SQL JSON object.
// Typically used as 2nd parameter to COALESCE().
func (p PostgreSQLProvider) JSONEmpty() string {
return "'{}'::json"
}
// JSONGetValue returns JSON attribute selection syntax.
// Typically used in SELECT <my_json_field> query.
func (p PostgreSQLProvider) JSONGetValue(column, attribute string) string {
if len(attribute) > 0 {
return fmt.Sprintf("%s -> '%s'", column, attribute)
}
return fmt.Sprintf("%s", column)
}
// VerfiyVersion checks to see if actual database meets
// minimum version requirements.``
func (p PostgreSQLProvider) VerfiyVersion(dbVersion string) (bool, string) {
// All versions supported.
return true, ""
}
// VerfiyCharacterCollation needs to ensure utf8.
func (p PostgreSQLProvider) VerfiyCharacterCollation(charset, collation string) (charOK bool, requirements string) {
if strings.ToLower(charset) != "utf8" {
return false, fmt.Sprintf("PostgreSQL character set needs to be utf8, found %s", charset)
}
// Collation check ignored.
return true, ""
}