[odb-users] How to make a "lazy" QList?

Rene Jensen rene at catatonic.dk
Tue Nov 6 13:30:32 EST 2012


Hi Boris

On Mon, Nov 5, 2012 at 1:43 PM, Boris Kolpackov <boris at codesynthesis.com>wrote:

> Hi Rene,
>
> Presented like that, I see that the problem also touches on a the lack of
> a
> > standard "signal-emitting" Qt collection or similar in std: Something
> that
> > would react when you inserted or removed a single element.
>
> Well, that would be only half of the problem. The other half is the
> modification of the element value in place. Consider:
>
> std::vector<int> v = ...
>
> int& x = v[0]; // Vector has no idea whether we will modify x or not.
>
> x++;
>
> So a solution would be a custom, change-tracking container (with QList
> of std::vector-like interface) that is provided by ODB. Such a container
> would (a) track element insertions/deletions and translate them to the
> corresponding minimum set of INSERT/ERASE statements on update and (b)
> not allow (or at least restrict) in-place element modifications so that
> it can keep track of these as well. In other words:
>
> odb::vector<int> v = ...
>
> if (v[0] == 0) {...} // Ok, we have const operator[].
>
> int& x = v[0]; // Error; no non-const operator[].
>
> int& x = v.modify (0); // Get reference for modification.
> x++;
>
> v.replace (0, 123); // Replace value.
>
> I think it won't be too difficult to add odb::vector and odb::qt::QList
> with this functionality. We have pretty much all the infrastructure for
> this and all that is left is to implement that change tracking logic
> carefully. Maybe, we should also support lazy loading this way: it
> won't be as general-purpose as sections but it will definitely be
> more natural to use and much easier to implement.
>
> Would you consider using odb::qt::QList with change tracking support
> instead of QList?
>
> Boris
>

Hi Boris.
You raise a very good question. I had to give it some thought. Could we
split the matter in two?
1) Keeping the items
2) Adding, removing, modifying the items - "managing" them.

The former is currently handled by known collections - QList, std::vector
etc. The latter not at all currently.
I suppose we can agree on these two claims:
ad 1) Items should be stored in such a way that existing API's can make use
of them.
ad 2) If the user has direct access to a well-known QList, std::vector...
then there is no way to know what he has done, thus update means: REMOVE
ALL, INSERT ALL

Basically I see two ways of organizing the code:
Put (1) inside (2). In you suggestion it would mean having an
odb::qt::QList as the manager which internally manages a traditional QList.
For purposes of reading, the user would be able to gain access to the
stored QList.
Put (1) next to (2). Here it would mean something like

struct Test
{
  #pragma db transient
  QList<QString>  nameList;
  #pragma db manages (nameList)
  odb::collectionmanager<QList<QString> > nameManager;
}

Test t;

// Modify nameList through the manager only
t.nameManager.load_all();
t.nameManager.append ("Hello");
t.nameManager.update();

// Use t.nameList directly for read-only purposes
foreach (QString name, t.nameList) { qDebug() << name; }

... Your version might make just as much sense, if not more:



struct Test
{
  // Use a template specialization which internally uses QList<QString>...
  odb::collectionmanager<QList<QString> > names;
}
Test t;

// The manager for QList mimics QList here and there, just for convenience.
t.names.append ("World");

// Get read/write access to specific item
QString& S = t.names[10];
S.replace ("Hello", "Hi");

// Get read-access to the QList.
foreach (QString S, t.names.getList()) { qDebug() << S; }


As long as the user can A) control which underlying collection type is
used, and B) gain at least read-only access to that collection, then I will
certainly use it.

Best regards,
Rene Jensen


More information about the odb-users mailing list