Skip to content

Commit a64a2fc

Browse files
committed
Support new mode :append in PgLargeObjects.LargeObject API
This should be convenient when implementing e.g. the Phoenix.LiveView.UploadWriter behaviour. It receives data via calls to `write_chunk/2`, but this disallows keeping an open transaction. Instead, on ever `write_chunk/2` call, we want to open and append to an object.
1 parent ad8a8df commit a64a2fc

3 files changed

Lines changed: 24 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Document difference between `Enum.count/1` and `PgLargeObject.LargeObjects.size/1`
66
* Reorder chapters in documentation
7+
* Add `:append` option to `PgLargeObjects.LargeObject.open/3` and others.
78

89
## v0.1.2 - 2025-11-12
910

lib/pg_large_objects/large_object.ex

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ defmodule PgLargeObjects.LargeObject do
9393
9494
* `:bufsize` - number of bytes to transfer at a time when streaming into/out
9595
of the object. Defaults to 1MB.
96-
* `:mode` - can be one of `:read`, `:write` or `:read_write` indicating
97-
whether to open the object for reading, writing, or both. Defaults to `:read`.
96+
* `:mode` - can be one of `:read`, `:write`, `:append` or `:read_write`
97+
indicating whether to open the object for reading, writing, appending or
98+
reading and writing.
9899
99100
## Return value
100101
@@ -117,11 +118,21 @@ defmodule PgLargeObjects.LargeObject do
117118
case opts[:mode] do
118119
:read -> Bindings.constant(:inv_read)
119120
:write -> Bindings.constant(:inv_write)
121+
:append -> Bindings.constant(:inv_write)
120122
:read_write -> Bindings.constant(:inv_read) + Bindings.constant(:inv_write)
121123
mode -> raise ArgumentError, message: "invalid mode: #{mode}"
122124
end
123125

124-
with {:ok, fd} <- Bindings.open(repo, oid, flags) do
126+
maybe_seek_to_end = fn
127+
fd, :append ->
128+
Bindings.lseek64(repo, fd, 0, Bindings.constant(:seek_end))
129+
130+
_fd, _mode ->
131+
{:ok, 0}
132+
end
133+
134+
with {:ok, fd} <- Bindings.open(repo, oid, flags),
135+
{:ok, _position} <- maybe_seek_to_end.(fd, opts[:mode]) do
125136
lob =
126137
%__MODULE__{
127138
repo: repo,

test/pg_large_objects/large_object_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ defmodule PgLargeObjects.LargeObjectTest do
9898
assert get_large_object!(oid) == "XYZDEFG"
9999
end
100100

101+
test "appends if open mode is `:append`" do
102+
{:ok, oid} =
103+
with_object("ABCDEFG", [mode: :append], fn lob ->
104+
assert :ok == LargeObject.write(lob, "XYZ")
105+
end)
106+
107+
assert get_large_object!(oid) == "ABCDEFGXYZ"
108+
end
109+
101110
test "fails given invalid object" do
102111
with_object("", [mode: :write], fn lob ->
103112
:ok = LargeObject.remove(TestRepo, lob.oid)

0 commit comments

Comments
 (0)