module PgORM::Persistence

Overview

Persistence module handles all database CRUD (Create, Read, Update, Delete) operations.

This module is automatically included in PgORM::Base and provides instance methods for saving, updating, and deleting records, as well as class methods for bulk operations.

Lifecycle States

Records can be in one of three states:

Callbacks

Persistence operations trigger callbacks in this order:

Direct including types

Defined in:

pg-orm/persistence.cr

Instance Method Summary

Instance Method Detail

def delete #

Deletes the record from the database without callbacks.

This is faster than #destroy but:

  • Does NOT run callbacks
  • Does NOT update associations
  • Does NOT wrap in a transaction

Use this for performance-critical deletions where you don't need the full destroy lifecycle.

Example

user = User.find(1)
user.delete # Direct DELETE query

Returns self (even if already destroyed or new).


[View source]
def destroy #

Destroys the record, running callbacks and updating associations.

This is the "safe" way to delete records as it:

  • Runs before_destroy and after_destroy callbacks
  • Handles dependent associations (nullify, delete, destroy)
  • Wraps everything in a transaction

Example

user = User.find(1)
user.destroy
user.destroyed? # => true
user.persisted? # => false

Returns self (even if already destroyed or new).


[View source]
def persisted? #

Returns true if the record has been saved to the database and not destroyed.

Example

user = User.new(name: "John")
user.persisted? # => false

user.save!
user.persisted? # => true

user.destroy
user.persisted? # => false

[View source]
def reload! #

Reloads the record from the database, discarding any changes.

Useful for:

  • Reverting unsaved changes
  • Getting fresh data after external updates
  • Clearing dirty tracking

Example

user = User.find(1)
user.name = "Changed"
user.reload!  # Reverts to database value
user.changed? # => false

Raises


[View source]
def save(**options) #

Saves the record to the database.

For new records, performs an INSERT. For existing records, performs an UPDATE. Returns true if successful, false if validation fails.

Example

user = User.new(name: "John")
if user.save
  puts "Saved! ID: #{user.id}"
else
  puts "Failed: #{user.errors}"
end

# Update existing record
user.name = "Jane"
user.save # => true (if valid)

Callbacks

Triggers appropriate callbacks based on record state:

  • New records: before_create, before_save, after_save, after_create
  • Existing: before_update, before_save, after_save, after_update

[View source]
def save!(**options) #

Saves the record to the database, raising an exception on failure.

For new records, performs an INSERT. For existing records, performs an UPDATE. Only updates changed attributes (dirty tracking).

Example

user = User.new(name: "John")
user.save! # => #<User id: 1, name: "John">

user.name = "Jane"
user.save! # Only updates 'name' column

Raises


[View source]
def update(**attributes) #

Updates the record with new attributes and saves it.

Returns true if successful, false if validation fails.

Example

user = User.find(1)
if user.update(name: "Jane", email: "[email protected]")
  puts "Updated!"
else
  puts "Failed: #{user.errors}"
end

[View source]
def update!(**attributes) #

Updates the record with new attributes and saves it, raising on failure.

Example

user = User.find(1)
user.update!(name: "Jane", email: "[email protected]")

Raises PgORM::Error::RecordInvalid if validation fails.


[View source]
def update_fields(**attributes) #

Atomically updates specific fields without running callbacks or validations.

This is faster than #update! but bypasses:

  • Validations
  • Callbacks (before_save, after_save, etc.)
  • Dirty tracking (changes are cleared after update)

Use this for performance-critical updates where you don't need the full persistence lifecycle.

Example

user = User.find(1)
user.update_fields(last_login: Time.utc, login_count: 42)
# Direct UPDATE query, no callbacks

Raises Error::RecordNotSaved if called on a new record.


[View source]