I apologize for sending another message to this thread. Our primary motivation for limiting access to the Structure API immediately is straightforward: changing a public API is a major undertaking. By limiting it now, we will force ourselves to design a universal, Turing-complete API from the ground up that supports both embedded and remote deployments.
This approach will enable our users to start with a small embedded database and scale up to a large cloud cluster without requiring significant application refactoring. Best regards, Andrii Lomakin On Mon, Nov 24, 2025 at 1:55 PM Andrii Lomakin <[email protected]> wrote: > Just to clarify, that is part of our GraphTraversalDSL > https://github.com/JetBrains/youtrackdb/blob/develop/core/src/main/java/com/jetbrains/youtrackdb/api/gremlin/YTDBGraphTraversalSourceDSL.java#L49 > . > > >I think this idea begs to be explored > > We will start experimenting with it then. We have thought about it for a > long time, so you can base your changes on what we have made. > > On Mon, Nov 24, 2025 at 1:51 PM Andrii Lomakin < > [email protected]> wrote: > >> Hi Stephen. >> Thank you for the feedback. Regarding transactions, after I wrote the >> letter, I am inclined to think that the approach using GraphTraversal that >> we currently use is closer to what I want to see in the TinkerPop process >> API than the steps designed to control TXs. >> >> BTW, we use the autoExecute approach a lot :-) >> >> /// Start a new transaction if it is not yet started and executes >>> passed in code in it. >>> /// >>> /// If a transaction is already started, executes passed in code in >>> it. In case of exception, >>> /// rolls back the transaction and commits the changes if the >>> transaction was started by this >>> /// method. >>> public <X extends Exception> void executeInTx( >>> @Nonnull FailableConsumer<YTDBGraphTraversalSource, X> code) >>> throws X { >>> var tx = tx(); >>> YTDBTransaction.executeInTX(code, (YTDBTransaction) tx); >>> } >> >> >> /// Start a new transaction if it is not yet started and executes >>> passed in code in it. >>> /// >>> /// If a transaction is already started, executes passed in code in >>> it. In case of exception, >>> /// rolls back the transaction and commits the changes if the >>> transaction was started by this >>> /// method. >>> /// >>> /// Unlike {@link #executeInTx(FailableConsumer)} also iterates over >>> the returned >>> /// [YTDBGraphTraversal] triggering its execution. >>> public <X extends Exception> void autoExecuteInTx( >>> @Nonnull FailableFunction<YTDBGraphTraversalSource, >>> YTDBGraphTraversal<?, ?>, X> code) >>> throws X { >>> var tx = tx(); >>> YTDBTransaction.executeInTX(code, (YTDBTransaction) tx); >>> } >> >> >> /// Start a new transaction if it is not yet started and executes >>> passed in code in it and then >>> /// returns the result of the code execution. >>> /// >>> /// If a transaction is already started, executes passed in code in >>> it. In case of exception, >>> /// rolls back the transaction and commits the changes if the >>> transaction was started by this >>> /// method. >>> public <X extends Exception, R> R computeInTx( >>> @Nonnull FailableFunction<YTDBGraphTraversalSource, R, X> code) >>> throws X { >>> var tx = tx(); >>> return YTDBTransaction.computeInTx(code, (YTDBTransaction) tx); >>> } >> >> >> On Mon, Nov 24, 2025 at 1:44 PM Stephen Mallette <[email protected]> >> wrote: >> >>> Generally speaking, I think this idea begs to be explored but I also >>> think >>> that it's a change of extraordinary size that will need a lot of thought >>> and planning to be sure it is done properly. I think initial efforts with >>> that plan are already underway with 3.8.0 where it introduced the notion >>> of >>> StepContract interfaces and "step placeholders" which should allow >>> providers to more easily provide their own implementations. In this way, >>> a >>> provider would be implementing at a Gremlin level rather than at that >>> Structure API level. So, that's a starting point to allow for any of this >>> to happen. I don't recall past discussions about what happens to Element >>> interfaces, but I sense they would end up being read-only as you >>> described. >>> I suppose they would stay interfaces and there would be a few concrete >>> TinkerPop implementations that we'd offer for providers to convert to >>> when >>> implementing steps. Remote providers might skip all that together and >>> just >>> write directly to GraphSON or GraphBinary. >>> >>> I don't know if transactions should explicitly be implemented as a >>> traditional Step or not. They don't behave like steps in my mind, in >>> that I >>> don't see how they chain. Maybe it's more like a terminal step or a >>> special step series like io().read()/write(). I think the first work to >>> be >>> taken around this big topic is to try to build consensus for what >>> transactions look like, both as a part of the Gremlin language and the >>> HTTP >>> API. I know Ken has been thinking about the Transaction API for 4.x, but >>> no >>> formal proposal has been raised yet that I can recall. >>> >>> I will add that while I feel the Transaction API is a must-have for 4.x, >>> I'm not sure that I see removal of the Graph API as a critical item for >>> that version. If there was consensus on a plan to do so, I think it would >>> be best for that to fall into a later body of work where perhaps the >>> deprecation for the Graph API is in 4.x with removal in 5.x. >>> >>> On Sat, Nov 22, 2025 at 8:49 AM Andrii Lomakin via dev < >>> [email protected]> wrote: >>> >>> > Dear like-minded colleagues, >>> > >>> > Sorry for the stream of ideas, but I wanted to share my thoughts on API >>> > dual support. >>> > >>> > I believe the dual support of two API types—structured and process—is >>> > counterproductive because it prevents the creation of truly >>> > platform-independent distributions. >>> > When an application development team begins to rely on the structured >>> API, >>> > they become limited to a minimal number of vendors who support embedded >>> > deployments. >>> > >>> > Furthermore, I agree with Stephen Mallette that it is more >>> straightforward >>> > and more idiomatic for a provider to implement a few basic steps that >>> > operate on database records than to implement the more demanding >>> interface >>> > of a Graph instance. >>> > >>> > In practice, this suggests the following changes: >>> > >>> > 1. Remove the Graph interface as a public API. >>> > 2. Make the Element, Vertex, and Edge concepts read-only. >>> > 3. Add steps to control transactions uniformly at the GraphTraversal >>> level >>> > to unify management. >>> > >>> > Regarding transaction management, the current implementation appears >>> to be >>> > an ununified side feature, especially considering the disparate >>> lifecycles >>> > between embedded and remote deployments. Introducing steps that >>> control the >>> > transaction lifecycle would resolve this issue. >>> > >>> > What do you think about these points? >>> > We will consider implementing those items on our side in the short >>> term. >>> > >>> > Best regards, >>> > Andrii Lomakin >>> > YouTrackDB development lead. >>> > >>> >>
