Global Configuration
Firebase ORM now supports global configuration options that provide convenient defaults and automation features. These configurations help maintain consistency across your models and reduce boilerplate code.
Overview
Global configuration allows you to:
- Auto Lower Case Field Names: Automatically convert camelCase field names to snake_case format
- Auto Path ID: Automatically generate path_id from class names
- Throw on Required Field Null: Throw exceptions when required fields are null during save
- Validation: Ensure all models have proper path_id configuration
Setting Global Configuration
Use the FirestoreOrmRepository.setGlobalConfig() method to configure global options:
import { FirestoreOrmRepository } from '@arbel/firebase-orm';
// Enable all features
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true,
auto_path_id: true,
throw_on_required_field_null: true
});
// Or configure individually
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true
});
FirestoreOrmRepository.setGlobalConfig({
auto_path_id: true
});
FirestoreOrmRepository.setGlobalConfig({
throw_on_required_field_null: true
});
Auto Lower Case Field Names
When auto_lower_case_field_name is enabled, field names are automatically converted from camelCase to snake_case format for database storage.
Without Auto Lower Case (Default)
@Model({
reference_path: 'users',
path_id: 'user_id'
})
export class User extends BaseModel {
@Field({ is_required: true })
public firstName!: string; // Stored as "firstName"
@Field({ is_required: true })
public cartItem!: string; // Stored as "cartItem"
}
With Auto Lower Case Enabled
// Enable global configuration
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true
});
@Model({
reference_path: 'users',
path_id: 'user_id'
})
export class User extends BaseModel {
@Field({ is_required: true })
public firstName!: string; // Stored as "first_name"
@Field({ is_required: true })
public cartItem!: string; // Stored as "cart_item"
@Field({
is_required: true,
field_name: 'custom_field' // Explicit field_name overrides auto conversion
})
public someField!: string; // Stored as "custom_field"
}
Conversion Rules
cartItem→cart_itemfirstName→first_namephotoURL→photo_u_r_luserID→user_i_dsimpleField→simple_fieldfield→field(single words remain unchanged)
Important: Explicit field_name values always take precedence over auto conversion.
Auto Path ID
When auto_path_id is enabled, the ORM automatically generates path_id from the class name if not explicitly provided.
Without Auto Path ID (Default)
@Model({
reference_path: 'users',
path_id: 'user_id' // Required - will throw error if missing
})
export class User extends BaseModel {
// ...
}
With Auto Path ID Enabled
// Enable global configuration
FirestoreOrmRepository.setGlobalConfig({
auto_path_id: true
});
@Model({
reference_path: 'users'
// path_id is optional - will be auto-generated as "user_id"
})
export class User extends BaseModel {
// ...
}
@Model({
reference_path: 'shopping_carts'
// path_id auto-generated as "shopping_cart_id"
})
export class ShoppingCart extends BaseModel {
// ...
}
@Model({
reference_path: 'profiles',
path_id: 'custom_profile_id' // Explicit path_id overrides auto generation
})
export class UserProfile extends BaseModel {
// ...
}
Generation Rules
User→user_idShoppingCart→shopping_cart_idUserProfile→user_profile_idHTTPRequest→h_t_t_p_request_idUserId→user_id(avoids duplicate_idsuffix)
Important: Explicit path_id values always take precedence over auto generation.
Throw on Required Field Null
When throw_on_required_field_null is enabled, the ORM will throw an exception when attempting to save a model with null required fields. This makes it easier to identify missing required values during development and debugging.
Without Throw on Required Field Null (Default)
@Model({
reference_path: 'users',
path_id: 'user_id'
})
export class User extends BaseModel {
@Field({ is_required: true })
public email!: string;
@Field({ is_required: false })
public nickname?: string;
}
const user = new User();
// email is not set
await user.save();
// Logs error to console: "Can't save email with null!"
// Returns the model without saving to database
With Throw on Required Field Null Enabled
// Enable global configuration
FirestoreOrmRepository.setGlobalConfig({
throw_on_required_field_null: true
});
@Model({
reference_path: 'users',
path_id: 'user_id'
})
export class User extends BaseModel {
@Field({ is_required: true })
public email!: string;
@Field({ is_required: false })
public nickname?: string;
}
const user = new User();
// email is not set
try {
await user.save();
} catch (error) {
// Error thrown: "users/:user_id - Can't save email with null!"
console.error('Failed to save user:', error.message);
}
// Correct usage
const validUser = new User();
validUser.email = 'user@example.com';
await validUser.save(); // Saves successfully
Benefits
- Early Error Detection: Catch missing required fields immediately during development
- Predictable Error Handling: Use try-catch blocks to handle validation errors
- Better Debugging: Stack traces show exactly where the error occurred
- Type Safety: Complements TypeScript’s type checking at runtime
Use Cases
- Development: Enable during development to catch errors early
- Production: Enable for critical applications where data integrity is paramount
- Testing: Helps ensure test data is properly configured
Important: This option affects the save() method behavior. When enabled, verifyRequiredFields() will throw instead of returning false.
Validation
When auto_path_id is disabled (default), all models must have an explicit path_id defined. If missing, the decorator will throw an error:
// This will throw an error when auto_path_id is disabled
@Model({
reference_path: 'users'
// Missing path_id!
})
export class User extends BaseModel {
// Error: Model 'User' must have a path_id defined in @Model decorator
// or enable auto_path_id in global configuration
}
Getting Current Configuration
You can retrieve the current global configuration:
const config = FirestoreOrmRepository.getGlobalConfig();
console.log(config.auto_lower_case_field_name); // true/false
console.log(config.auto_path_id); // true/false
console.log(config.throw_on_required_field_null); // true/false
Best Practices
Recommended Configuration
For new projects, we recommend the following configurations:
Development Environment:
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true,
auto_path_id: true,
throw_on_required_field_null: true // Catch errors early in development
});
Production Environment:
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true,
auto_path_id: true,
throw_on_required_field_null: false // Or true for strict validation
});
Naming Conventions
- Collection Names: Use lowercase with underscores
@Model({ reference_path: 'user_profiles' // ✅ Good // reference_path: 'userProfiles' // ❌ Avoid }) - Field Names: Use camelCase in TypeScript, let auto conversion handle storage
@Field() public firstName!: string; // ✅ Good - becomes first_name in DB @Field({ field_name: 'first_name' }) public firstName!: string; // ✅ Also good - explicit naming - Model Class Names: Use PascalCase
export class UserProfile extends BaseModel { } // ✅ Good export class userprofile extends BaseModel { } // ❌ Avoid
Migration Strategy
If you’re migrating an existing project:
- Start with field names only:
FirestoreOrmRepository.setGlobalConfig({ auto_lower_case_field_name: true, auto_path_id: false // Keep existing path_ids }); -
Gradually adopt auto path_id for new models while keeping explicit path_id for existing ones.
- Use explicit field_name for fields that need specific database column names.
Complete Example
import { FirestoreOrmRepository, Model, Field, BaseModel } from '@arbel/firebase-orm';
// Configure global settings
FirestoreOrmRepository.setGlobalConfig({
auto_lower_case_field_name: true,
auto_path_id: true,
throw_on_required_field_null: true
});
// User model with auto-generated path_id and auto-converted field names
@Model({
reference_path: 'users'
// path_id auto-generated as "user_id"
})
export class User extends BaseModel {
@Field({ is_required: true })
public firstName!: string; // Stored as "first_name"
@Field({ is_required: true })
public lastName!: string; // Stored as "last_name"
@Field({ is_required: true })
public emailAddress!: string; // Stored as "email_address"
@Field({
is_required: false,
field_name: 'avatar_url' // Custom field name
})
public profileImage?: string; // Stored as "avatar_url"
}
// Shopping cart with complex class name
@Model({
reference_path: 'shopping_carts'
// path_id auto-generated as "shopping_cart_id"
})
export class ShoppingCart extends BaseModel {
@Field({ is_required: true })
public cartItems!: string[]; // Stored as "cart_items"
@Field({ is_required: true })
public totalPrice!: number; // Stored as "total_price"
@Field({ is_required: true })
public createdAt!: string; // Stored as "created_at"
}
// Usage
async function example() {
const user = new User();
user.firstName = 'John';
user.lastName = 'Doe';
user.emailAddress = 'john@example.com';
await user.save();
console.log('User saved with auto-generated path_id:', user.pathId); // "user_id"
console.log('Database data:', user.getData());
// { first_name: 'John', last_name: 'Doe', email_address: 'john@example.com' }
}
This global configuration system helps maintain consistency across your Firebase ORM models while reducing boilerplate and ensuring best practices are followed automatically.