use {@link TriOrm#query(Class)} to get {@link com.hendrix.triorm.query.TriQuery.Builder} of a table.
15 | *
use {@link TriOrm#load(Class, String)} to get a single Data of a table by identifier.
16 | *
use {@link TriOrm#table(Class)} to get {@link com.hendrix.triorm.TriTable} reference of the class type.
17 | *
use {@link com.hendrix.triorm.TriOrm#newDatabase()} to get a new {@link com.hendrix.triorm.TriDatabase.Builder} instance.
18 | *
19 | *
20 | * TODO:
21 | * - add a method to get all the tables of a specific database by name.
22 | *
23 | * @author Tomer Shalev
24 | *
25 | */
26 | @SuppressWarnings("UnusedDeclaration")
27 | public final class TriOrm
28 | {
29 | private static TriOrm _instance = null;
30 | /**
31 | * the context
32 | */
33 | private Context _ctx = null;
34 | /**
35 | * class names with package to {@link TriTable} map
36 | */
37 | private HashMap _mapTables = null;
38 |
39 | private TriOrm() {
40 | if(_instance != null)
41 | throw new RuntimeException("TriOrm is a singleton. please use TriOrm.instance() instead");
42 |
43 | TriData.triOrm = this;
44 | _mapTables = new HashMap<>();
45 | }
46 |
47 | /**
48 | * get the representing {@link TriTable}
49 | *
50 | * @param type the class type of the table
51 | * @param the type itself
52 | *
53 | * @return {@link TriTable}
54 | */
55 | public static TriTable table(Class type) {
56 | return instance().getTable(type);
57 | }
58 |
59 | /**
60 | * load data from the table by identifier.
61 | *
62 | * @param type the class type of the table
63 | * @param id the identifier of the data
64 | * @param the type itself
65 | *
66 | * @return the data
67 | */
68 | public static T load(Class type, String id) {
69 | return table(type).getData(id);
70 | }
71 |
72 | /**
73 | * get the query builder.
74 | *
75 | * @param type the class type of the table
76 | * @param the type itself
77 | *
78 | * @return the {@link com.hendrix.triorm.query.TriQuery.Builder} instance
79 | *
80 | * @see com.hendrix.triorm.query.TriQuery.Builder
81 | */
82 | public static TriQuery.Builder query(Class type) {
83 | return table(type).getQueryBuilder();
84 | }
85 |
86 | /**
87 | * get a new Database builder object. you can also use:
88 | * {@code new TriDatabase.Builder(..)} yourself.
89 | *
90 | * @return {@link com.hendrix.triorm.TriDatabase.Builder}
91 | */
92 | public static TriDatabase.Builder newDatabase() {
93 | return new TriDatabase.Builder(null);
94 | }
95 |
96 | /**
97 | * get the instance. package protected.
98 | *
99 | * @return the only {link TriOrm} instance.
100 | */
101 | static protected TriOrm instance() {
102 | return (_instance==null) ? _instance = new TriOrm() : _instance;
103 | }
104 |
105 | /**
106 | * add tables to the ORM. this is used by {@link com.hendrix.triorm.TriDatabase} and therefore is protected access.
107 | *
108 | * @param tables a Map Collection between class names into {@link com.hendrix.triorm.TriTable}
109 | */
110 | protected void addTables(HashMap tables) {
111 | _mapTables.putAll(tables);
112 | }
113 |
114 | /**
115 | * get a table by it's identifier from any database that was loaded.
116 | * table names a are unique, since the class type is used. Therefore,
117 | * client does not have to specify database name.
118 | *
119 | * @param type the type of Class the table handles
120 | * @param the type of Class the table handles
121 | *
122 | * @return the table
123 | *
124 | * @throws com.hendrix.triorm.exceptions.TableNotExistException if the table was not registered.
125 | */
126 | @SuppressWarnings("unchecked")
127 | protected TriTable getTable(Class type)
128 | {
129 | TriTable triTable = (TriTable)_mapTables.get(type.getName());
130 |
131 | if(triTable == null)
132 | throw new TableNotExistException(type);
133 |
134 | return triTable;
135 | }
136 |
137 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-TriOrm
2 | a 3d database ORM experiment for Android. (used in two commercial projects).
3 | based around small tables concept and `JVM Serialization`.
4 |
5 | [](https://android-arsenal.com/details/1/2293)
6 |
7 | ## How to use
8 | simply fork or download the project, you can also download and create `.aar` file yourself.
9 |
10 | ### Explanation
11 | `TriOrm` is a very light, simple and efficient `ORM` with partial `SQL` wrapping, with the following theme:
12 | * every Object (`TriData` extension) is serialized and saved in the database.
13 | * you can only query by three fields: `id`, `time_created` and `type`.
14 | * familiar no fuss Builder pattern to construct database.
15 | * easy API to query, save and load typed objects.
16 | * a very small usage of annotation(Optional).
17 | * no learning curve whatsoever, no Boiler-plate code.
18 | * Database is ready to use in less than couple of minutes.
19 | * everything is typed.
20 | * most of the presistent is carried by `JVM Serialization` and minimal small SQL table.
21 |
22 | ### construct your Model/Tables
23 | Simply extend `TriData` with the following annotations(Optional).
24 | ```java
25 | @TriTable(dbName = "myDataBase", tableName = "user")
26 | public class User extends TriData {
27 | public String firstName = "John";
28 | public String lastName = "Dow";
29 |
30 | public User() {
31 | }
32 |
33 | public User(String id) {
34 | super(id);
35 | }
36 | }
37 |
38 | @TriTable(dbName = "myDataBase", tableName = "location")
39 | public class Location extends TriData {
40 | public String city = "city";
41 | public String state = "state";
42 |
43 | public Location() {
44 | }
45 |
46 | }
47 |
48 | ```
49 |
50 | every `TriData` has the following indexed/query-able properties with getters/setters:
51 | * `setId(..)` - you can set the id or it will be set automatically for you.
52 | * `setType(..)` - some auxiliary field.
53 | * `setTimeCreated(..)` - also set-up for you by default.
54 |
55 | ### construct your Database
56 | constructing a database takes one line of code
57 | ```java
58 | new TriDatabase.Builder(this).addTable(User.class).addTable(Location.class).build();
59 |
60 | ```
61 |
62 | and without annotations:
63 | ```java
64 | new TriDatabase.Builder(this).name("myDataBase").addTable("user", User.class).addTable("location", Location.class).build();
65 |
66 | ```
67 |
68 | ### Saving into your Database
69 | Simply invoke the `save()` method on your extended `TriData` object.
70 | ```java
71 | User user = new User();
72 |
73 | user.setId("theDude");
74 | user.setType("Java programmer");
75 |
76 | user.firstName = "Jimi";
77 | user.lastName = "Hendrix";
78 |
79 | user.save();
80 | ```
81 |
82 | ### loading a single object from your Database
83 | Simply use the `TriOrm.load(..)` Singleton and use your typed object.
84 | ```java
85 | User user = TriOrm.load(User.class, "theDude");
86 | ```
87 |
88 | ### querying from your Database
89 | Simply use the `TriOrm.query(..)` builder Singleton and use your typed object.
90 | ```java
91 | ArrayList list_users = TriOrm.query(User.class).timeCreatedFrom(0).timeCreatedTo(100).type("Java programmer").build().query();
92 | ```
93 | you can query anything from the three properties: `id`, `timeCreated` and `type`.
94 |
95 | ### getting an instance of a table
96 |
97 | Simply use the `TriOrm.table(..)` Singleton and use your typed object.
98 | With table you can have more options and some sandbox methods.
99 | ```java
100 | TriTable table = TriOrm.table(User.class);
101 | ```
102 |
103 | ### Important Notes
104 | The presistent layer is built around `JVM Serialization`, therefore
105 | there are important considerations for when evolving your model/tables like any
106 | other database solution, beware of the folowing:
107 | * TriData is based on `JVM Serialization`, therefore:
108 | * adding new fields is compatible.
109 | * deleting/renaming exiting fields is **not compatible**, Therefore you will have
110 | to implement your `writeObject/readObject` and be smart about it.
111 | * adding new methods, altering previous methods is incompatible.
112 | * look here for more info [Durable Java: Serialization](http://macchiato.com/columns/Durable4.html)
113 | * I recommend using primitive types as much as possible when designing the model/table.
114 | * for best performence and compatibility control, you can experiment with `Externalizable` interface for reflection free.
115 | * contributions are most welcome with regards to compatiblity/performence.
116 |
117 |
118 | ### Dependencies
119 | * AOSP
120 |
121 | ### Terms
122 | * completely free source code. [Apache License, Version 2.0.](http://www.apache.org/licenses/LICENSE-2.0)
123 | * if you like it -> star or share it with others
124 |
125 | ### Contact Author
126 | * [tomer.shalev@gmail.com](tomer.shalev@gmail.com)
127 | * [Google+ TomershalevMan](https://plus.google.com/+TomershalevMan/about)
128 | * [Facebook - HendrixString](https://www.facebook.com/HendrixString)
129 |
130 |
--------------------------------------------------------------------------------
/triorm.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/src/main/java/com/hendrix/triorm/TriDatabase.java:
--------------------------------------------------------------------------------
1 | package com.hendrix.triorm;
2 |
3 | import android.content.Context;
4 |
5 | import com.hendrix.triorm.utils.SReflection;
6 | import com.hendrix.triorm.utils.SReflection.Meta;
7 |
8 | import java.util.HashMap;
9 |
10 | /**
11 | * immutable 3D Database.
12 | * may only be built with {@link com.hendrix.triorm.TriDatabase.Builder}.
13 | * After the {@link TriDatabase} was built, it will be automatically registered
14 | * in the {@link com.hendrix.triorm.TriOrm} master object, for future usage.
15 | * (consult documentation of {@code TriOrm})
16 | *
17 | *
18 | *
use {@link #getTable(Class)} to get the table by id
19 | *
20 | *
21 | * @see TriDatabase.Builder
22 | *
23 | * @author Tomer Shalev
24 | *
25 | */
26 | @SuppressWarnings("UnusedDeclaration")
27 | public class TriDatabase
28 | {
29 | /**
30 | * the context
31 | */
32 | private Context _ctx = null;
33 | /**
34 | * the data base name
35 | */
36 | private String _dbName = null;
37 | /**
38 | * the version of the database
39 | */
40 | private int _version = 0;
41 |
42 | private HashMap _mapTables = null;
43 |
44 | private TriDatabase(Builder builder)
45 | {
46 | _version = builder._version;
47 | _ctx = builder._ctx;
48 | _dbName = builder._dbName;
49 | _mapTables = builder._mapTables;
50 |
51 | TriOrm.instance().addTables(_mapTables);
52 | }
53 |
54 | /**
55 | * get a table by it's class type.
56 | *
57 | * @param type the type of Class the table handles
58 | * @param the type of Class the table handles
59 | *
60 | * @return the table
61 | */
62 | @SuppressWarnings("unchecked")
63 | public TriTable getTable(Class type)
64 | {
65 | String uniqueClassName = type.getName();
66 |
67 | return (TriTable)_mapTables.get(uniqueClassName);
68 | }
69 |
70 | /**
71 | * @return database name
72 | */
73 | public String getDatabaseName() {
74 | return _dbName;
75 | }
76 |
77 | /**
78 | * @return database version
79 | */
80 | public int version() {
81 | return _version;
82 | }
83 |
84 | /**
85 | * builder for immutable controller for {@link TriDatabase}
86 | *
87 | * @author Tomer Shalev
88 | */
89 | public static class Builder
90 | {
91 | private Context _ctx = null;
92 | private String _dbName = null;
93 | private int _version = 1;
94 |
95 | private HashMap _mapTables = null;
96 |
97 | /**
98 | * @param ctx a context
99 | */
100 | public Builder(Context ctx) {
101 | _ctx = ctx;
102 |
103 | _mapTables = new HashMap<>();
104 | }
105 |
106 | /**
107 | * build the database
108 | *
109 | * @return {@link TriDatabase} instance
110 | */
111 | public TriDatabase build() {
112 | return new TriDatabase(this);
113 | }
114 |
115 | /**
116 | * set another context
117 | *
118 | * @see TriDatabase.Builder
119 | */
120 | public Builder context(Context ctx) {
121 | _ctx = ctx;
122 |
123 | return this;
124 | }
125 |
126 | /**
127 | * set a version
128 | *
129 | * @see TriDatabase.Builder
130 | */
131 | public Builder Version(int v) {
132 | _version = v;
133 |
134 | return this;
135 | }
136 |
137 | /**
138 | * set the name of the database.
139 | * this is optional if you are using {@link #addTable(Class)}, which forces the usage of
140 | * {@link com.hendrix.triorm.annotations.TriTable} annotations.
141 | *
142 | * @see TriDatabase.Builder
143 | */
144 | public Builder name(String name) {
145 | _dbName = name;
146 |
147 | return this;
148 | }
149 |
150 | /**
151 | * add a table to the database if it was not already added in the past
152 | *
153 | * @param tableName the table name
154 | * @param type the Class type of the object to store, must implement {@link java.io.Serializable}
155 | * @param the Class type of the object to store, must implement {@link java.io.Serializable}
156 | *
157 | * @see TriDatabase
158 | * @see TriTable
159 | * @see java.io.Serializable
160 | * @see TriDatabase.Builder
161 | *
162 | * @deprecated not really deprecated, but I advocate using {@link #addTable(Class)} with {@link com.hendrix.triorm.annotations.TriTable} class annotations.
163 | */
164 | public Builder addTable(String tableName, Class type)
165 | {
166 | if(_mapTables.containsKey(tableName))
167 | return this;
168 |
169 | String uniqueClassName = type.getName();
170 |
171 | TriTable triTable = new TriTable<>(_ctx, _dbName, tableName, _version);
172 |
173 | _mapTables.put(uniqueClassName, triTable);
174 |
175 | return this;
176 | }
177 |
178 | /**
179 | * add a table to the database if it was not already added in the past using {@link com.hendrix.triorm.annotations.TriTable}
180 | * annotation.
181 | *
182 | * @param type the Class type of the object to store, must implement {@link java.io.Serializable}
183 | * @param the Class type of the object to store, must implement {@link java.io.Serializable}
184 | *
185 | * @see TriDatabase
186 | * @see TriTable
187 | * @see java.io.Serializable
188 | * @see TriDatabase.Builder
189 | *
190 | * @throws java.lang.RuntimeException if meta database name is different from current database name
191 | */
192 | public Builder addTable(Class type)
193 | {
194 | SReflection.Meta meta = SReflection.extractMetadata(type);
195 |
196 | // guaranteed uniqueness because of packages
197 | String uniqueClassName = type.getName();
198 |
199 | if(_mapTables.containsKey(uniqueClassName))
200 | return this;
201 |
202 | validateDataBaseName(meta);
203 |
204 | TriTable triTable = new TriTable<>(_ctx, meta.getDbName(), meta.getTableName(), _version);
205 |
206 | _mapTables.put(uniqueClassName, triTable);
207 |
208 | return this;
209 | }
210 |
211 | /**
212 | * sets and validate the name of the database
213 | *
214 | * @param meta the {@link com.hendrix.triorm.utils.SReflection.Meta} of the table
215 | *
216 | * @throws java.lang.RuntimeException if meta database name is different from current database name
217 | */
218 | private void validateDataBaseName(Meta meta) {
219 | if(_dbName == null) {
220 | _dbName = meta.getDbName();
221 | return;
222 | }
223 |
224 | if(!_dbName.equals(meta.getDbName()))
225 | throw new RuntimeException("Table name " + meta.getDbName() + " is not consistent with current name " + _dbName + "caused by the following class" + meta.getTableType().getName());
226 | }
227 |
228 | }
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/Android-TriOrm.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/main/java/com/hendrix/triorm/query/TriQuery.java:
--------------------------------------------------------------------------------
1 | package com.hendrix.triorm.query;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteDatabase;
5 |
6 | import com.hendrix.triorm.TriData;
7 | import com.hendrix.triorm.TriTable;
8 | import com.hendrix.triorm.TriTable.Columns;
9 | import com.hendrix.triorm.utils.SSerialize;
10 |
11 | import java.util.ArrayList;
12 |
13 | /**
14 | * a {@code SQL} query builder according to the identifier, type, time_created fields of {@link com.hendrix.triorm.TriTable.Columns}
15 | *
16 | * @param the data type
17 | *
18 | * @author Tomer Shalev
19 | */
20 | @SuppressWarnings("UnusedDeclaration")
21 | public class TriQuery {
22 |
23 | private String _rawQueryString = null;
24 | private TriTable _ssd = null;
25 | /**
26 | * limit
27 | */
28 | private int _limit = Integer.MAX_VALUE;
29 | /**
30 | * order by column
31 | */
32 | private Columns _by = null;
33 | /**
34 | * order of results
35 | */
36 | private ORDER _order = ORDER.NONE;
37 |
38 | /**
39 | * enum for describing order {@code {DESC, ASC, NONE}}
40 | */
41 | public enum ORDER{DESC, ASC, NONE}
42 |
43 | private TriQuery(Builder builder) {
44 | update(builder);
45 | }
46 |
47 | /**
48 | * update a recycled builder
49 | *
50 | * @param builder the builder that was recycled
51 | */
52 | private void update(Builder builder) {
53 | _rawQueryString = builder._rawQueryString;
54 | _ssd = builder._ssd;
55 | _limit = builder._limit;
56 | _by = builder._by;
57 | _order = builder._order;
58 | }
59 |
60 | /**
61 | * perform the query
62 | *
63 | * @return {@link java.util.ArrayList} of data
64 | */
65 | @SuppressWarnings("unchecked")
66 | public ArrayList query()
67 | {
68 | SQLiteDatabase db = _ssd.getReadableDatabase();
69 |
70 | ArrayList listData = new ArrayList<>();
71 |
72 | String orderBy = null;
73 |
74 | if(_order != ORDER.NONE && _by!=null) {
75 | orderBy = _by.key() + " " + _order.name();
76 | }
77 |
78 | String limit = (_limit==Integer.MAX_VALUE) ? null : String.valueOf(_limit);
79 |
80 | Cursor cursor = db.query(_ssd.TABLE_NAME(), new String[] {Columns.KEY_DATA.key() }, _rawQueryString, null, null, null, orderBy, limit);
81 |
82 | int a = cursor.getCount();
83 |
84 | if(cursor==null || (cursor.getCount()==0))
85 | return listData;
86 |
87 | if (cursor.moveToFirst()) {
88 | do {
89 | // String data = cursor.getString(0); *****
90 | byte[] data = cursor.getBlob(0);
91 |
92 | Object dd = SSerialize.deserialize(data);
93 |
94 | listData.add((T) SSerialize.deserialize(data));
95 | } while (cursor.moveToNext());
96 | }
97 |
98 | //cursor.close();
99 |
100 | return listData;
101 | }
102 |
103 | /**
104 | * the builder of the query
105 | *
106 | * @param the data type
107 | *
108 | * @see com.hendrix.triorm.query.TriQuery
109 | *
110 | * @author Tomer Shalev
111 | */
112 | public static class Builder {
113 |
114 | /**
115 | * recycle the TriQuery object?
116 | */
117 | public boolean flagCacheQuery = false;
118 |
119 | private String _idFrom = null;
120 | private String _idTo = null;
121 | private String _type = null;
122 | private String _rawQueryString = null;
123 | private long _time_created_from = -1L;
124 | private long _time_created_to = -1L;
125 |
126 | /**
127 | * order by column
128 | */
129 | private Columns _by = null;
130 | /**
131 | * order of results
132 | */
133 | private ORDER _order = ORDER.NONE;
134 | /**
135 | * limit of results
136 | */
137 | private int _limit = Integer.MAX_VALUE;
138 |
139 | /**
140 | * the table on which to perform the query
141 | */
142 | private TriTable _ssd = null;
143 | /**
144 | * the cached query
145 | *
146 | * @see #flagCacheQuery
147 | */
148 | private TriQuery _cachedQuery = null;
149 |
150 | /**
151 | * @param ssd the table on which to perform the query
152 | */
153 | public Builder(TriTable ssd) {
154 | _ssd = ssd;
155 | }
156 |
157 | /**
158 | * build the query
159 | *
160 | * @return a {@link com.hendrix.triorm.query.TriQuery} instance
161 | */
162 | public TriQuery build(){
163 | buildString();
164 | //reset();
165 |
166 | TriQuery query = (flagCacheQuery) ? (_cachedQuery==null ? _cachedQuery=new TriQuery<>(this) : _cachedQuery) : new TriQuery(this);
167 |
168 | if(flagCacheQuery)
169 | query.update(this);
170 |
171 | return query;
172 | }
173 |
174 | /**
175 | * build the {@code SQL} query string
176 | *
177 | * @return the {@code SQL} string
178 | */
179 | public String buildString()
180 | {
181 | String id_selection, type_selection, created_selection, query = "";
182 | boolean isFirst = true;
183 |
184 | if(_idFrom!=null && _idTo!=null) {
185 | id_selection = "(" + Columns.KEY_ID.key() + " BETWEEN '" + _idFrom + "' AND '" + _idTo + "')";
186 | query = id_selection;
187 | isFirst = false;
188 | }
189 |
190 | if(_type!=null) {
191 | type_selection = "(" + Columns.KEY_TYPE.key() + " = '" + _type + "')";
192 | query = (!isFirst) ? query + " AND " + type_selection : type_selection;
193 | isFirst = false;
194 | }
195 |
196 | if(_time_created_from>=0 && _time_created_to>=0) {
197 | created_selection = "(" + Columns.KEY_CREATED.key() + " BETWEEN '" + Long.toString(_time_created_from) + "' AND '" + Long.toString(_time_created_to) + "')";
198 | query = (!isFirst) ? query + " AND " + created_selection : created_selection;
199 | isFirst = false;
200 | }
201 |
202 | if(isFirst) {
203 | // query=null will force SELECT *.. ->from the android api
204 | query = null;
205 | }
206 |
207 | return (_rawQueryString = query);
208 | }
209 |
210 | /**
211 | * @return a printable representation of the {@code SQL} query {@code SELECTION} string
212 | */
213 | @Override
214 | public String toString() {
215 | return _rawQueryString;
216 | }
217 |
218 | /**
219 | * reset the builder for recycling purposes. always user reset if.
220 | *
221 | * @return the reset recycled builder
222 | *
223 | * @see com.hendrix.triorm.query.TriQuery.Builder
224 | */
225 | public Builder reset() {
226 | _idFrom = null;
227 | _idTo = null;
228 | _type = null;
229 | _rawQueryString = null;
230 | _by = null;
231 | _order = ORDER.NONE;
232 | _limit = Integer.MAX_VALUE;
233 | _time_created_from = -1L;
234 | _time_created_to = -1L;
235 |
236 | return this;
237 | }
238 |
239 | /**
240 | * set starting id for query
241 | *
242 | * @param from the starting identifier
243 | *
244 | * @return the Builder
245 | *
246 | * @see com.hendrix.triorm.query.TriQuery.Builder
247 | */
248 | public Builder idFrom(String from) {
249 | _idFrom = from;
250 |
251 | return this;
252 | }
253 |
254 | /**
255 | * set destination id for query
256 | *
257 | * @param to the destination identifier
258 | *
259 | * @return the Builder
260 | *
261 | * @see com.hendrix.triorm.query.TriQuery.Builder
262 | */
263 | public Builder idTo(String to) {
264 | _idTo = to;
265 |
266 | return this;
267 | }
268 |
269 | /**
270 | * set the type for query
271 | *
272 | * @param type the type
273 | *
274 | * @return the Builder
275 | *
276 | * @see com.hendrix.triorm.query.TriQuery.Builder
277 | */
278 | public Builder type(String type) {
279 | _type = type;
280 |
281 | return this;
282 | }
283 |
284 | /**
285 | * set the starting creation time for query
286 | *
287 | * @param from the starting creation time
288 | *
289 | * @return the Builder
290 | *
291 | * @see com.hendrix.triorm.query.TriQuery.Builder
292 | */
293 | public Builder timeCreatedFrom(long from) {
294 | _time_created_from = from;
295 |
296 | return this;
297 | }
298 |
299 | /**
300 | * set the destination creation time for query
301 | *
302 | * @param to the destination creation time
303 | *
304 | * @return the Builder
305 | *
306 | * @see com.hendrix.triorm.query.TriQuery.Builder
307 | */
308 | public Builder timeCreatedTo(long to) {
309 | _time_created_to = to;
310 |
311 | return this;
312 | }
313 |
314 | /**
315 | * set the order for query
316 | *
317 | * @param by order by which column
318 | * @param order the order
319 | *
320 | * @return the Builder
321 | *
322 | * @see com.hendrix.triorm.query.TriQuery.Builder
323 | */
324 | public Builder ORDER(Columns by, ORDER order)
325 | {
326 | _by = by;
327 | _order = order;
328 |
329 | return this;
330 | }
331 |
332 | /**
333 | * set the limit of the query result
334 | *
335 | * @param limit the limit of the query
336 | *
337 | * @return the Builder
338 | *
339 | * @see com.hendrix.triorm.query.TriQuery.Builder
340 | */
341 | public Builder LIMIT(int limit)
342 | {
343 | _limit = limit;
344 |
345 | return this;
346 | }
347 |
348 | }
349 |
350 | }
351 |
--------------------------------------------------------------------------------
/src/main/java/com/hendrix/triorm/TriTable.java:
--------------------------------------------------------------------------------
1 | package com.hendrix.triorm;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 |
9 | import com.hendrix.triorm.query.TriQuery;
10 | import com.hendrix.triorm.query.TriQuery.ORDER;
11 | import com.hendrix.triorm.utils.SSerialize;
12 |
13 | import java.util.ArrayList;
14 |
15 | /**
16 | * simple 3D SQL table carrier with {@code (id, type, data, time_created)} rows, that serializes/deserialize to/from database.
17 | *
18 | *
use {@link #addData(TriData)}, {@link #addDataWithConflict(TriData, int)} to add data.
19 | *
use {@link #getData(String)} to get a single data by identifier.
20 | *
use {@link #delete(String)}, {@link #delete(TriData)} to delete data.
21 | *
use {@link #getQueryBuilder()} to get the query builder.
22 | *
there are also other query methods, but all are based on {@link #getQueryBuilder()}.
23 | *
24 | *
25 | * Notes:
26 | *
27 | * the recommended way to access a table is with {@link TriOrm} object.
28 | *
29 | *
use {@link TriOrm#query(Class)} to get {@link #getQueryBuilder()} of a table.
30 | *
use {@link TriOrm#load(Class, String)} to get a single Data of a table by identifier.
31 | *
use {@link TriOrm#table(Class)} to get {@link com.hendrix.triorm.TriTable} reference of the class type.
32 | *
33 | *
34 | * @param the Class type of the object to store, must implement {@link com.hendrix.triorm.TriData}
35 | *
36 | * @author Tomer Shalev
37 | */
38 | @SuppressWarnings("UnusedDeclaration")
39 | public class TriTable extends SQLiteOpenHelper
40 | {
41 | private TriQuery.Builder _queryBuilder = null;
42 |
43 | // Database Version
44 | protected int DATABASE_VERSION = 1;
45 |
46 | // Database Name
47 | protected String DATABASE_NAME;
48 |
49 | // Table name
50 | protected String TABLE_NAME;
51 |
52 | /**
53 | * get the query builder
54 | *
55 | * @return the {@link TriQuery.Builder} reference
56 | */
57 | synchronized public TriQuery.Builder getQueryBuilder() {
58 | return _queryBuilder.reset();
59 | }
60 |
61 | /**
62 | * get the database name
63 | *
64 | * @return the database name
65 | */
66 | public String DATABASE_NAME() {
67 | return DATABASE_NAME;
68 | }
69 |
70 | /**
71 | * get the table name
72 | *
73 | * @return the table name
74 | */
75 | public String TABLE_NAME() {
76 | return TABLE_NAME;
77 | }
78 |
79 | /**
80 | * enum describing the columns of the table
81 | *
82 | * {@code {KEY_ID, KEY_TYPE, KEY_DATA, KEY_CREATED}}
83 | */
84 | public enum Columns {
85 | KEY_ID("id", 0), KEY_TYPE("type", 1), KEY_DATA("data", 2), KEY_CREATED("time_created", 3);
86 |
87 | private Columns(String key, int index) {
88 | _index = index;
89 | _key = key;
90 | }
91 |
92 | private int _index;
93 | private String _key;
94 |
95 | public int index() {
96 | return _index;
97 | }
98 |
99 | public String key() {
100 | return _key;
101 | }
102 | }
103 |
104 | /**
105 | * A new table
106 | *
107 | * @param context Android's context
108 | * @param databaseName name of the database to be created or loaded
109 | * @param tableName the name of the table to be loaded
110 | * @param version version number
111 | */
112 | public TriTable(Context context, String databaseName, String tableName, int version)
113 | {
114 | super(context, databaseName, null, version);
115 |
116 | DATABASE_VERSION = version;
117 |
118 | DATABASE_NAME = databaseName;
119 | TABLE_NAME = tableName;
120 |
121 | onCreate(getWritableDatabase());
122 | }
123 |
124 | @Override
125 | public void onCreate(SQLiteDatabase db)
126 | {
127 | String CREATE_TABLE_COMMAND = "CREATE TABLE IF NOT EXISTS "
128 | + TABLE_NAME + "("
129 | + Columns.KEY_ID.key() + " TEXT PRIMARY KEY, "
130 | + Columns.KEY_TYPE.key() + " STRING, "
131 | //+ Columns.KEY_DATA.key() + " TEXT, "
132 | + Columns.KEY_DATA.key() + " BLOB, "
133 | + Columns.KEY_CREATED.key() + " INTEGER" + ")";
134 |
135 | db.execSQL(CREATE_TABLE_COMMAND);
136 |
137 | _queryBuilder = new TriQuery.Builder<>(this);
138 | _queryBuilder.flagCacheQuery = true;
139 | }
140 |
141 | @Override
142 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
143 | {
144 | // Drop older table if existed
145 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
146 |
147 | // Create tables again
148 | onCreate(db);
149 | }
150 |
151 | /**
152 | * add/replace new/older data, or update an older one with the correct conflict algorithm
153 | *
154 | * @param data the data
155 | */
156 | public void addData(T data)
157 | {
158 | addDataWithConflict(data, SQLiteDatabase.CONFLICT_REPLACE);
159 | }
160 |
161 | /**
162 | * add new data, or update an older one with the correct conflict algorithm
163 | *
164 | * @param data the data
165 | * @param conflictAlgorithm for example SQLiteDatabase.CONFLICT_REPLACE
166 | *
167 | */
168 | public void addDataWithConflict(T data, int conflictAlgorithm)
169 | {
170 | SQLiteDatabase db = this.getWritableDatabase();
171 |
172 | ContentValues values = new ContentValues();
173 |
174 | values.put(Columns.KEY_ID.key(), data.getId());
175 | values.put(Columns.KEY_TYPE.key(), data.getType());
176 | //values.put(Columns.KEY_DATA.key(), SSerialize.serialize(data));
177 | values.put(Columns.KEY_DATA.key(), SSerialize.serializeToByteArray(data));
178 | values.put(Columns.KEY_CREATED.key(), data.getTimeCreated());
179 |
180 | if(data.getId() == null)
181 | throw new NullPointerException("data.getId() = null");
182 |
183 | // Inserting Row
184 | db.insertWithOnConflict(TABLE_NAME, null, values, conflictAlgorithm);
185 | db.close();
186 | }
187 |
188 | /**
189 | * general get data
190 | *
191 | * @return {@link ArrayList} of data
192 | */
193 | synchronized public ArrayList getData( String idFrom, String idTo,
194 | String type, long createdFrom, long createdTo)
195 | {
196 | return _queryBuilder.reset().idFrom(idFrom).idTo(idTo).type(type).timeCreatedFrom(createdFrom).timeCreatedTo(createdTo).ORDER(Columns.KEY_CREATED, ORDER.DESC).build().query();
197 | }
198 |
199 | /**
200 | * Select data by it's identifier
201 | *
202 | * @param id the id of the data
203 | * @return the data
204 | */
205 | public T getData(String id)
206 | {
207 | SQLiteDatabase db = this.getReadableDatabase();
208 |
209 | Cursor cursor = db.query(TABLE_NAME, new String[] { Columns.KEY_DATA.key() }, Columns.KEY_ID.key() + "=?", new String[] { String.valueOf(id) }, null, null, null, null);
210 |
211 | if(cursor==null || (cursor.getCount()==0))
212 | return null;
213 |
214 | cursor.moveToFirst();
215 |
216 | //T res = SSerialize.deserialize(cursor.getString(0)); ******
217 | T res = SSerialize.deserialize(cursor.getBlob(0));
218 |
219 | cursor.close();
220 |
221 | return res;
222 | }
223 |
224 | /**
225 | * Select data set by it's type
226 | *
227 | * @param type the type of the data
228 | *
229 | * @return {@link ArrayList} of data
230 | */
231 | public ArrayList getDataByType(String type)
232 | {
233 | return _queryBuilder.reset().type(type).build().query();
234 | }
235 |
236 | /**
237 | * Select data from a window of identifiers. useful when ids are timestamps.
238 | * requires QA.
239 | *
240 | * @param idFrom starting id
241 | * @param idTo last id
242 | *
243 | * @return {@link ArrayList} of data
244 | */
245 | public ArrayList getDataBetweenId(String idFrom, String idTo)
246 | {
247 | return _queryBuilder.reset().idFrom(idFrom).idTo(idTo).build().query();
248 | }
249 |
250 | /**
251 | * Select data from a window of time_created with projected type requires QA.
252 | *
253 | * @param date_from time_created start
254 | * @param date_to time_created end
255 | * @param type the type
256 | *
257 | * @return {@link ArrayList} of data
258 | */
259 | public ArrayList getDataBetweenDateWithType(long date_from, long date_to, String type)
260 | {
261 | return _queryBuilder.reset().timeCreatedFrom(date_from).timeCreatedTo(date_to).type(type).ORDER(Columns.KEY_CREATED, ORDER.DESC).build().query();
262 | }
263 |
264 | /**
265 | * Select data from a window of time_created with projected type requires QA.
266 | *
267 | * @param date_from time_created start
268 | * @param date_to time_created end
269 | *
270 | * @return {@link ArrayList} of data
271 | */
272 | public ArrayList getDataBetweenDate(long date_from, long date_to)
273 | {
274 | return _queryBuilder.reset().timeCreatedFrom(date_from).timeCreatedTo(date_to).ORDER(Columns.KEY_CREATED, ORDER.DESC).build().query();
275 | }
276 |
277 | /**
278 | * Select data from a window of identifiers with casted type. useful when ids are timestamps.
279 | *
280 | * @param idFrom starting id
281 | * @param idTo last id
282 | * @param type the type
283 | *
284 | * @return {@link ArrayList} of data
285 | */
286 | public ArrayList getDataBetweenIdWithType(String idFrom, String idTo, String type)
287 | {
288 | return _queryBuilder.reset().idFrom(idFrom).idTo(idTo).type(type).build().query();
289 | }
290 |
291 | /**
292 | * Select latest data with limit
293 | *
294 | * @param limit the max amount of latest objects
295 | *
296 | * @return {@link ArrayList} of data
297 | */
298 | public ArrayList getAllData(int limit)
299 | {
300 | return _queryBuilder.reset().ORDER(Columns.KEY_ID, ORDER.DESC).LIMIT(limit).build().query();
301 | }
302 |
303 | /**
304 | * update an already existing data by identifier
305 | *
306 | * @param id the id of the data
307 | * @param data the updated data
308 | *
309 | * @return the number of rows affected
310 | */
311 | public int updateData(String id, T data)
312 | {
313 | SQLiteDatabase db = this.getWritableDatabase();
314 |
315 | ContentValues values = new ContentValues();
316 |
317 | values.put(Columns.KEY_ID.key(), data.getId());
318 | values.put(Columns.KEY_TYPE.key(), data.getType());
319 | values.put(Columns.KEY_DATA.key(), SSerialize.serializeToByteArray(data));
320 | values.put(Columns.KEY_CREATED.key(), data.getTimeCreated());
321 |
322 | // updating row
323 | return db.update(TABLE_NAME, values, Columns.KEY_ID.key() + " = ?", new String[] { id });
324 | }
325 |
326 | /**
327 | * delete data by identifier
328 | *
329 | * @param id the id of the data
330 | */
331 | public void delete(String id)
332 | {
333 | SQLiteDatabase db = this.getWritableDatabase();
334 |
335 | db.delete(TABLE_NAME, Columns.KEY_ID.key() + " = ?", new String[] { id });
336 | db.close();
337 | }
338 |
339 | /**
340 | * delete data by identifier
341 | *
342 | * @param data the data of the data
343 | */
344 | public void delete(T data)
345 | {
346 | delete(data.getId());
347 | }
348 |
349 | /**
350 | * delete all of the data
351 | */
352 | public void deleteAllData()
353 | {
354 | SQLiteDatabase db = this.getWritableDatabase();
355 |
356 | db.delete(TABLE_NAME, null, null);
357 | db.close();
358 | }
359 |
360 | /**
361 | * grab the amount of rows
362 | *
363 | * @return the count
364 | */
365 | public int getDataCount()
366 | {
367 | String countQuery = "SELECT * FROM " + TABLE_NAME;
368 | SQLiteDatabase db = this.getReadableDatabase();
369 | Cursor cursor = db.rawQuery(countQuery, null);
370 |
371 | int result = cursor.getCount();
372 |
373 | cursor.close();
374 |
375 | // return count
376 | return result;
377 | }
378 |
379 | }
--------------------------------------------------------------------------------