diff --git a/lib/senzing/g2/engine.ex b/lib/senzing/g2/engine.ex index 67d9906..91e2ce1 100644 --- a/lib/senzing/g2/engine.ex +++ b/lib/senzing/g2/engine.ex @@ -422,6 +422,31 @@ defmodule Senzing.G2.Engine do end end + @doc """ + This method is used to delete observation data from the system. + + This removes a single entity observation record, by removing all of its + feature data and the observation itself. + + See https://docs.senzing.com/python/3/g2engine/deleting/index.html#deleterecord + + ## Examples + + iex> :ok = Senzing.G2.Engine.add_record(%{"RECORD_ID" => "test id"}, "TEST") + iex> :ok = Senzing.G2.Engine.delete_record("test id", "TEST") + + """ + @doc type: :deleting_records + @spec delete_record( + record_id :: record_id(), + data_source :: data_source(), + opts :: [with_info: boolean(), load_id: String.t()] + ) :: G2.result() | G2.result(map()) + def delete_record(record_id, data_source, opts \\ []) do + with {:ok, response} <- Nif.delete_record(data_source, record_id, opts[:load_id], opts[:with_info] || false), + do: {:ok, :json.decode(response)} + end + # This method will destroy and perform cleanup for the G2 processing object. # # It should be called after all other calls are complete. diff --git a/lib/senzing/g2/engine/nif.ex b/lib/senzing/g2/engine/nif.ex index 3245a44..cf42799 100644 --- a/lib/senzing/g2/engine/nif.ex +++ b/lib/senzing/g2/engine/nif.ex @@ -343,6 +343,36 @@ defmodule Senzing.G2.Engine.Nif do return beam.make(env, .{ .ok, responseBuf }, .{}); } + pub fn delete_record(env: beam.env, dataSource: []u8, recordId: []u8, loadId: ?[]u8, withInfo: bool) !beam.term { + var g2_dataSource = try beam.allocator.dupeZ(u8, dataSource); + var g2_recordId = try beam.allocator.dupeZ(u8, recordId); + var g2_loadId = if (loadId) |id| try beam.allocator.dupeZ(u8, id) else try beam.allocator.dupeZ(u8, ""); + + if (withInfo) { + var g2_flags: c_longlong = 0; // Reserved for future use, not currently used + + var responseBuf: [*c]u8 = null; + var responseBufSize: usize = 1024; + var initialResponseBuf = try beam.allocator.alloc(u8, responseBufSize); + defer beam.allocator.free(initialResponseBuf); + responseBuf = initialResponseBuf.ptr; + + if (G2.G2_deleteRecordWithInfo(g2_dataSource, g2_recordId, g2_loadId, g2_flags, &responseBuf, &responseBufSize, resize_pointer) != 0) { + var reason = try get_and_clear_last_exception(env); + return beam.make_error_pair(env, reason, .{}); + } + + return beam.make(env, .{ .ok, responseBuf }, .{}); + } + + if (G2.G2_deleteRecord(g2_dataSource, g2_recordId, g2_loadId) != 0) { + var reason = try get_and_clear_last_exception(env); + return beam.make_error_pair(env, reason, .{}); + } + + return beam.make(env, .ok, .{}); + } + // TODO: Complete pub fn get_entity_by_record_id(env: beam.env, dataSource: []u8, recordId: []u8) !beam.term { var g2_dataSource = try beam.allocator.dupeZ(u8, dataSource); diff --git a/test/senzing/g2/engine_test.exs b/test/senzing/g2/engine_test.exs index 89ead65..cad72d0 100644 --- a/test/senzing/g2/engine_test.exs +++ b/test/senzing/g2/engine_test.exs @@ -202,4 +202,27 @@ defmodule Senzing.G2.EngineTest do assert {:ok, nil} = Engine.process_next_redo_record(return_info: true) end end + + describe inspect(&Engine.delete_record/2) do + test "works", %{test: test} do + id = "#{inspect(__MODULE__)}.#{inspect(test)}" + + assert :ok = Engine.add_record(%{"RECORD_ID" => id}, "TEST") + + assert :ok = Engine.delete_record(id, "TEST") + + assert :ok = Engine.add_record(%{"RECORD_ID" => id}, "TEST") + + assert {:ok, + %{ + "AFFECTED_ENTITIES" => _affected_entities, + "DATA_SOURCE" => "TEST", + "INTERESTING_ENTITIES" => %{"ENTITIES" => _entities}, + "RECORD_ID" => ^id + }} = Engine.delete_record(id, "TEST", with_info: true) + + # TODO: Use finished fn + assert {:error, {33, _message}} = Engine.Nif.get_entity_by_record_id("TEST", id) + end + end end