Hello all,

I'm using `session.merge()` within an HTTP handler, I would like to know 
which objects have been newly added and which ones have been modified after 
`merge()` completes. 

Bare with me please ...

I know there are `before_flush`, etc. events exactly for this scenario but 
I **only** need to know within the context of my HTTP request handler. I am 
already using whole application-server `before_flush`, `before_commit`, 
etc for other purposes.

*Here is my use-case scenario:*

Consider an object graph that represents folder with sub-folders and files 
(of any depth). For example:

```
/
# root folder

/folder1/file1
# file1 within folder1; folder1 within root

/folder1/folder2/file2
# file2 within folder2; folder2 within folder1; folder1 within root
```

My sqlalchemy model looks like this:

```
class Folder(Base):
...
id = Column(... primary key)
folder_id = Column(... foreign key to parent folder id)
folder = relationship(...

class File(Base):
...
id = Column(... primary key)
folder_id = Column(... foreign key to parent folder id)
folder = relationship(...
```

The HTTP client would like to do a **single** POST containing the new 
directory structure with folders and subfolders rearranged containing any 
combination of existing files, existing folders, and to-be created new 
folders and subfolders. All in a single HTTP POST.

*My current solution is like this:*

Within my HTTP request handler, the POST payload is validated and newly 
detached sqlalchemy instances are created (I'm using pyramid, cornice and 
marshmallow). 

I use `session.merge()` to automatically "create" and/or "update" my object 
graph in one shot. Even if this payload object graph contains any 
combination of persisted objects and new objects.

For instance, HTTP client wants the following changes ...

/folder3/folder4/folder1/file1
/folder3/folder4/folder1/folder2/file2

... to be applied over ...

/folder1/file1
/folder1/folder2/file2

IOW: client wants to create a new folder3 (containing a new subfolder 
folder4); putting folder3 in root; and moving folder1 into folder4 - all in 
one shot:

In code, something like this would be happening within marshmallow:

```
folder3 = Folder()
folder4 = Folder()
folder3.append(folder4)
folder4.folders.append(folder1)
```

In my HTTP handler, I'm doing this:

```
folder3 = request.validated['folder']
session.merge(folder3)
```

All this works just fine :)
New folders are created and existing folders and existing files are 
shuffled around correctly.

*However*, after the `merge()`, folder3 and folder4 appear in 
`session.dirty` while `session.new` is empty. Also folder1 appears in 
`session.dirty`. I.e. `session.dirty` has both newly inserted and modified 
instances. 

I need to know that folder3 and folder4 were newly added so I can tell the 
client "newly added folders: folder3, folder4" - client doesn't care about 
"updated" folders and/or files, just cares about new folders.

So, looking at `session.new` and `session.dirty` doesn't help me 
identifying which objects were newly inserted and which ones were updated.

*How can I know if folder3 was newly added (or any descendant) without 
having to query the DB for every object in the POSTed object graph before 
passing all down to `session.merge()`?*

I was considering that I could `@event.listens_for('init'...)` within the 
context of the HTTP request (perhaps `before_flush`)  but there is a 
"dragon warning" (https://docs.sqlalchemy.org/en/latest/core/event.html) 
about adding/removing events in "high velocity" which sounds like I would 
be doing here?


*Any suggestions?*


Perhaps I'm doing this all wrong to start with ... As my last resort, I 
could just simplify my API and incrementally build the directory structure 
step by step like a normal "filesystem":

folder1 = mkdir('folder1', root)
put_file(file1, folder1)
folder2 mkdir('folder2', folder1)
put_file(file2, folder1)

The disadvantage would be that client would need to sequentially send each 
HTTP request one by one in the correct order. Which is the opposite of the 
desired use-case scenario.



-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to