Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/normalizr/add country entity and students that belongs to contry #36

Open
wants to merge 23 commits into
base: feature/normalizer_implementation
Choose a base branch
from

Conversation

nasdan
Copy link
Member

@nasdan nasdan commented Jan 5, 2017

No description provided.

@nasdan nasdan requested a review from brauliodiez January 9, 2017 08:34

public constructor() {
this.id = -1;
this.gotActiveTraining = false;
this.fullname = "";
this.email = "";
this.countryId = -1;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 smells bad to me. Why not null or undefined?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think null can be a good value, on the other hand is it a good idea to define this as a class or should it be an interface? Should we add a factory to initialize a new instance?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are using this value because Uncontrolled input warning (If you initialize input value to null, it means that is uncontrolled component) But I think that this initialization has to be component liability and it doesn't delegate to class constructor used in reducer default value state. What do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, if it's a component problem, let the component to deal with it.
On the other hand, I would use an interface too. I avoid factory methods unless you need to share some initialization logic that I don't see on this case.

return {
id: country.id,
name: country.name
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need a new object? Is not just an interface? In TS, any Country is a CountryView because of structural typing, so just use the original object, even when it has extra props, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, we can return original object and in the future, map additional props or some format

@@ -7,7 +7,11 @@ class StudentMapper {
id: student.id,
gotActiveTraining: student.gotActiveTraining,
fullname: student.fullname,
email: student.email
email: student.email,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make trailing comma a convention to avoid this in PRs. It can be set up in TSLint.

email: student.email,
country: {
id: student.countryId,
name: ''

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong (before looking more code).


public constructor() {
this.id = -1;
this.gotActiveTraining = false;
this.fullname = "";
this.email = "";
this.country = new CountryView();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems wrong. Either leave country undefined, or use a CountryView.Empty like with the Null Object pattern. Otherwise it seems you're creating a brand new country for each student.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, or we could assign a default country entry. Thinking now about pros adding a factory to create then StudentView

export const getCountries = (state) : CountryView[] => {
const ids = getIds(state.countryDomain.allIds);
return ids.map(id => getCountry(state, id));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why getCountry and getCountries are on different places?

return state;
}

export const getIds = (state: number[]) => state;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably getIds is not needed.

export const getStudent = (state, id) : StudentView => {
return {
...state.studentDomain.byId[id],
country: getCountry(state, state.studentDomain.byId[id].country)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got lost: previously state was the dictionary of students. Now it's the global state. This seems hard to manage unless you strong-type arguments to prevent mismatches.

@@ -0,0 +1,4 @@
import { schema } from 'normalizr';

export const countrySchema = new schema.Entity('countries');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should put all schemas on the same file, so you can export without the schema prefix, like mySchema.country.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case it scales we could go for a solution like

+ src
    + schema
         * index.ts
         * country.ts
         * student.ts

Then just in index we export all the schemas.

If somebody has to use this he only has to worry about

import "./schema"

But on the name of the schema it self, not sure if we should keep the "Schema" prefix, to avoid creating aliases if there are name collisions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the index would be a solution in case we need to break down. Btw I meant suffix, not prefix.

import { countrySchema } from './countrySchema';

export const studentSchema = new schema.Entity('students', {
country: countrySchema

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true. Current API returns countryId, not a nested object. What I have understood so far is that this line would be helpful to denormalize country information from students, but this is not going to happen. If student gets a country object just for the UI, it doesn't apply here, and probably we would like to stop adding that country to the student object, instead you can look up the country from the Id when needed. Thumbs down to normalizr here, to extract nested object, I see value on it to convert countries array to a dictionary.

allIds
});

export const getCountries = (state) : CountryView[] => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCountries(state)

This state should be already countryDomain

@@ -6,5 +6,6 @@ export const actionsEnums = {
STUDENT_FIELD_VALUE_CHANGED: "STUDENT_FIELD_VALUE_CHANGED",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this action is covered by a thunk function

<div className={wrapperClass}>
<label htmlFor={this.props.name}>
{this.props.label}
</label>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This label should not be included in this component

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants