Entities and attributes aliasing feature looks broken

I have tried to use datomic alias feature both for entities and attributes by using function db/add and I got strange behaviour. First case when I’m trying to set aliasing for entities:
E.g. the next schema is transacted:
(def user-schema [
{
:db/ident :user/code
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/unique :db.unique/value

                   }
                   {
                       :db/ident :user/firstName
                       :db/valueType :db.type/string
                       :db/cardinality :db.cardinality/one
                   }
                   {
                       :db/ident :user/lastName
                       :db/valueType :db.type/string
                       :db/cardinality :db.cardinality/one
                   }

                   ])
(d/transact conn user-schema)

Then I’m creating entity:
(def user-data [
{
:db/ident :user/fistLastNames
:user/firstName “FirstName”
:user/lastName “LastName”
:user/code “code1”
}

                   ])
(d/transact conn user-data)

Then I’m setting an alias
(d/transact
conn
[[:db/add :user/fistLastNames :db/ident :person/fistLastNames]
])

If to check entity using both idents it points to the same entity


Which ID is 17592186045427, so everything looks, aliasing works well, but once I’m trying to update entity
(def user-data [
{
:db/ident :user/fistLastNames
:user/lastName “LastNameFixed”
:user/code “code1”
}

                   ])
(d/transact conn user-data)

I’m getting: “Unique conflict: :user/code, value: code1 already held by: 17592186045427 asserted for: 17592186045430”

Actually I’m interested in doing such operations for attributes too, and everything is good even when updating already aliased attribute but using original ident, but the same actions do not work if an updated attribute is part of other attribute(mentioned in :db/tupleAttrs). I’m getting:
:db.error/cannot-retarget-ident Ident :user/firstName cannot be used for entity 95, already used for :person/firstName"

I tried the next schema:

(def user-schema [
                   {
                       :db/ident :user/firstName
                       :db/valueType :db.type/string
                       :db/cardinality :db.cardinality/one
                   }
                   {
                       :db/ident :user/lastName
                       :db/valueType :db.type/string
                       :db/cardinality :db.cardinality/one
                   }
                   {
                       :db/ident :user/fullName
                       :db/valueType :db.type/tuple
                       :db/tupleAttrs [:user/firstName :user/lastName]
                       :db/cardinality :db.cardinality/one
                   }

                           ])
(d/transact conn user-schema)

Then I did:
(d/transact
conn
[[:db/add :user/firstName :db/ident :person/firstName]
[:db/add :user/lastName :db/ident :person/lastName]
[:db/add :user/fullName :db/ident :person/fullName]
])

So, when I’m trying to transact:
(def alter-user-schema [
{
:db/ident :user/firstName
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
}

                           ])
(d/transact conn alter-user-schema)

Then I’m getting the above mentioned error, but when attribute is not part of other tuple attribute then all is good

I believe you want to be using :db.unique/identity for your :user/code, not :db.unique/value.
See https://docs.datomic.com/on-prem/identity.html#unique-identities

Identity provides the ‘upsert’ functionality you appear to be wanting.

Yea, it solves issue with entities, I just thought if I use :db/ident which unique is :db.unique/identity then datomic can resolve references, but okay for entities, what about attributes? I noticed another strange issue related to attribute aliasing in addition to issues for tuple attributes mentioned in the topic:

E.g. I have attribute:

{
    :db/ident       :product/code
    :db/valueType   :db.type/string
    :db/cardinality :db.cardinality/one
}

When alias is created

(d/transact conn [[:db/add :product/code :db/ident :product/sku]])

Both idents point to the same attribute what is correct, but once I’m transacting attribute again:

(def attr-schema [
   {
       :db/ident :product/code
       :db/valueType :db.type/string
       :db/cardinality :db.cardinality/one
   }
])
(d/transact conn attr-schema)

then datomic creates new attribute instead of executing transaction for previously created attribute.

@marshall I’m really interesting on getting your thoughts on this issue, current workaround is to pass db id of attribute then datomic does not create new attribute if existing one is already aliased

(def attr-schema [
   {
       :db/id 71 # Passing of ID fixes issue for attributes already aliased
       :db/ident :product/code
       :db/valueType :db.type/string
       :db/cardinality :db.cardinality/one
   }
])
(d/transact conn attr-schema)

I don’t understand why you are re-transacting your attribute definition in the first place.
Are you attempting to alter the schema?

As a possible case. I have schema definition represented in JSON format, and each time when my application starts JSON schema is converted to EDN and transacted to datomic, so it’s possible to transact the same attribute structure.