aaberg / sql2o

sql2o is a small library, which makes it easy to convert the result of your sql-statements into objects. No resultset hacking required. Kind of like an orm, but without the sql-generation capabilities. Supports named parameters.
http://sql2o.org
MIT License
1.14k stars 229 forks source link

Intergration of Converters and Spring / Model attributes in model #288

Open z3ntu opened 6 years ago

z3ntu commented 6 years ago

Hello, I'm trying to create a small application using sql2o and Spring. Currently I have a Chat and a User domain class.

@Data
@NoArgsConstructor
@RequiredArgsConstructor
public class User {

    private Long id;

    @NonNull
    private String username;

    @NonNull
    private String realname;
}

and

@Data
@NoArgsConstructor
@RequiredArgsConstructor
public class Chat {

    private Long id;

    @NonNull
    private User user1;

    @NonNull
    private User user2;

    @NonNull
    private DateTime createdAt;
}

but I noticed that sql2o doesn't automatically fetch the objects/rows for the "User" fields in a Chat (which is kind of expected of such a light library). My question is how to do that (without necessarily changing my domain class). In your example (https://github.com/aaberg/Sql2oExample) I see that you just put the ids in classes that want others. I've tried what was written here but I'm not sure if this comment was meant as a question or as a solution^^. Anyways, with

    @Override
    public List<Chat> getChatsByUser(User user) {
        final String sql =
            "SELECT chat.id, user1, user2, createdAt, " +
            "u1.id AS 'user1.id', u1.username AS 'user1.username', u1.realname AS 'user1.realname', " +
            "u2.id AS 'user2.id', u2.username AS 'user2.username', u2.realname AS 'user2.realname' " +
            "FROM chat " +
            "INNER JOIN user u1 ON user1 = u1.id " +
            "INNER JOIN user u2 ON user2 = u2.id " +
            "WHERE user1=:user OR " +
            "user2=:user";

        try (Connection con = sql2o.open()) {
            return con.createQuery(sql)
                    .addParameter("user", user.getId())
                    .executeAndFetch(Chat.class);
        }
    }

I get a java.lang.IllegalArgumentException: java.lang.ClassCastException@11ad5cef but I couldn't find any documentation if it's possible to do with sql2o with my current model (so replacing java references with IDs). Thanks :) EDIT: Just saw in your example project, that you created a PriorityConverter which is doing basically what I want to do. Will try that.

z3ntu commented 6 years ago

Now I have a converter:

@Component
public class UserConverter implements Converter<User> {

    @Autowired
    private UserRepository userRepository;

    @Override
    public User convert(Object val) throws ConverterException {
        if (val instanceof Number) {
            Long userId = ((Number) val).longValue();
            return userRepository.getUserById(userId);
        } else {
            return null;
        }
    }

    @Override
    public Object toDatabaseParam(User val) {
        if (val == null) {
            return null;
        } else {
            return val.getId();
        }
    }
}

and

    @Bean
    public Sql2o getSql2o(UserConverter userConverter) {
        final Map<Class, Converter> mappers = new HashMap<>();
        mappers.put(User.class, userConverter);
        return new Sql2o(dataSource(),
                new NoQuirks(mappers));
    }

which works great. Now only have a problem when I add another converter I get Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'getSql2o': Requested bean is currently in creation: Is there an unresolvable circular reference? which I'm trying to work around...

z3ntu commented 6 years ago

Okay I solved the last issue by adding @Lazy next to the @Autowired like this:

@Component
public class ChatConverter implements Converter<Chat> {

    @Autowired
    @Lazy
    private ChatRepository chatRepository;

now everything is working great as far as I can see.

Now an example like this is missing for the wiki (either in the Converters page or in the Spring page) :)

zapodot commented 6 years ago

@z3ntu feel free to add documentation to the Wiki. That would be great!