DatabaseConfig Developer Documentation¶
- DatabaseConfig Developer Documentation
- Overview
- Constants
- Configuration Properties
- Constructor
- API Reference
- Public Methods
clone()toJSON()fromJSON(obj)- Private Methods
_initialiseGeneralDefaults(config)_initialiseRetryConfig(config)_initialiseQueryEngineConfig(config)_initialiseBooleanFlags(config)_getDefaultRootFolder()_validateConfig()_validateQueryOperators()_validateOperatorArray(configKey, operators, rawValue, wasProvided)
- Validation Rules
- Usage Examples
- Integration with Database
- Component-Level Configuration
- Best Practices
Overview¶
The DatabaseConfig class manages database configuration settings with validation and defaults. It provides a standardized configuration object for Database instances, ensuring all settings are validated and properly formatted before use.
Key Responsibilities:
- Configuration validation and normalization
- Default value management
- Type checking and constraint enforcement
- Configuration cloning and serialization
Design Principles:
- Fail-fast validation in constructor
- Configuration intended to be treated as immutable after creation
- Clear error messages for invalid settings
- Sensible defaults for all properties
Constants¶
DatabaseConfig internally defines shared constants for log handling so the configuration stays in sync with JDbLogger behaviour. These are implementation details used for validation and are not exposed as public static properties or part of the public API:
LOG_LEVELS: ordered array of accepted level names (['DEBUG','INFO','WARN','ERROR']) used during validation.DEFAULT_LOG_LEVEL: default value ('INFO') applied when no explicit level is supplied.
Configuration Properties¶
Core Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
rootFolderId |
String | Drive root folder | Root Drive folder for database files |
masterIndexKey |
String | 'GASDB_MASTER_INDEX' | ScriptProperties key for master index |
Optional Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
autoCreateCollections |
Boolean | true |
Auto-create collections when accessed |
lockTimeout |
Number | 30000 |
Legacy compatibility alias for collectionLockLeaseMs; when provided on its own it seeds both timeout settings |
collectionLockLeaseMs |
Number | 30000 |
Collection lock lease duration in milliseconds; must be at least as long as coordinationTimeoutMs |
coordinationTimeoutMs |
Number | 30000 |
Maximum duration allowed for a coordinated collection operation |
retryAttempts |
Number | 3 |
Lock acquisition retry attempts |
retryDelayMs |
Number | 1000 |
Delay between lock retries |
lockRetryBackoffBase |
Number | 2 |
Exponential backoff base for lock retries |
cacheEnabled |
Boolean | true |
Enable file caching |
logLevel |
String | DEFAULT_LOG_LEVEL ('INFO') |
Log level constrained to the values declared in LOG_LEVELS |
fileRetryAttempts |
Number | 3 |
File operation retry attempts |
fileRetryDelayMs |
Number | 1000 |
Delay between file retries |
fileRetryBackoffBase |
Number | 2 |
Exponential backoff base for file retries |
queryEngineMaxNestedDepth |
Number | 10 |
Maximum allowed query nesting depth |
queryEngineSupportedOperators |
String[] | ['$eq','$gt','$lt','$and','$or'] |
Operators permitted by the QueryEngine |
queryEngineLogicalOperators |
String[] | ['$and','$or'] |
Logical operators recognised by the QueryEngine |
backupOnInitialise |
Boolean | false |
If true, Database.initialise() will create/find the Drive index file and back up the MasterIndex immediately. If false, the backup index is created lazily on first write (e.g. creating/dropping a collection) or when loadIndex() is called. |
stripDisallowedCollectionNameCharacters |
Boolean | false |
When enabled, invalid characters are stripped from collection names before validation so integrations that cannot guarantee clean inputs can still rely on strict reserved-name and empty-name checks. |
Constructor¶
Parameters:
config(Object): Configuration options object
Behaviour:
- Delegates to grouped helpers (
_initialiseGeneralDefaults,_initialiseRetryConfig,_initialiseQueryEngineConfig,_initialiseBooleanFlags) so each concern applies defaults consistently. - Uses nullish coalescing (
??) to normalise nullish overrides while keeping explicit falsy values intact. - Sets default values for all properties
- Validates all configuration parameters
- Throws errors immediately for invalid settings
- Automatically determines root folder if not provided
Example:
const config = new DatabaseConfig({
rootFolderId: 'your-folder-id',
autoCreateCollections: false,
logLevel: 'DEBUG'
});
API Reference¶
Public Methods¶
clone()¶
Creates a deep copy of the configuration.
- Returns:
DatabaseConfig- New configuration instance - Use Cases:
- Creating modified configurations
- Immutable configuration management
- Testing with variations
toJSON()¶
Converts configuration to a serialisable plain object with a __type tag.
- Returns:
Object- Plain object suitable for JSON serialisation - Use Cases:
- Serialisation
- Debugging and logging
- Configuration comparison
fromJSON(obj)¶
Creates a DatabaseConfig from an object produced by toJSON().
- Parameters:
obj(Object) - A deserialised config object containing__type: 'DatabaseConfig' - Returns:
DatabaseConfig - Throws:
InvalidArgumentErrorif the object is not a validDatabaseConfigserialisation
Private Methods¶
_initialiseGeneralDefaults(config)¶
Applies root folder, split coordination timing defaults, log level (via DEFAULT_LOG_LEVEL), and master index defaults.
_initialiseRetryConfig(config)¶
Normalises retry-related options (lock and file retries) with grouped defaults.
_initialiseQueryEngineConfig(config)¶
Clones provided operator arrays when supplied and records raw values for validation while restoring defaults when omitted.
_initialiseBooleanFlags(config)¶
Initialises boolean feature toggles such as autoCreateCollections and backupOnInitialise.
_getDefaultRootFolder()¶
Determines the default root folder ID.
- Returns:
String- Drive root folder ID - Throws:
Errorif unable to access Drive - Behaviour: Uses
DriveApp.getRootFolder().getId()
_validateConfig()¶
Validates all configuration properties according to rules.
- Throws:
Errorfor any validation failure - Validation Order:
- Type checking
- Range validation
- Format validation
- Constraint checking
_validateQueryOperators()¶
Ensures logical operators are a subset of supported operators and raises INVALID_ARGUMENT when alignment fails.
_validateOperatorArray(configKey, operators, rawValue, wasProvided)¶
Validates optional operator arrays against type constraints and preserves the original error context.
Validation Rules¶
Property Validation¶
lockTimeout / collectionLockLeaseMs / coordinationTimeoutMs:
- Each value must be a number of at least 500ms
lockTimeoutis retained as a legacy alias; new code should prefer the split propertiescollectionLockLeaseMsmust be greater than or equal tocoordinationTimeoutMsCollectionCoordinatormay renew a lease shortly before final metadata persistence, but the configured lease should still comfortably cover the main write callback- Recommended range: 5000-60000ms unless you have a measured need for longer operations
- Zero is invalid because the minimum is enforced during validation
retryAttempts / retryDelayMs / lockRetryBackoffBase:
retryAttemptsmust be a positive integerretryDelayMsmust be a non-negative numberlockRetryBackoffBasemust be a positive number
logLevel:
- Must be one of the entries in
LOG_LEVELS(currently 'DEBUG', 'INFO', 'WARN', 'ERROR') - Case-sensitive validation
- Defaults to
DEFAULT_LOG_LEVELto remain consistent withJDbLogger - Affects logging verbosity across the system
rootFolderId:
- Must be a valid string if provided
- Auto-detected if not specified
- Should correspond to accessible Drive folder
- Default root folder lookups are cached after first access to avoid repeated Drive API calls
Boolean Properties:
autoCreateCollections: Must be true or falsecacheEnabled: Must be true or false- Type coercion not performed
stripDisallowedCollectionNameCharacters: Must be true or false; defaultfalseenforces strict rejection of invalid names, whiletrueenables sanitisation.
masterIndexKey:
- Must be a non-empty string
- Used as ScriptProperties key
- Should be unique per database instance
File retry settings:
fileRetryAttemptsmust be a positive integerfileRetryDelayMsmust be a non-negative numberfileRetryBackoffBasemust be a positive number
QueryEngine settings:
queryEngineMaxNestedDepthmust be an integer greater than or equal to zeroqueryEngineSupportedOperatorsmust be a non-empty array of non-empty stringsqueryEngineLogicalOperatorsmust be a non-empty array of non-empty strings, each present inqueryEngineSupportedOperators
Error Scenarios¶
Common validation errors and their meanings:
| Error Message | Cause | Solution |
|---|---|---|
| "Lock timeout must be a number" | Invalid timeout value | Use a number of at least 500ms |
| "Log level must be one of: DEBUG, INFO, WARN, ERROR" | Invalid log level | Use exact string match |
| "Auto create collections must be a boolean" | Non-boolean value | Use true or false explicitly |
| "Failed to get default root folder" | Drive access issue | Check permissions and authentication |
| "Collection sanitisation flag must be a boolean" | Non-boolean value for stripDisallowedCollectionNameCharacters |
Use true or false explicitly |
Usage Examples¶
Basic Configuration¶
// Minimal configuration (uses defaults)
const config = new DatabaseConfig();
// Custom root folder
const config = new DatabaseConfig({
rootFolderId: '1ABC123xyz789'
});
// Production-ready configuration
const config = new DatabaseConfig({
rootFolderId: 'prod-folder-id',
autoCreateCollections: false,
collectionLockLeaseMs: 12000,
coordinationTimeoutMs: 10000,
logLevel: 'WARN',
// Avoid Drive file churn on start; backups occur lazily or explicitly
backupOnInitialise: false
});
Development vs Production¶
// Development configuration
const devConfig = new DatabaseConfig({
autoCreateCollections: true,
logLevel: 'DEBUG',
cacheEnabled: true,
// Enable eager backup if you want an index snapshot each initialise
backupOnInitialise: true,
// Looser query depth for exploratory work
queryEngineMaxNestedDepth: 12
});
// Production configuration
const prodConfig = new DatabaseConfig({
rootFolderId: 'production-folder-id',
autoCreateCollections: false,
collectionLockLeaseMs: 8000,
coordinationTimeoutMs: 5000,
logLevel: 'ERROR',
cacheEnabled: true,
backupOnInitialise: false
});
Configuration Cloning¶
const baseConfig = new DatabaseConfig({
rootFolderId: 'base-folder',
logLevel: 'INFO'
});
// Create variation for testing
const testConfig = baseConfig.clone();
// Note: Properties are read-only after creation
// Clone and create new instance for modifications
const modifiedConfig = new DatabaseConfig({
...baseConfig.toJSON(),
logLevel: 'DEBUG'
});
Configuration Serialization¶
const config = new DatabaseConfig({
autoCreateCollections: false,
collectionLockLeaseMs: 20000,
coordinationTimeoutMs: 15000
});
// Serialize for storage or logging
const configData = config.toJSON();
console.log('Config:', JSON.stringify(configData, null, 2));
// Recreate from serialised data
const restoredConfig = DatabaseConfig.fromJSON(configData);
Integration with Database¶
The DatabaseConfig class integrates seamlessly with the Database class. For Apps Script consumers, prefer the public API factories:
// First-time setup
const db1 = JsonDbApp.createAndInitialiseDatabase(
new DatabaseConfig({
masterIndexKey: 'myMasterIndex'
})
);
// Load existing database
const db2 = JsonDbApp.loadDatabase({
masterIndexKey: 'myMasterIndex',
logLevel: 'DEBUG',
// Only back up MasterIndex to Drive during initialise when explicitly enabled
backupOnInitialise: false
});
// Configuration is validated when constructing DatabaseConfig/Database
try {
JsonDbApp.loadDatabase({ coordinationTimeoutMs: -1 }); // Will throw
} catch (error) {
console.error('Invalid configuration:', error.message);
}
Component-Level Configuration¶
While DatabaseConfig handles database-wide settings, individual components may have their own configuration options:
QueryEngine Configuration¶
The QueryEngine uses defaults sourced from DatabaseConfig and is instantiated through DocumentOperations. You can still override defaults by passing a custom config directly to QueryEngine when needed.
// QueryEngine has its own configuration
const queryEngine = new QueryEngine({
maxNestedDepth: 15 // Override default of 10
});
// DatabaseConfig supplies defaults for collections
const dbConfig = new DatabaseConfig({
logLevel: 'DEBUG',
collectionLockLeaseMs: 25000,
coordinationTimeoutMs: 20000,
queryEngineMaxNestedDepth: 12,
queryEngineSupportedOperators: ['$eq', '$gt', '$lt', '$and', '$or']
});
const db = new Database(dbConfig);
// Collections use the QueryEngine internally with DatabaseConfig defaults
QueryEngine Options:
maxNestedDepth(Number, default: 10): Maximum allowed query nesting depth for securitysupportedOperators(String[], default:['$eq', '$gt', '$lt', '$and', '$or']): Operators permitted by the enginelogicalOperators(String[], default:['$and', '$or']): Logical operators permitted by the engine
FileOperations Configuration¶
File operations use retry settings from DatabaseConfig when the Database constructs FileOperations:
fileRetryAttempts: Number of retry attempts for Drive operationsfileRetryDelayMs: Delay between retriesfileRetryBackoffBase: Exponential backoff base for retries
Security Note: QueryEngine always validates all queries for structure and supported operators to prevent malicious queries, regardless of configuration.
Index Backup Strategy¶
backupOnInitialise controls whether Database.initialise() performs Drive index creation and backup:
false(default): Initialise reads from MasterIndex only; no Drive writes are performed. The Drive-based index is created lazily on first write operation (e.g.,createCollection,dropCollection) or when callingdatabase.loadIndex().true: Initialise will create/find the index file in Drive and back up the current MasterIndex immediately. This is useful when you want a snapshot on every start at the cost of additional Drive operations.
Independent of this flag, explicit calls to database.backupIndexToDrive() will always perform a backup if an index file exists.
Best Practices¶
- Validate early: Create DatabaseConfig instances explicitly to catch errors
- Use appropriate timeouts: Size
collectionLockLeaseMsto cover the whole write, and keepcoordinationTimeoutMswithin that lease - Environment-specific configs: Create different configurations for dev/test/prod
- Immutable configurations: Don't modify config properties after creation
- Proper folder permissions: Ensure root folder is accessible to the script
- Sensible logging levels: Use DEBUG for development, INFO/WARN for production
- Document custom settings: Comment why specific values were chosen
- Test configuration validation: Include config validation in your tests
- Security-first design: All components prioritise security over optional performance optimisations
- Component separation: Each component manages its own configuration appropriate to its responsibilities