Skip to content

Commit c719709

Browse files
committed
initialize project with CI, example models and basic repository setup
1 parent 5a12a7b commit c719709

File tree

8 files changed

+393
-0
lines changed

8 files changed

+393
-0
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["main", "master"]
6+
pull_request:
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Set up JDK 11
14+
uses: actions/setup-java@v4
15+
with:
16+
distribution: temurin
17+
java-version: '11'
18+
cache: 'maven'
19+
- name: Build with Maven
20+
run: mvn -B -DskipTests=false verify

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"java.compile.nullAnalysis.mode": "automatic",
3+
"java.configuration.updateBuildConfiguration": "interactive"
4+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Theory (Java)
2+
3+
[![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/ci.yml)
4+
[![Maven Central](https://img.shields.io/maven-central/v/io.retrorock/theory.svg)](https://central.sonatype.com/artifact/io.retrorock/theory)
5+
6+
Note: Replace `OWNER/REPO` with your GitHub org/repo, and adjust Maven Central coordinates when published.
7+
8+
A small, annotation-driven data access library built on Spring JDBC. It provides:
9+
10+
- Model mapping via annotations (`@Table`, `@Column`, `@PrimaryKey`, `@BelongsTo`) on POJOs.
11+
- A lightweight `Repository<T>` base with common query and persistence helpers.
12+
- A simple SQL builder through `Query` and `ModelMapper` to generate SELECTs with joins and limits.
13+
14+
This is intended for pragmatic, minimal data access without a heavy ORM.
15+
16+
## Requirements
17+
18+
- Java 8+
19+
- Maven 3+
20+
- Spring JDBC 4.2.x (pulled via `pom.xml`)
21+
22+
## Project Structure
23+
24+
- `pom.xml` — Maven build and dependencies
25+
- `src/main/java/io/retrorock/theory/` — library source
26+
- `annotations/``@Table`, `@Column`, `@PrimaryKey`, `@BelongsTo`
27+
- `base/``Model`, `Repository`, `Operation`
28+
- `components/` — SQL building blocks (e.g., `From`, `Join`)
29+
- `helpers/` — mappers and utilities (e.g., `ModelMapper`, `RowMapperHelper`)
30+
- `interfaces/``IRepository`, `IOperation`
31+
- `operations/``Query`, `Insert`, `Update`, `Delete`
32+
33+
## Installation
34+
35+
Build and install to your local Maven repository:
36+
37+
```bash
38+
mvn clean install
39+
```
40+
41+
Then, in a separate project, add the dependency (adjust version if needed):
42+
43+
```xml
44+
<dependency>
45+
<groupId>io.retrorock</groupId>
46+
<artifactId>theory</artifactId>
47+
<version>1.0-SNAPSHOT</version>
48+
</dependency>
49+
```
50+
51+
## Quick Start
52+
53+
### 1) Define a Model
54+
55+
Annotate your entity with table/column mapping. Extend `Model` to get helpers like `serialize()` and JDBC `RowMapper` behavior.
56+
57+
```java
58+
import io.retrorock.theory.annotations.*;
59+
import io.retrorock.theory.base.Model;
60+
61+
@Table(name = "users", alias = "u")
62+
public class User extends Model {
63+
@PrimaryKey
64+
@Column(name = "id", alias = "u_id")
65+
private Integer id;
66+
67+
@Column(name = "email", alias = "u_email")
68+
private String email;
69+
70+
@Column(name = "name", alias = "u_name")
71+
private String name;
72+
73+
// getters/setters ...
74+
}
75+
```
76+
77+
Relationships can be declared with `@BelongsTo` on a field referencing another `Model`.
78+
79+
### 2) Create a Repository
80+
81+
Extend `Repository<T>` and wire a `JdbcTemplate` (via Spring or manually through `JdbcDaoSupport`).
82+
83+
```java
84+
import io.retrorock.theory.base.Repository;
85+
import org.springframework.jdbc.core.RowMapper;
86+
import org.springframework.jdbc.core.BeanPropertyRowMapper;
87+
88+
public class UserRepository extends Repository<User> {
89+
public UserRepository() {
90+
this.setEntity(User.class);
91+
this.setMapper((RowMapper<User>) new BeanPropertyRowMapper<>(User.class));
92+
this.setTableName("users");
93+
this.setPrimaryKeyName("id");
94+
}
95+
}
96+
```
97+
98+
Inject a `DataSource` so `JdbcDaoSupport` can provide `JdbcTemplate`:
99+
100+
```java
101+
import javax.sql.DataSource;
102+
103+
public class UserRepository extends Repository<User> {
104+
public UserRepository(DataSource dataSource) {
105+
this(); // calls default ctor to set entity/mapper
106+
setDataSource(dataSource);
107+
}
108+
}
109+
```
110+
111+
### 3) Querying
112+
113+
Use the built-in `Query` builder. `Repository#list()` and `Repository#find(id)` leverage `Query` and your mapper.
114+
115+
```java
116+
UserRepository repo = new UserRepository(dataSource);
117+
118+
// Find by primary key
119+
User u = repo.find(1);
120+
121+
// List all
122+
List<User> users = repo.list();
123+
124+
// Custom select with Query
125+
var q = new io.retrorock.theory.operations.Query();
126+
q.db.from(User.class)
127+
.fields(User.class)
128+
.where("u.email = '%s'", "alice@example.com")
129+
.limit(10);
130+
List<User> result = repo.select(q, repo.mapper);
131+
```
132+
133+
Note: `Query#selectString()` prints the generated SQL and resets internal state after building.
134+
135+
### 4) Insert/Update/Delete
136+
137+
`Repository` exposes `persist` helpers that accept an `Operation`:
138+
139+
```java
140+
User user = new User();
141+
user.setEmail("bob@example.com");
142+
user.setName("Bob");
143+
144+
// Insert and return generated key
145+
Integer id = repo.persist(user, new io.retrorock.theory.operations.Insert());
146+
user.identify(id);
147+
148+
// Update example
149+
var update = new io.retrorock.theory.operations.Update();
150+
repo.persist(user, update);
151+
152+
// Raw SQL
153+
repo.persist("DELETE FROM users WHERE id = 123");
154+
```
155+
156+
## Minimal Runnable Example
157+
158+
This repo includes a minimal example using H2 in-memory DB under `src/test/java/io/retrorock/theory/example/`:
159+
160+
- `User` model: `src/test/java/io/retrorock/theory/example/User.java`
161+
- `UserRepository`: `src/test/java/io/retrorock/theory/example/UserRepository.java`
162+
- Test: `src/test/java/io/retrorock/theory/example/UserRepositoryTest.java`
163+
164+
Run just the example test:
165+
166+
```bash
167+
mvn -Dtest=io.retrorock.theory.example.UserRepositoryTest test
168+
```
169+
170+
## Spring Configuration
171+
172+
In XML or Java config, provide a `DataSource` and wire your repository. Example (Java config):
173+
174+
```java
175+
import org.springframework.context.annotation.*;
176+
import org.springframework.jdbc.datasource.DriverManagerDataSource;
177+
178+
@Configuration
179+
public class AppConfig {
180+
@Bean
181+
public DataSource dataSource() {
182+
DriverManagerDataSource ds = new DriverManagerDataSource();
183+
ds.setDriverClassName("org.postgresql.Driver");
184+
ds.setUrl("jdbc:postgresql://localhost:5432/app");
185+
ds.setUsername("app");
186+
ds.setPassword("secret");
187+
return ds;
188+
}
189+
190+
@Bean
191+
public UserRepository userRepository(DataSource ds) {
192+
return new UserRepository(ds);
193+
}
194+
}
195+
```
196+
197+
## Development
198+
199+
- Build: `mvn clean package`
200+
- Tests: `mvn test`
201+
202+
### TDD Flow (suggested)
203+
204+
1. Write a failing test under `src/test/java/` that describes desired behavior.
205+
2. Run tests: `mvn test` and watch it fail.
206+
3. Implement the minimal code in `src/main/java/` to make it pass.
207+
4. Refactor ruthlessly while keeping tests green.
208+
5. Repeat.
209+
210+
## Notes
211+
212+
- This library targets Spring 4.2.x APIs as specified in `pom.xml`.
213+
- Some operations rely on column aliases matching the `@Column(alias=...)` convention during mapping.
214+
215+
## License
216+
217+
MIT — see `LICENSE` for details.

pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,20 @@
104104
<artifactId>google-collections</artifactId>
105105
<version>1.0</version>
106106
</dependency>
107+
108+
<!-- REQUIRED: Spring JDBC for JdbcDaoSupport/JdbcTemplate -->
109+
<dependency>
110+
<groupId>org.springframework</groupId>
111+
<artifactId>spring-jdbc</artifactId>
112+
<version>4.2.1.RELEASE</version>
113+
</dependency>
114+
115+
<!-- TEST: In-memory database for runnable examples/tests -->
116+
<dependency>
117+
<groupId>com.h2database</groupId>
118+
<artifactId>h2</artifactId>
119+
<version>1.4.200</version>
120+
<scope>test</scope>
121+
</dependency>
107122
</dependencies>
108123
</project>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.retrorock.theory.example;
2+
3+
import io.retrorock.theory.annotations.Column;
4+
import io.retrorock.theory.annotations.PrimaryKey;
5+
import io.retrorock.theory.annotations.Table;
6+
import io.retrorock.theory.base.Model;
7+
8+
@Table(name = "users", alias = "u")
9+
public class User extends Model {
10+
@PrimaryKey
11+
@Column(name = "id", alias = "u_id")
12+
private Integer id;
13+
14+
@Column(name = "email", alias = "u_email")
15+
private String email;
16+
17+
@Column(name = "name", alias = "u_name")
18+
private String name;
19+
20+
public Integer getId() { return id; }
21+
public void setId(Integer id) { this.id = id; }
22+
23+
public String getEmail() { return email; }
24+
public void setEmail(String email) { this.email = email; }
25+
26+
public String getName() { return name; }
27+
public void setName(String name) { this.name = name; }
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.retrorock.theory.example;
2+
3+
import io.retrorock.theory.base.Repository;
4+
import org.springframework.jdbc.core.RowMapper;
5+
6+
import javax.sql.DataSource;
7+
8+
public class UserRepository extends Repository<User> {
9+
public UserRepository(DataSource dataSource) {
10+
this.setEntity(User.class);
11+
this.setMapper((RowMapper<User>) (rs, rowNum) -> (User) new User().map(rs, rowNum));
12+
this.setTableName("users");
13+
this.setPrimaryKeyName("id");
14+
setDataSource(dataSource);
15+
}
16+
}

0 commit comments

Comments
 (0)