On Fri, Jan 11, 2019 at 11:39 AM HP3 <[email protected]> wrote:
>
> 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.

as you tried, the easiest way is to look in session.new and
session.dirty after the fact.  if session.new is empty that means it
is autoflushing, so turn that off:


with session.no_autoflush:
    obj = session.merge(my_thing)
    for r in session.new:
        ....
    for r in session.dirty:
        ...

if that doesn't work there are ways to use the event hooks here.

>
> 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 [email protected].
> To post to this group, send email to [email protected].
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to