##### Will data get duplicated upon re-running code? [image: .md][image]

LaminDB's operations are idempotent in the sense defined here, which
allows you to re-run code without duplicating data.

SQLRecords with name field: When you instantiate "SQLRecord" with a
name, in case a name has an *exact match* in a registry, the
constructor returns it instead of creating a new record. In case
records with *similar names* exist, you'll see them in a table: you
can then decide whether you want to save the new record or pick an
existing record.If you set "search_names" to "False", you bypass these
checks.

Artifacts & collections: If you instantiate "Artifact" from data that
will be written into a managed storage, the "Artifact()" constructor
returns the existing artifact based on a hash lookup. For paths that
already live in a registered storage location, hash lookup is skipped
by default. You can override this via "skip_hash_lookup=False" (or
force skipping via "skip_hash_lookup=True").

 # pip install lamindb
 lamin init --storage ./test-idempotency

 import lamindb as ln

 ln.track("ANW20Fr4eZgM0000")

#### SQLRecords with name field

 assert ln.settings.creation.search_names

Let us add a first record to the "Record" registry:

 label = ln.Record(name="My label 1").save()

If we create a new record, we'll automatically get search results that
give clues on whether we are prone to duplicating an entry:

 label = ln.Record(name="My label 1a")

Let's save the "1a" label, we actually intend to create it.

 label.save()

In case we match an existing name directly, we'll get the existing
object:

 label = ln.Record(name="My label 1")

If we save it again, it will not create a new entry in the registry:

 label.save()

Now, if we create a third record, we'll get two alternatives:

 label = ln.Record(name="My label 1b")

If we prefer to not perform a search, e.g. for performance reasons, we
can switch it off.

 ln.settings.creation.search_names = False
 label = ln.Record(name="My label 1c")

Switch it back on:

 ln.settings.creation.search_names = True

#### Artifacts & collections

 filepath = ln.examples.datasets.file_fcs()

Create an "Artifact":

 artifact = ln.Artifact(filepath, key="my_fcs_file.fcs").save()

 assert artifact.hash == "rCPvmZB19xs4zHZ7p_-Wrg"
 assert artifact.run == ln.context.run
 assert not artifact.recreating_runs.exists()

Create an "Artifact" from the same path:

 artifact2 = ln.Artifact(filepath, key="my_fcs_file.fcs")

It gives us the existing object:

This behavior is the default when "skip_hash_lookup=None" (the default
setting): for data written into managed storage, LaminDB performs hash
lookup; for paths already in a registered storage location, hash
lookup is skipped unless you pass "skip_hash_lookup=False".

 assert artifact.id == artifact2.id
 assert artifact.run == artifact2.run
 assert not artifact.recreating_runs.exists()

If you save it again, nothing will happen (the operation is
idempotent):

 artifact2.save()

In the hidden cell below, you'll see how this interplays with data
lineage.

 ln.track(new_run=True)
 artifact3 = ln.Artifact(filepath, key="my_fcs_file.fcs")
 assert artifact3.id == artifact2.id
 assert artifact3.run == artifact2.run != ln.context.run  # run is not updated
 assert artifact2.recreating_runs.first() == ln.context.run

 rm -rf ./test-idempotency
 lamin delete --force test-idempotency