Skip to content

Commit

Permalink
Adds support for generate truncate table queries.
Browse files Browse the repository at this point in the history
  • Loading branch information
mishafw committed Jun 12, 2023
1 parent e29489b commit 3a0471b
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/cassandrax/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ defmodule Cassandrax.Connection do
["DELETE FROM ", quote_table(keyspace, table), " WHERE " | filters]
end

def truncate(keyspace, table), do: ["TRUNCATE TABLE ", quote_table(keyspace, table)]

defp assemble_filters(filters) do
intersperse_map(filters, " AND ", fn field ->
field = field |> Atom.to_string() |> quote_name()
Expand Down
13 changes: 13 additions & 0 deletions lib/cassandrax/keyspace.ex
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ defmodule Cassandrax.Keyspace do
def delete!(struct, opts \\ []),
do: Cassandrax.Keyspace.Schema.delete!(__MODULE__, struct, opts)

def truncate(module_or_table) when is_atom(module_or_table),
do: Cassandrax.Keyspace.Schema.truncate(__MODULE__, module_or_table)

## Queryable

def all(queryable, opts \\ []),
Expand Down Expand Up @@ -256,6 +259,16 @@ defmodule Cassandrax.Keyspace do
opts :: Keyword.t()
) :: Cassandrax.Schema.t()

@doc """
Truncates a schema.
## Example
```
MyKeyspace.truncate(User)
```
"""
@callback truncate(module() | atom()) :: :ok

@doc """
Fetches all entries from the data store that matches the given query.
Expand Down
34 changes: 34 additions & 0 deletions lib/cassandrax/keyspace/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ defmodule Cassandrax.Keyspace.Schema do
end
end

@doc """
Implementation for `Cassandrax.Keyspace.truncate/2`.
"""
def truncate(keyspace, schema_module_or_table_name) do
conn = keyspace.__conn__
keyspace_name = keyspace.__keyspace__

with {:ok, table} <- table_name_from_module_or_atom(schema_module_or_table_name),
statement = Cassandrax.Connection.truncate(keyspace_name, table),
{:ok, results} <- Cassandrax.cql(conn, statement) do
{:ok, results}
else
{:error, error} -> {:error, error}
end
end

@doc """
Implementation for `Cassandrax.Keyspace.insert/2`.
"""
Expand Down Expand Up @@ -258,4 +274,22 @@ defmodule Cassandrax.Keyspace.Schema do
}}
end
end

defp table_name_from_module_or_atom(module_or_atom) do
is_module = function_exported?(module_or_atom, :__info__, 1)

table =
if is_module do
is_cassandrax_schema =
Keyword.has_key?(module_or_atom.__info__(:functions), :__cassandrax_source__)

if is_cassandrax_schema do
{:ok, module_or_atom.__cassandrax_source__}
else
{:error, "module #{module_or_atom} does not use Cassandrax.Schema"}
end
else
{:ok, module_or_atom}
end
end
end
1 change: 1 addition & 0 deletions lib/cassandrax/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ defmodule Cassandrax.Schema do

def __schema__(:queryable), do: %Cassandrax.Query{from: unquote(source), schema: __MODULE__}
def __schema__(:pk), do: @primary_key
def __cassandrax_source__, do: unquote(source)

# Set it to false to bypass Ecto primary_key verification
@primary_key false
Expand Down
15 changes: 15 additions & 0 deletions test/cassandrax/connection_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule Cassandrax.ConnectionTest do
end

defp to_string({iodata, _values}), do: IO.iodata_to_binary(iodata)
defp to_string(iodata), do: IO.iodata_to_binary(iodata)
defp all(queryable), do: Cassandrax.Connection.all(TestKeyspace, queryable) |> to_string()

describe "all/2" do
Expand Down Expand Up @@ -152,4 +153,18 @@ defmodule Cassandrax.ConnectionTest do
assert all(queryable) =~ ~r/WHERE \("id" < \?\)/
end
end

defp truncate(queryable) do
changeset = Ecto.Changeset.change(queryable.__struct__)
schema = changeset.data.__struct__
keyspace_name = TestKeyspace.__keyspace__()
table = schema.__schema__(:source)
Cassandrax.Connection.truncate(keyspace_name, table) |> to_string()
end

describe "truncate" do
test "successfully generate a truncate clause when passed a schema" do
assert truncate(TestSchema) =~ ~r/TRUNCATE TABLE "test_keyspace"."my_table"/
end
end
end
42 changes: 42 additions & 0 deletions test/cassandrax/keyspace_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,48 @@ defmodule Cassandrax.KeyspaceTest do
end
end

describe "truncate" do
setup do
[
first: fixture(TestData, id: "0", timestamp: "00:00", data: "0"),
second:
fixture(TestData,
id: "1",
timestamp: "01:00",
data: "1",
svalue: MapSet.new(["one", "another one"])
)
]
end

test "truncates all records on the table when passed module that uses Cassandrax.Schema" do
assert Enum.count(TestKeyspace.all(TestData)) == 2
assert {:ok, %Xandra.Void{}} = TestKeyspace.truncate(TestData)
assert Enum.count(TestKeyspace.all(TestData)) == 0
end

test "truncates all records on the table when passed valid table name" do
assert Enum.count(TestKeyspace.all(TestData)) == 2
assert {:ok, %Xandra.Void{}} = TestKeyspace.truncate(:test_data)
assert Enum.count(TestKeyspace.all(TestData)) == 0
end

test "returns error when passed invalid module" do
assert {:error, "module Elixir.String does not use Cassandrax.Schema"} =
TestKeyspace.truncate(String)
end

test "returns error when passed invalid table name" do
assert {:error,
%Xandra.Error{
__exception__: true,
message: "table test_data2 does not exist",
reason: :invalid,
warnings: []
}} = TestKeyspace.truncate(:test_data2)
end
end

describe "cql" do
setup do
[
Expand Down

0 comments on commit 3a0471b

Please sign in to comment.