Repository: typedorm/typedorm (ts)

Issue:
Attribute `names` used by the `primary key` should be unique and shall not be reused by any entities
Attribute `names` used by the `primary key` should be unique and shall not be reused by any entities.
 
When this happens, TypeDORM should throw a validation error, indicating that this is not allowed. 
However, this should still be allowed using explicit `alias` syntax.

i.e this should not be allowed

```typescript
        table: new Table({
            name: tableName,
            partitionKey: 'id',          // <- partition key attribtue name is 'id' 
            sortKey: 'sortKey',
        }),
```

```typescript
@Entity({
...
})
class Event {
    @Attribute()
    id!: string;           // <-  'id' name also used as an attribute
    
    @Attribute()
    sortKey!: number;
}
```

Pull request:
Feature/186 validate attribute names
closes #186 

Patch:
diff --git a/packages/common/src/error/conflicting-attribute-name-error.ts b/packages/common/src/error/conflicting-attribute-name-error.ts
new file mode 100644
index 0000000..5b9fdef
--- /dev/null
+++ b/packages/common/src/error/conflicting-attribute-name-error.ts
@@ -0,0 +1,18 @@
+export class ConflictingAttributeNameError extends Error {
+  name = 'ConflictingAttributeNameError';
+
+  constructor({
+    attributeName,
+    entity,
+    tableName,
+  }: {
+    attributeName: string;
+    entity: string;
+    tableName: string;
+  }) {
+    super();
+
+    this.message = `Attribute name "${attributeName}" can not be used for other entity "${entity}".    
+    The table "${tableName}" has a partition key or sort key with the same name.`;
+  }
+}
diff --git a/packages/common/src/error/index.ts b/packages/common/src/error/index.ts
index 7b84e26..a2b5c05 100644
--- a/packages/common/src/error/index.ts
+++ b/packages/common/src/error/index.ts
@@ -20,3 +20,4 @@ export * from './invalid-unique-attribute-update-error';
 export * from './invalid-parallel-scan-limit-option-error';
 export * from './invalid-dynamic-update-attribute-value';
 export * from './unknown-attribute-value-generation-strategy-error';
+export * from './conflicting-attribute-name-error';
diff --git a/packages/core/src/classes/connection/attribute-metadata-builder.ts b/packages/core/src/classes/connection/attribute-metadata-builder.ts
index 481febd..792e4c9 100644
--- a/packages/core/src/classes/connection/attribute-metadata-builder.ts
+++ b/packages/core/src/classes/connection/attribute-metadata-builder.ts
@@ -1,5 +1,6 @@
 import {
   AutoGenerateAttributeRawMetadataOptions,
+  ConflictingAttributeNameError,
   EntityRawMetadataOptions,
   IsAutoGenerateAttributeRawMetadataOptions,
   MetadataManager,
@@ -23,12 +24,29 @@ export class AttributesMetadataBuilder {
       );
 
     return getRawAttributesForEntity.map(attr => {
-      if (IsAutoGenerateAttributeRawMetadataOptions(attr)) {
-        const entityMetadata = this.tryGetEntityMetadata(
-          attributeTargetEntityClass,
-          decoratedEntityClass
-        );
+      const entityMetadata = this.tryGetEntityMetadata(
+        attributeTargetEntityClass,
+        decoratedEntityClass
+      );
 
+      // validate attribute names for primary key conflicts
+      if (
+        [
+          entityMetadata.table?.partitionKey,
+          entityMetadata.table?.usesCompositeKey() &&
+            entityMetadata.table?.sortKey,
+        ]
+          .filter(Boolean)
+          .includes(attr.name)
+      ) {
+        throw new ConflictingAttributeNameError({
+          attributeName: attr.name,
+          entity: entityMetadata.name,
+          tableName: entityMetadata.table?.name || '',
+        });
+      }
+
+      if (IsAutoGenerateAttributeRawMetadataOptions(attr)) {
         return this.validateAndBuildAutoGeneratedAttributeMetadata(
           attr,
           entityMetadata
@@ -55,6 +73,7 @@ export class AttributesMetadataBuilder {
         );
       }
     }
+
     return new AutoGeneratedAttributeMetadata({
       ...attr,
     });


Test patch:
diff --git a/packages/core/src/classes/connection/__test__/attributes-metadata-builder.spec.ts b/packages/core/src/classes/connection/__test__/attributes-metadata-builder.spec.ts
index 5609c57..b6c6cb5 100644
--- a/packages/core/src/classes/connection/__test__/attributes-metadata-builder.spec.ts
+++ b/packages/core/src/classes/connection/__test__/attributes-metadata-builder.spec.ts
@@ -6,6 +6,7 @@ import {
   Attribute,
   AutoGenerateAttribute,
   AUTO_GENERATE_ATTRIBUTE_STRATEGY,
+  ConflictingAttributeNameError,
 } from '@typedorm/common';
 import {UserAutoGenerateAttributes} from '../../../../__mocks__/user-auto-generate-attributes';
 import {User} from '../../../../__mocks__/user';
@@ -245,3 +246,29 @@ test('throws an error when attribute referenced in primary key is also marked as
     'Failed to build metadata for "adminId", attributes referenced in primary key cannot be auto updated.'
   );
 });
+
+test('throws an error when attribute name conflicts with a primary key or sort key name of the table ', () => {
+  const mockTable = new Table({
+    name: 'admin-table',
+    partitionKey: 'id',
+  });
+  @Entity({
+    name: 'admin-test',
+    table: mockTable,
+    primaryKey: {
+      partitionKey: 'ADMIN#{{id}}',
+    },
+  })
+  class AdminTest {
+    @AutoGenerateAttribute({
+      strategy: AUTO_GENERATE_ATTRIBUTE_STRATEGY.KSUID,
+    })
+    id: string;
+  }
+
+  const metadata = () =>
+    attributesMetadataBuilder
+      .build(mockTable, AdminTest, AdminTest)
+      .map(obj => Object.assign({}, obj));
+  expect(metadata).toThrow(ConflictingAttributeNameError);
+});