The Big Split -- SimpleOrm.records and SimpleOrm.database.

Anthony Berglas <[email protected]>
Newsgroups gmane.comp.java.orm.simpleorm
Message-ID <[email protected]>
Hello Franck,

I think that as part of 3.0 we should consider splitting SimpleOrm 
into two pieces, each in their own Jars.

simpleorm.records that contains SRecordMeta, SRecordInstance, SField*

simpleorm.database that contains SQuery, SDriver*, SConnection.

The record part should have zero dependency on the database part, and 
should be compiled and built into its own jar, with some test cases of its own.

The database part should depend on the records part, obviously.

When working detached, one should only need the .records jar.


This is actually not that hard to do.  I have already decoupled 
SQuery from SRecordMeta.  A similar trick can be used to decouple 
findOrCreate and friends.  And the only other substantial connection 
is where SReferenceField.getRawValue can do a lazy read.


For findOrCreate, the API becomes slightly messier:-

SFinder empf<Employee> = new SFinder(Employee.meta);
Employee e = empf.findOrCreate("123");

or simply but slightly less efficiently

Employee e = new SFinder(Employee.meta).findOrCreate("123");

(The finder would cache the sets of different types of fields etc.)

vs old

Employee e = Employee.meta.findOrCreate("123");


For the SFieldReference.get the call would become

SFinder deptf<Department> = new SFinder(Department.meta);
Department dept = deptf.getReference(myEmp, DEPT);(

(For the detached case, no query:-)
Department dept = myEmp.getUnqueriedReference(DEPT);


One could, of course, give SRecordMeta a default finder, defined 
through an interface in .SRecord, and then keep the existing 
API.  But being explicit makes the structure clear.



I have also attached some other prototyping that I was doing in 
SimpleData (it is checked in).  But I now think that splitting 
SimpleOrm is a much better idea, and SimpeData should be 
abandoned.  I think that this change is actually very good, and would 
lead naturally to DataSets if we wanted to go there later.

My current task is to work on the white paper etc.  I would not want 
to start any split until you have caught up with the current changes 
and your application works 100%.  (Although I might be tempted to do 
some of the internal rearrangement, moving code from SRecordMeta to SFinder.)

One way or the other I am hoping to make your branch the trunk this week.


What do you think?

Anthony



Dr Anthony Berglas, [email protected]       Mobile: +61 4 4838 8874
Just because it is possible to push twigs along the ground with ones nose
does not necessarily mean that is the best way to collect firewood.

------------------------------------

Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/SimpleORM/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/SimpleORM/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:[email protected] 
    mailto:[email protected]

<*> To unsubscribe from this group, send an email to:
    [email protected]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/
DBasicTest.java (text/plain, 6 KB)
package simpleorm.data.test;

import simpleorm.data.*;
import simpleorm.data.ddlutilsaddaptor.DDdlUtlisConnection;
import simpleorm.data.dynabeanadaptor.DDynaConnection;
import simpleorm.data.dynabeanadaptor.DDynaDatabase;

import java.util.Iterator;

import org.hsqldb.jdbc.jdbcDataSource;

/**
 * Basic sample and example of Data Interface.<p>
 *
 * Three providers: DdlUtilsConnection, DDynaCollection and custom MyConnection.
 * The latter also provides an example of writing a manual provider, should that be desired.
 */
public class DBasicTest {

    /** Could subtype DRecordInstance etc. if necessary. */
    static public class MyRecord  extends DRecordInstance {
        static public final DRecordMeta MY_RECORD = new DRecordMeta(MyRecord.class, "MY_RECORD");
        static final DFieldMeta ID = MY_RECORD.addField(new DFieldMeta("ID", DType.INTEGER))
                .setPrimaryKey(true);
        static final DFieldMeta NAME = MY_RECORD.addField(new DFieldMeta("NAME", DType.STRING));
        static final DFieldMeta DESCRIPTION = MY_RECORD.addField(new DFieldMeta("DESCRIPTION", DType.STRING));
        //static final DFieldMeta KEY = MY_RECORD.addField(new DFieldMeta("KEY", DType.BYTES));
        static final DFieldMeta UNQUERIED = MY_RECORD.addField(new DFieldMeta("UNQUERIED", DType.STRING));
        static final DFieldMeta PARENT = MY_RECORD.addField(new DFieldMeta("PARENT", DType.INTEGER));

        static final DForeignKeyMeta PARENT_FK = MY_RECORD.addRefingFKey(PARENT);

        String getName() {return getString(NAME);}  // get/seters optional and not recommended, just an example.

        public MyRecord() {super(MY_RECORD); }

        public @Override void onPreUpSert(DConnection connection, QueryMode mode) {
            System.err.println("onPreUpSert " + mode +  this);
        }

    }

   static class MySubRecord  extends MyRecord {
//        static final DRecordMeta MY_RECORD = new DRecordMeta("MY_RECORD");
//        static final DFieldMeta ID = MY_RECORD.addField(new DFieldMeta("ID", DType.INTEGER))
//                .setPrimaryKey(true);
//        static final DFieldMeta NAME = MY_RECORD.addField(new DFieldMeta("NAME", DType.STRING));
//        static final DFieldMeta KEY = MY_RECORD.addField(new DFieldMeta("KEY", DType.BYTES));
//
//        public MySubRecord() {
//            super(MY_RECORD);
//        }
    }

    public static void main(String[] args) throws Exception {

        //todo enable simple commons logging so that ddlutils error messages are displayed! (eg. no primary key).

        /// Example of manual bean, not normally used.
        testAdaptor(new MyConnection());

        /// Example of an automated dyna bean / hash map database
        testAdaptor(new DDynaConnection(new DDynaDatabase()));

        /// Main example using Ddl Utils.
        testAdaptor(newDdlUtilConnection());
    }

    private static DDdlUtlisConnection newDdlUtilConnection() {
        DDdlUtlisConnection dcon = new DDdlUtlisConnection();

        jdbcDataSource dataSource = new jdbcDataSource();
        dataSource.setUser("sa");
        dataSource.setDatabase("jdbc:hsqldb:file:testdb/ddlutils_hsqldb");

        dcon.addTableToSchema(MyRecord.MY_RECORD);
        dcon.setDataSource(dataSource);

        dcon.createModel();
        return dcon;
    }

    static void testAdaptor(DConnection connection) throws Exception {

        System.err.println("\n======================================= " + connection.getClass().getSimpleName());

        MyRecord rec1 = addRec(connection, 1, "Fred", "First");
        MyRecord rec2 = addRec(connection, 2, "Nerk", "Second");
        MyRecord rec3 = addRec(connection, 3, "Bert",  "Thrid");
        MyRecord rec4 = addRec(connection, 4, "Fred",  "Fourth");
        System.err.println("Record " + rec1);
        assertEquals("Fred", rec1.getObject(rec1.NAME));
        rec4.setObject(rec4.DESCRIPTION, "FourthX");
        connection.update(rec4);

        DQuery qry = new DQuery(MyRecord.MY_RECORD)
                .addSelect(rec1.ID).addSelect(rec1.NAME).addSelect(rec1.DESCRIPTION)
                .eq(rec1.NAME, "Fred").addOrderBy(rec1.NAME)
                .setOffset(0).setLockRecords(false);
//        assertEquals(qry.compare(rec1, rec3), 1); // > ## returns 4? 
//        assertEquals(qry.compare(rec3, rec4), -1); // <
        assertEquals(qry.compare(rec3, rec3), 0);
        assertEquals(!rec1.equals(rec2), true);
        assertEquals(rec1.hashCode() != rec2.hashCode(), true);

        Iterator recI = qry.execute(connection);
        MyRecord lrec = null;
        int count=0;
        while (recI.hasNext()) {
            lrec = (MyRecord)recI.next();
            System.err.println("Queried " + ++count + " :" + lrec.toLongString());
        }
        assertEquals(2, count);
        assertEquals(lrec, rec4);
        assertEquals(lrec == rec4, false);
        String descr4 = lrec.getString(lrec.DESCRIPTION);
        assertEquals(descr4, "FourthX");

        DQuery qry2 = new DQuery(MyRecord.MY_RECORD)
                .addSelect(rec1.ID).addSelect(rec1.NAME)
                .eq(rec1.ID, 2);
        MyRecord q2r2 = (MyRecord)qry2.executeOnlyRecord(connection);
        assertEquals(q2r2, rec2);

        MyRecord q3r3 = (MyRecord)new DQuery(MyRecord.MY_RECORD)
                .queryPrimaryKey(connection, 3);
        assertEquals(q3r3, rec3);

    }

    static MyRecord addRec(DConnection connection, int id, String name, String description) {
        MyRecord rec1 = (MyRecord)connection.newInstance(MyRecord.MY_RECORD); // ## MESSY
        rec1.setObject(rec1.ID, id);
        rec1.setObject(rec1.NAME, name);
        rec1.setObject(rec1.DESCRIPTION, description);
        rec1.setObject(rec1.UNQUERIED, "UnQueried" + id);
        connection.insert(rec1);
        return rec1;
    }


    static void assertEquals(Object expected, Object actual) {
        System.err.println("Asserting " + expected);
        if ( expected==null ? actual!=null : !expected.equals(actual) )
            throw new DException("assertEquals Failed " + expected + " != " + actual);
    }

}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.