luckyframework / luckyframework/avram

Consider adding counter cache functionality that uses triggers

Open
#338 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Crystal
Stars
183
Forks
67
PR merge metrics
No merged PRs in 30d

Description

`Triggered` by #337.

This may be something that should be its own shard. I've considered creating a shard for this, but I thought it would be good to discuss it here first.

I have a couple counter caches in my app that are implemented with triggers. The migrations are definitely a little hairy and it would be nice to be able to just say something like:

```crystal
def migrate
alter table_for(Comments) do
add_counter_cache like_count : Int64, count_table: :likes, foreign_key: comment_id
end
end

def rollback
alter table_for(Comments) do
remove_counter_cache :like_count, count_table: :likes, foreign_key: comment_id
end
end
```

Here's some actual code to create a counter cache trigger. There's a lot of boilerplate in there:

```crystal
def migrate
execute <<-SQL
CREATE FUNCTION maintain_campaign_call_count_trg() RETURNS TRIGGER AS
$$
BEGIN
IF TG_OP IN ('UPDATE', 'DELETE') THEN
UPDATE campaigns SET call_count = call_count - 1 WHERE id = old.campaign_id;
END IF;
IF TG_OP IN ('INSERT', 'UPDATE') THEN
UPDATE campaigns SET call_count = call_count + 1 WHERE id = new.campaign_id;
END IF;
RETURN NULL;
END
$$
LANGUAGE plpgsql;
SQL
execute <<-SQL
CREATE TRIGGER maintain_campaign_call_count
AFTER INSERT OR UPDATE OF campaign_id OR DELETE ON calls
FOR EACH ROW
EXECUTE PROCEDURE maintain_campaign_call_count_trg();
SQL

execute <<-SQL
CREATE FUNCTION maintain_campaign_call_count_after_truncate_trg() RETURNS TRIGGER AS
$$
BEGIN
UPDATE campaigns SET call_count = 0;
RETURN NULL;
END
$$
LANGUAGE plpgsql;
SQL
execute <<-SQL
CREATE TRIGGER maintain_campaign_call_count_after_truncate
AFTER TRUNCATE ON calls
EXECUTE PROCEDURE maintain_campaign_call_count_after_truncate_trg();
SQL
end

def rollback
execute "DROP TRIGGER maintain_campaign_call_count ON calls;"
execute "DROP FUNCTION maintain_campaign_call_count_trg();"

execute "DROP TRIGGER maintain_campaign_call_count_after_truncate ON calls;"
execute "DROP FUNCTION maintain_campaign_call_count_after_truncate_trg();"
end
```

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names migration entry points using alter table_for, add_counter_cache, remove_counter_cache, and raw execute SQL, but no repository files or tests. Start by locating those migration APIs and reviewing the PostgreSQL trigger examples; done would require an agreed scope and verified migration and rollback behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
crystal, postgresql
Domain
databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.