# Define EntitiesDefinition

## EntitiesDefinition
ED(EntitiesDefinition) is the most important part of the EM(EntitiesManager). It defines how are entities related with each other and constraints what the type of them should be. (data-type-constraints is not implemented yet)

## Sample of EntitiesDefinition
```javascript
import { EntitiesManager as EM } from '@pedaling/firebase-entities-manager'

const entitiesDefinition = {
  user: {
    signedUpAt: EM.createdAt(),
    postCount: EM.count('post'),
    commentCount: EM.count('comment'),
  },
  category: {
    name: EM.required(),
    description: EM.required()
  },
  post: {
    authorId: EM.parentId('user'),
    categoryIds: EM.parentIds('category'),
    postedAt: EM.createdAt(),
  }
}
```

## Static methods of EntitiesManager for building EntitiesDefinition
- `.parentId(entityType: string)`  
make 1:N relation
- `.parentIds(entityType: string)`  
make N:M relation
- `.createdAt()`  
set timestamp when added (in ms)
- `.updatedAt()`  
set timestamp when added & updated (in ms)
- `.required()`  
set constraints (this prop can't be null|undefined and must be provided when add)
- `.count(childEntityType: string, conditions?: Array<AggregationCondition>)`  
automatically count the number of children
- `.sum(childEntityType: string, childPropKey: string, conditions?: Array<AggregationCondition>)`
automatically sum the propValue of children
- `.duplicateChildren(childEntityType: string, mapFunc: (item:Object)=>Object, limit: number, conditions?: Array<AggregationCondition>)`
```javascript
post: {
  comments: EM.duplicateChildren('comment', comment => comment, 5, [['hidden', '!=', true]]),
}
```

## Cautions
- You must specify parent with `parentId` or `parentIds` when you want to use aggregations (`count`, `sum`, `duplicateChildren`)
```javascript
// WRONG
{
  post: {
    commentCount: EM.count('comment')
  },
  comment: {
    // no relation with post
  }
}

// OK
{
  post: {
    commentCount: EM.count('comment')
  },
  comment: {
    postId: EM.parentId('post')
  }
}
```

## Interfaces used above
- `AggregationCondition: [string, '==' | '!=' | '<' | '<=' | '>' | '>=', *]`  
e.g., ['childrenCount', '>=', 30]