Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    goqp
    @goqp
    Okay, I am still kind of confused because I dont know jcabi and the lambda mapping part is new to me, BUT, this looks wrong.
    You are doing all of the work all over again in this decorator.
    First, you need a target or origin result set representing the list of people that is unfiltered. This is the only object that will EVER touch the database. So is that what you are trying to show here, and then you will decorate?
    Maybe I didnt know how to read this actually...
    Paulo
    @ptrecenti
    yes that is the point, the original implementation I'm selecting all database, but I don't want to fetch all database and to get only one record
    goqp
    @goqp
    oh so, like if the person has ID whatever, or email whatever, you only want to go to the database and get that one record.
    rather than getting the entire list of people.
    yes?
    Paulo
    @ptrecenti
    yes
    this is the original implementation
    public final class PgPeople implements People {
    
        private final DataSource dataSource;
    
        public PgPeople(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        @Override
        public Iterable<Person> iterate() {
            try {
                return new JdbcSession(this.dataSource)
                        .sql("SELECT id FROM person")
                        .select(
                                new ListOutcome<>(
                                        (ListOutcome.Mapping<Person>) rset -> new PgPerson(
                                                dataSource,
                                                rset.getInt(1)
                                        )
                                )
                        );
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public Person add(Email email) {
            try {
                return new PgPerson(
                        this.dataSource,
                        new JdbcSession(dataSource)
                                .sql("INSERT INTO person (email) VALUES (?)")
                                .set(email.toString())
                                .update(new SingleOutcome<>(Long.class)).intValue()
                );
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    goqp
    @goqp
    Okay, here's your problem. It's conceptual.
    A list of people is all people who fit some criteria. By definition if no criteria are specified then that means the entire set.
    A filtered list of people is a list of people, who, having all people who fit a criteria, only returns you some subset that matches an additional criteria. That is why he is a decorator.
    You cant mix and match the ideas like I think you are doing.
    Paulo
    @ptrecenti
    so should I have to apply something like a filter inside of PgPeople right?
    ok now I see
    goqp
    @goqp
    Once you have the list, you have to stick with him. If you want to filter over him you have to do it to the entire list.
    You cant try to inject some kind of new sql to make the inner list act differently from what he was doing before.
    That would be a procedural idea.
    Paulo
    @ptrecenti
    something like that
    public final class PgOrganizations implements Organizations {
    
        private final DataSource dataSource;
        private final Filter filteredBy;
        private final Object[] params;
    
        public PgOrganizations(DataSource dataSource) {
            this(
                    dataSource,
                    Filter.NONE
            );
        }
    
        public PgOrganizations(DataSource dataSource, Filter filteredBy, Object... params) {
            this.dataSource = dataSource;
            this.filteredBy = filteredBy;
            this.params = params;
        }
    
        @Override
        public Iterable<Organization> iterate() {
            try {
    
                final JdbcSession session = new JdbcSession(this.dataSource);
    
                session.sql(
                        String.format("SELECT id FROM organization %s", filteredBy.where)
                );
    
                for (Object param : params) {
                    session.set(param);
                }
    
                return session.select(
                        new ListOutcome<>(
                                (ListOutcome.Mapping<Organization>) rset -> new PgOrganization(
                                        dataSource,
                                        rset.getInt(1)
                                )
                        )
                );
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public Organization add(OrganizationUrl url) {
            try {
                return new PgOrganization(
                        this.dataSource,
                        new JdbcSession(dataSource)
                                .sql("INSERT INTO organization (email) VALUES (?)")
                                .set(url.toString())
                                .update(new SingleOutcome<>(Long.class)).intValue()
                );
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
        public enum Filter {
            NONE(""),
            BY_URL("where url = ?");
    
            private final String where;
    
            Filter(String where) {
                this.where = where;
            }
        }
    }
    goqp
    @goqp
    no this is going in the wrong direction
    you are creating a super object that is god-controlling all of the needed behavior in this problem.
    think about modelling
    Paulo
    @ptrecenti
    do you have any example about what do I need to re-think?
    goqp
    @goqp
    I will try and write one. Lets think about the problem space of a bit. Why do you need a list of people who only have a single email or is restricted?
    What is going on here that we are MODELLING?
    Paulo
    @ptrecenti
    I got your point
    the problem that I'm trying to solve is sometimes I need to find a person by email but the identity of the person is an int id like that
    @EqualsAndHashCode(of = "id")
    public final class PgPerson implements Person {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(PgPerson.class);
    
        private final DataSource dataSource;
        private final int id;
        private final Account account;
    
        public PgPerson(DataSource dataSource, int id) {
            this(
                    dataSource,
                    id,
                    new PgAccount(
                            dataSource,
                            id
                    )
            );
        }
    
        public PgPerson(DataSource dataSource, int id, Account account) {
            this.dataSource = dataSource;
            this.id = id;
            this.account = account;
        }
    
        @Override
        public int id() {
            return this.id;
        }
    
    
        @Override
        public void update(Name name) {
    
            LOGGER.debug(
                    "name: {}",
                    name.toString());
    
            try {
                new JdbcSession(this.dataSource)
                        .sql("update person set first=?, middle=?, last=? where id = ?")
                        .set(name.first())
                        .set(name.middle())
                        .set(name.last())
                        .set(this.id)
                        .execute();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public Name name() {
            try {
                return new JdbcSession(this.dataSource)
                        .sql("select COALESCE(first,''), COALESCE(middle,''), COALESCE(last,'') from person where id = ?")
                        .set(this.id)
                        .select((Outcome<Name>) (rset, stmt) -> {
                            rset.next();
                            return new DefaultName(
                                    rset.getString(1),
                                    rset.getString(2),
                                    rset.getString(3)
                            );
                        });
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public Account account() {
            return this.account;
        }
    
    }
    goqp
    @goqp
    right, could be actually we want to find a person by first name, last name, or combination of both of them too.
    Could be by organization.
    The list of attributes is pretty large.
    Paulo
    @ptrecenti
    in the case of email it's unique and could define the identity of the person, but not the name (first, last, soon) because many people can have the same last name and this will return to me a list of people
    but I really don't know how fit the requirement to filter by last name (for example) without do what I made in the people class to filter by last name without rewrite the iterate method or use filter like the organizations
    goqp
    @goqp
    what I am saying is finding a person by email is a special case of finding some subset of people by any criteria
    whats the difference? None.
    The fact that the email is a unique mapping to a person is irrelevant.
    See, if you are looking for a person you have to stick with the person object.
    But if you are looking for potentially more than you just need a list that sorts on any criteria you specify.

    Paulo
    @ptrecenti
    ok, how could I deal with the fact to do not load the entire database and apply this criteria without re-write the iterate method?
    goqp
    @goqp
    Wait, I think you have solved the problem but your objects are like machines, not models.
    You need to strip them down and repackage the code.
    Paulo
    @ptrecenti
    I've tried to create a strategy to do that but I thought that it's going to a wrong way too
    goqp
    @goqp
    It was because you had helper objects for filtering inside of your list object.
    that isn't right.
    First of all. The list of people is a thing that we are modelling. Right? So it has a coordinate to a real world target (the database), which as all of the needed information about this list.
    So, the coordinate is the sql that the databse will use to create a temporary file (the result set of the query), that will then be read by the people list object.
    Right?
    Paulo
    @ptrecenti
    ok
    goqp
    @goqp
    So then, you have a list called FilteredPeople. Can you make JUST that for a second?