Packages
phoenix_kit
1.7.11
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/posts/post_comment.ex
defmodule PhoenixKit.Posts.PostComment do
@moduledoc """
Schema for post comments with unlimited threading depth.
Supports nested comment threads (Reddit-style) with self-referencing parent/child
relationships. Depth is automatically calculated based on parent chain.
## Comment Status
- `published` - Comment is visible
- `hidden` - Comment is hidden by moderator
- `deleted` - Comment deleted (soft delete)
- `pending` - Awaiting moderation approval
## Fields
- `post_id` - Reference to the post
- `user_id` - Reference to the commenter
- `parent_id` - Reference to parent comment (nil for top-level)
- `content` - Comment text
- `status` - published/hidden/deleted/pending
- `depth` - Nesting level (0=top, 1=reply, 2=reply-to-reply, etc.)
- `like_count` - Denormalized counter (future feature)
## Examples
# Top-level comment
%PostComment{
post_id: "018e3c4a-9f6b-7890-abcd-ef1234567890",
user_id: 42,
parent_id: nil,
content: "Great post!",
status: "published",
depth: 0
}
# Reply to comment
%PostComment{
post_id: "018e3c4a-9f6b-7890-abcd-ef1234567890",
user_id: 15,
parent_id: "018e3c4a-1234-5678-abcd-ef1234567890",
content: "Thanks!",
status: "published",
depth: 1
}
# Reply to reply
%PostComment{
post_id: "018e3c4a-9f6b-7890-abcd-ef1234567890",
user_id: 99,
parent_id: "018e3c4a-5678-1234-abcd-ef1234567890",
content: "You're welcome!",
status: "published",
depth: 2
}
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, UUIDv7, autogenerate: true}
@type t :: %__MODULE__{
id: UUIDv7.t() | nil,
post_id: UUIDv7.t(),
user_id: integer(),
parent_id: UUIDv7.t() | nil,
content: String.t(),
status: String.t(),
depth: integer(),
like_count: integer(),
post: PhoenixKit.Posts.Post.t() | Ecto.Association.NotLoaded.t(),
user: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t(),
parent: t() | Ecto.Association.NotLoaded.t() | nil,
children: [t()] | Ecto.Association.NotLoaded.t(),
inserted_at: NaiveDateTime.t() | nil,
updated_at: NaiveDateTime.t() | nil
}
schema "phoenix_kit_post_comments" do
field :content, :string
field :status, :string, default: "published"
field :depth, :integer, default: 0
field :like_count, :integer, default: 0
belongs_to :post, PhoenixKit.Posts.Post, type: UUIDv7
belongs_to :user, PhoenixKit.Users.Auth.User, type: :integer
belongs_to :parent, __MODULE__, type: UUIDv7
has_many :children, __MODULE__, foreign_key: :parent_id
timestamps(type: :naive_datetime)
end
@doc """
Changeset for creating or updating a comment.
## Required Fields
- `post_id` - Reference to post
- `user_id` - Reference to commenter
- `content` - Comment text
## Validation Rules
- Content must not be empty
- Status must be valid (published/hidden/deleted/pending)
- Depth automatically calculated from parent
"""
def changeset(comment, attrs) do
comment
|> cast(attrs, [:post_id, :user_id, :parent_id, :content, :status, :depth])
|> validate_required([:post_id, :user_id, :content])
|> validate_inclusion(:status, ["published", "hidden", "deleted", "pending"])
|> validate_length(:content, min: 1, max: 10_000)
|> foreign_key_constraint(:post_id)
|> foreign_key_constraint(:user_id)
|> foreign_key_constraint(:parent_id)
end
@doc """
Check if comment is a reply (has parent).
"""
def reply?(%__MODULE__{parent_id: nil}), do: false
def reply?(%__MODULE__{}), do: true
@doc """
Check if comment is top-level (no parent).
"""
def top_level?(%__MODULE__{parent_id: nil}), do: true
def top_level?(%__MODULE__{}), do: false
@doc """
Check if comment is published.
"""
def published?(%__MODULE__{status: "published"}), do: true
def published?(_), do: false
@doc """
Check if comment is deleted.
"""
def deleted?(%__MODULE__{status: "deleted"}), do: true
def deleted?(_), do: false
end