diff --git a/documentation/blog/en/07-advanced-features-on-developers-portal.md b/documentation/blog/en/07-advanced-features-on-developers-portal.md index 986cb5956..b972ddfdd 100644 --- a/documentation/blog/en/07-advanced-features-on-developers-portal.md +++ b/documentation/blog/en/07-advanced-features-on-developers-portal.md @@ -101,15 +101,15 @@ different formats. At the same time, it does not make sense to display all forma be interested only in the variant he intends to use during integration. However, this posed a challenge due to various obstacles, such as page indexing and print support. -It all started with the `` component. I believe that from its name and markup, you can already +It all started with the `` component. I believe that from its name and markup, you can already understand the purpose of this component. ##### Markup ```md - + // content specific to Java and EvitaQL - + ``` Now, let's move on to the next step, which involves creating a user-friendly switch to allow users to easily switch @@ -171,7 +171,7 @@ parameter `?codelang={preferredLanguage}`. This will preserve the correct preset link to the clipboard and sends it to someone else. This person will then get the same page variant as the person who sent the link. -The component is now aware of preferred language. In case of `` component, show the actual content +The component is now aware of preferred language. In case of `` component, show the actual content depending on your preferred programming language. @@ -183,7 +183,7 @@ On smaller screens, you'll display the preferred language switch after clicking ##### Markup ```md - + --- > This block of text is specific to `evitaql` programming language. @@ -191,12 +191,12 @@ On smaller screens, you'll display the preferred language switch after clicking > Go ahead and try to switch. --- - + ``` ##### Result - + --- > This block of text is specific to `evitaql` and `java` programming language. @@ -204,9 +204,9 @@ On smaller screens, you'll display the preferred language switch after clicking > Go ahead and try to switch. --- - + - + --- > This block of text is specific to `Rest` programming language. @@ -214,9 +214,9 @@ On smaller screens, you'll display the preferred language switch after clicking > Go ahead and try to switch. --- - + - + --- > This block of text is specific to `GraphQL` programming language. @@ -224,7 +224,7 @@ On smaller screens, you'll display the preferred language switch after clicking > Go ahead and try to switch. --- - + Other Custom component aware of the user preferred language is [above shown ``](#result-1). @@ -236,11 +236,11 @@ prioritizing visual accessibility, even if it leads to layout shifting. Moreover document, our component render function incorporates supplementary elements to enhance the visibility of this functionality. -So when you try to print this page, you'll see that the `` examples shown above are available and +So when you try to print this page, you'll see that the `` examples shown above are available and ready to be printed. The print preview is similar to what you see on the Github itself, where all the content is visible regardless. -![`` component print example](assets/images/07-print-example.png "`Custom ` component print example.") +![`` component print example](assets/images/07-print-example.png "`Custom ` component print example.") ## What's next diff --git a/documentation/blog/en/12-evitalab-after-6-months.md b/documentation/blog/en/12-evitalab-after-6-months.md new file mode 100644 index 000000000..69b3fc7fc --- /dev/null +++ b/documentation/blog/en/12-evitalab-after-6-months.md @@ -0,0 +1,353 @@ +--- +title: evitaLab after 6 months +perex: | + evitaLab is still being actively developed alongside evitaDB and there are many new features that are worth mentioning. + There are features for learning evitaDB as well as for debugging data. +date: '26.1.2024' +author: 'Lukáš Hornych' +motive: assets/images/12-evitalab-after-6-months.png +proofreading: 'done' +--- + +In [one of our previous blog posts](https://evitadb.io/blog/09-our-new-web-client-evitalab), we covered the initial +release of evitaLab. Since then, we've been running evitaLab internally on all of our new e-commerce applications using +the new evitaDB database, and so far, our developers are loving it. In fact, the original modest driving idea behind the +evitaLab, to help developers debug their evitaDB data from time to time, has become so critical to the workflow of our +newly developed e-commerce applications, that our developers cannot imagine working without it anymore. + +## Our usage workflow + +To get the most out of evitaLab, we automatically deploy it to all our test and development environments for all +applications running evitaDB. This is quite easy because we’ve taken advantage of the fact that evitaLab is already +embedded in the evitaDB server running on the required environments. This way, we can easily pre-configure evitaLab to +include the connection to the particular environment and deploy it to that environment. + +This way, our developers can easily access evitaLab from the same URL as the application itself (just with a different port) +and access their dataset with one click. evitaLab is used both by our backend and frontend developers. Backend Java +developers primarily use it to debug their published data from our primary database using the entity grid. They also use +the evitaQL console to debug their backend Java queries. On the other hand, frontend developers primarily use it to debug +their GraphQL queries using the GraphQL console. + +Of course, this is just a gist of how we currently use evitaLab, but it may give you an idea of how you can use it in +your own workflow. + +## New features and bug fixes + +Since the [initial release](https://evitadb.io/blog/09-our-new-web-client-evitalab), we've worked hard to fix existing +bugs and add planned features that our developers needed (and maybe you needed too) that didn't make it into the first +release. + +### Entity grid + +The entity grid (previously referred to as the data grid) as a whole remains almost the same, we just add new features +and polish it. As it turns out, it’s a really helpful tool for data debugging because it’s so quick to find the data +you’re looking for. The biggest additions to the entity grid are: + +#### Reference attributes + +The property selector now allows you to fetch not only entity references, but also [attributes on those references](https://evitadb.io/documentation/use/schema?lang=evitaql#reference) +(i.e. on the relation between the source and target entities, not on the target entities themselves). + +It then fetches the attributes in additional columns next to the actual references. Each cell then contains attributes +for each reference in a single array. This isn’t an ideal solution, but there is not much room in such a flattened +structure like a table. + +However, you can use the existing detail previewer by clicking on the cell, and easily preview each attribute for each +reference in full detail. + +

+ +

+ + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwgCYUgWgOYBOAlhiADTjQAKEBEAtgM5qgDGA9gHadKthFcAkqXQYk9duRCtsEADbs8AOQYp0SAG5FIUpJ35g48ZGhBUC7DAFc+IAL4VIUACKyWIAI5WkBOABkITjwrCDw1EE1tCA85KQAzIjkwHwAhOFMpdgIxAjSMigwiRgQ5CDgkDHN2ZAJ+JGZUAG0QBGJ6WjgAaSR0imwwYigrZMZUDjEpAiQ4nz1WerHsJDwsonrJ6dnOeYBBMAGiIZHF5JXiBaycwU4AYSWz9IBdCgRQpABlIgAvNQAmAFYXm8lFZ6FAfGgAIx2OxAA). + + + +#### Prices + +Prices are tricky to visualize because there are many of them and there is also the price for sale. Fortunately, you can +now preview all of the prices in the entity grid by simply selecting them in the property selector. + +By default, price cells display the count of all prices in each entity. +When you [execute a filter query](https://evitadb.io/documentation/query/filtering/price?lang=evitaql#quick-guide-to-filtering-by-price) +to calculate prices for sale, each cell automatically displays the price for sale for quick preview. + +However, the most important feature is hidden in the cell details. If you click on any cell with prices, you will see 3 +sections in the detail window: basic entity price properties, calculated price for sale and the most important - a list +of all entity prices. + +The price for sale section simply visualizes the evitaDB price object. + +The list of prices, on the other hand, allows you not only to see all prices, but also to filter them in a way similar +to what you would do with actual evitaQL or GraphQL queries. You can filter the prices by price lists, just like using +the [priceInPriceLists](https://evitadb.io/documentation/query/filtering/price#price-in-price-lists) +constraint (even the order of selection is important as it defines the priority of the price lists). You can also filter +by currency as you would with the [priceInCurrency](https://evitadb.io/documentation/query/filtering/price#price-in-currency), +and on top of that you can even filter by price ID and inner record ID (which is something you cannot do with evitaQL or +GraphQL alone right now). And if you define price lists and currency in the filter, evitaLab will automatically calculate +the price for sale for your filter and display the preview of the calculated price for sale as the first one in the list. + +

+ +

+ + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwgCYUgWgOYBOAlhiADTjQAKEBEAtgM5qgDGA9gHadKthFcAkqXQYk9duRCtsEADbs8AOQYp0SAG5FIUpJ35g48ZGhBUC7DAFc+IAL4VIUACKyWIAI5WkBOABkITjwrCDw1EE1tCA85KQAzIjkwHwAhOFMEYlYkQU5zImy-IkYwRgAKAB0QKAhGAqqASjIAAkyCnM4AYSsCAj1WOEqQAFEAVQAlRql2AjECNNMpDGKEOQg4JAxzdmQCfiRmVABtEDb6WjgAaSR0imwwYigrZMZUDjEpNuzmAF0KBFCSAAykQAF5qABMAFZ-oClFZ6FAfGgAIx2OxAA). + + + +This allows you to easily debug your prices and price list priority without rewriting your queries. + +### Data visualisers + +Big new feature set is data visualization in evitaQL and GraphQL consoles. This is especially useful for newbies trying +to make sense of large extra result JSON documents. + +We’re still missing visualization for entities and query telemetry, but we feel that these aren’t the most important +features right now. The reason is that entities don’t have such complex and large JSON objects like extra results, and +they’re pretty straightforward. Also, because of the graph-like fetching of referenced entities, it may be difficult to +visualize them properly, so we are still thinking about the right solution. As for query telemetry, it is indeed +difficult to read without visualization, but it’s not the most used feature of evitaDB right now. + +The visualizations are available after you execute a query in an alternative panel to the raw JSON output. You can switch +between these panels in the navigation bar on the right side of the console. + +![Result visualizer switch in console](assets/images/12-console-visualizer-switch.png "Result visualizer switch in console") + +There you will see a select component to select a query for visualization (in the case of GraphQL) and a select component +to select a query part to visualize. + +#### Facet summary + +One of the supported extra results that are supported in the visualizer is the [facet summary](https://evitadb.io/documentation/query/requirements/facet). +If you execute an evitaQL or GraphQL query with [facetSummary](https://evitadb.io/documentation/query/requirements/facet#facet-summary) +or [facetSummaryOfReference](https://evitadb.io/documentation/query/requirements/facet#facet-summary-of-reference) +require constraint, a facet summary visualization will be available in the visualization panel. + + + + + +##### GraphQL field aliases and visualizer + + +Note that the GraphQL query supports field aliases, which effectively change the output JSON. This is something we’re +unable to work with in the visualizer at the time of writing this article. For now, you can’t use aliases in the facet +summary subtree, otherwise the visualizer won’t find it. We plan to support aliases as well, but it requires analyzing +the input query, which is a bit more complicated and time consuming than we are willing to invest right now. + + + +After executing the query, you will first see a list of all faceted references based on the used require constraint. +Each item contains several useful numbers, which you can read more about in our [documentation](https://evitadb.io/documentation/query/requirements/facet#evitalab-visualization). If your faceted +references are grouped, you will see the actual groups on the second level of the list, and individual facets on the next +level. If there are no groups for a particular reference, the facets are listed directly under the reference. + +![Facet summary visualization in console](assets/images/12-visualizer-facet-summary.png "Facet summary visualization in console") + + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwiQNwJaQI4A2AtAMYD2AdgM5kEoA040AChAE4QC2Vao5FFJCTDZKASQAmaEBKScyIRiQiQCZAOYA5LinRZcEEAF9GkKABEVh1KDwBXJGzjT7juAAoAOhQAEfn+QEdMKiFF4gzGxkEnbCniAAlPTe-j4AZtgEYI4AQh4pqf4AFtiO7CRFcADquCVhBYWF8crZ6mRspVTxyb6NhSpgHVB22QCi9hAEVOHkst0+8UhEbEgQsmxdiQ2FSdupA0MjSON2k9PxVJBgdpv0CyAAggDCMGIAaqPxCdu7vX4r9mwKy8f0KaQgJCQYAAynZOJx2PlQY0xABZZjPGA9Pr+JAUERgOAAMShFRBOP2YEG2GG2SelGy+Jm0SQXz2O2xFLxBLgAHEonYECSwGT2Y0DjSjvT8dzmXMtsidmKfN9QaqEooQJh2NhoHQeOhgAVvEZjEYgA). + + + +#### Hierarchy + +The second important feature of evitaDB is the calculation of [hierarchy trees](https://evitadb.io/documentation/query/requirements/hierarchy) +for menus and navigation. There is a visualization for that too. +If you use [hierarchyOfSelf](https://evitadb.io/documentation/query/requirements/hierarchy#hierarchy-of-self) or +[hierarchyOfReference](https://evitadb.io/documentation/query/requirements/hierarchy#hierarchy-of-reference) require +constraint, a hierarchy tree visualization will be available in the visualization panel. + + + + + +##### Hierarchy field aliases and visualizer + + +In the case of hierarchy visualization, there is a small exception to the field alias restriction for GraphQL. You can +use field aliases to name your hierarchies and the visualizer will render it correctly with your name. + + + +As you can see, you get a view similar to the facet summary visualization. You can browse through the individual +hierarchies and directly see how your query affects the richness of each hierarchy tree. + +![Hierarchy trees visualization in console](assets/images/12-visualizer-hierarchy.png "Hierarchy trees visualization in console") + + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwiQNwJaQI4A2AtAMYD2AdgM5kEoA040AChAE4QC2Vao5FFJCTDZKASQAmaEBKScyIRiQiQCZAOYA5LinRZcEEAF9GkKABEVh1KDwBXJGzjT7juAAoAOhQAEP8gR0wqIU7gDkzGxkEnbCYQCU9N5+AGbYBGCOAEIeyX4+ABbYjuwkBXAA6rhFoXn5PmHKmepkbMVUYUm+9T4qYG1QdpkAovYQBFTh5LKdDRB2EqIJXT0+SAAeJAQL2BTqXt2rfQNDSKN245ON0UizYQDu2GxIdFRURAVIEBIIBZRIHXidXyQMOPlBfkSeWe9ieSAO9SKJTYZTgAHkUgAlJApRxICgkeHA-KNFRIFptAGdYl+BDsfFgSY0+phOnPCiMqpgAowT5PADK2CgBF26g6K1W+QZuDgADEkGAyu5jkLTgBhSiZDlTG4JKFg1ZUIUivZMg2S6VgOUKpUqwaZDUchk6mbxCGSyHM-WSlJRTiYshkMAIj0NKJB8WhnzMqUcmXyxUFZVgfqqh2a53XV3e0NUMBkBAAQWDdEwL3cAEY3RKPXmVNg89gSJM1QAJMQAGXMmOGmgA+mq0QBVTQweg+ACKQ+GmLEw3Mfd7MDEMAAmgPh6P3T1t+C8qDQYoQJh2NhoK9pMA8t4jMYjEA). + + + +#### Histograms + +The last currently supported visualization extra results are histograms, both price and attribute histograms. +[Histograms](https://evitadb.io/documentation/query/requirements/histogram) allow you to nicely visualize large cardinality +of values in a limited space. The actual JSON returned for visualization of histograms in your application isn’t as +complex as the other extra results. However, it is much harder to visualize in your head. +If you use [attributeHistogram](https://evitadb.io/documentation/query/requirements/histogram#attribute-histogram) or +[priceHistogram](https://evitadb.io/documentation/query/requirements/histogram#price-histogram) require constraint in +the query, a histogram visualization will be available in the visualization panel. + +![Histogram visualization in console](assets/images/12-visualizer-histogram.png "Histogram visualization in console") + + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwiQNwJaQI4A2AtAMYD2AdgM5kEoA040AChAE4QC2Vao5FFJCTDZKASQAmaEBKScyIRiQiQCZAOYA5LinRZcEEAF9GkKABEVh1KDwBXJGzjT7juAAoAOhQAEfn+QEdMKiFF4gzGxkEnbCniAAlPTe-j4AZtgEYI4AQh4pqT4IbNgkSGIUkaVIADLYVGBU4VAQVKXxSQWpxdUVAMJ2bGxIFCT5IACiAKoASh1dPp2+-sP22MNey90lZQAS9WAaHJzuAIwADAkLVxQJiiCY7NjQdDzowAXeRsZGQA). + + + +You will see the actual histogram as well as additional information for each bucket. If you then extend your query +with a [userFilter](https://evitadb.io/documentation/query/filtering/behavioral#user-filter) that contains either +[attributeBetween](https://evitadb.io/documentation/query/filtering/comparable#attribute-between) or +[priceBetween](https://evitadb.io/documentation/query/filtering/price#price-between) to simulate user selection, +the visualization will take this into account and visualize the narrowed view as well. + +![Narrowed histogram visualization in console](assets/images/12-visualizer-histogram-narrowed.png "Narrowed histogram visualization in console") + + + +Checkout the example in our [demo evitaLab](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwiQNwJaQI4A2AtAMYD2AdgM5kEoA040AChAE4QC2Vao5FFJCTDZKASQAmaEBKScyIRiQiQCZAOYA5LinRZcEEAF9GkKABEVh1KDwBXJGzjT7juAAoAOhQAEfn+QEdMKiFF4gzGxkEnbCniAAlPTe-j4AZtgEYI4AQh4pqT4IbNgkSGIUkaVIADLYVGBU4VAQVKXxSQWpxdUVAMJ2bGxIFCT5IACiAKoASh3JvoV2VI4AYpnZbF6LhUUlZTlIYADuSCPuAKwADFf0PgDMN1cJXf4vOz6dH8P22MPbux6ZQAEvUwBoOJx3ABGZ6vd4JRQgTDsbDQOg8dDAAreIzGIxAA). + + + +### evitaQL language support + +For the GraphQL console, we used an [existing library](https://github.com/graphql/graphiql/tree/main/packages/cm6-graphql#readme) for auto-completion and linting. However, since the evitaQL +language is our own, there is no support for it in the [CodeMirror](https://codemirror.net/) editor that we use. So we invested some time to +develop at least minimal [language support](https://www.npmjs.com/package/@lukashornych/codemirror-lang-evitaql) for the CodeMirror editor, so that it is not such a pain to write evitaQL +queries in evitaLab. Currently, we have at least basic auto-completion of all available constraints with basic +documentation (without supported parameters yet). + +![evitaQL language support in console](assets/images/12-evitaql-support-console.png "evitaQL language support in console") + +![evitaQL language support in entity grid](assets/images/12-evitaql-support-entity-grid.png "evitaQL language support in entity grid") + + + +Checkout the entity grid example [here](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwgCYUgWgOYBOAlhiADTjQAKEBEAtgM5qgDGA9gHadKthFcAkqXQYk9duRCtsEADbs8AOQYp0SAG5FIUpJ35g48ZGhBUC7DAFc+IAL4VIUACKyWIAI5WkBOABkITjwrCDw1EE1tCA85KQAzIjkwHwAhOFNsMGIoK2SAZUgCMEYAdW0ACwAKAB1pSyRasgACWvoIVih2dgBrWoBKKXYCMQI0jLAsohzklTArOjkaurFGpoBBPIBhAYoMIkYEOQg4JAxzdmQioiRmVABtEARiNt8AaSR0igUZORupeTkfnYPz+FCeRFYSEE3B8ACVeEMMAAJQIYOREIL-CbZXI3VAySAKZRWehQHxYybTPGMSBzZgUTI45KMfH1ClMvFIQJScGQ5gAXTBoSQeSIAC81AAmACsQrCShJZIIaAAjHY7EA) and the evitaQL console [here](https://demo.evitadb.io/lab?sharedTab=N4IgLghgRgKgngBwKYgFwiQNwJaQI4A2AtAMYD2AdgM5kEoA040AChAE4QC2Vao5FFJCTDZKASQAmaEBKScyIRiQiQCZAOYA5LinRZcEEAF9GkKABEVh1KDwBXJGzjT7juAAoAOhQAEP8gR0wqIUXiDMbGQSdsKeIACU9N5+AGbYBGCOAEIeyX4+KmBs2FB2mQDKkGxgVADquAAWYeSycfQ+cZwQJFBkZADWcfF5iXlsSPbY416++UgUImBwAGJIYCRNefkFYEUlZUgAwpSZC81RSENbPsOzt-GKIJjs2NB0POjAed5GxkZAA). + + + +There is also a very simple linter to check things like missing commas or the structure of the query root, and other +little things like syntax highlighting, folding, or automatic indentation. Even this basic support has been invaluable +when writing queries. Of course, we plan to make the support more sophisticated, but unfortunately that’s quite +time-consuming. + +### Sharing tabs between browsers + +Tab sharing between developers is something we’re very excited about. A lot of the time our frontend and backend +developers share their queries via a messaging application by copying and pasting entire queries into the chat, +just to debug some parts of the queries. This leads to cluttered chat conversations and communication errors when +the same developers are working on multiple projects with different evitaDB server instances. That’s why we hope this +feature will greatly improve communication between developers and save them some time and nerves. + +You can easily share any tab with current data by sharing a link to with the other developer. An actual link targets the +same evitaLab instance as yours and your data with properly set up evitaDB connection, catalog selection and so on. The +receiving developer doesn't have to worry about choosing the right server, the right connection and so on anymore. All +of this is embedded in the link. + + + +As you can see, we’ve used this feature even in this article to show you custom examples that aren’t in our documentation. +You can use this feature in a similar way e.g. in your own documentation, for example, by pointing to your demo instance +to demonstrate your domain-specific queries. + + + +Checkout the entire workflow in our short showcase video: + +

+ +

+ +### Storing last session + +When it comes to restoring your workspace after some time, the absence of recently opened tabs and executed queries can +be quite annoying. Especially if you have large queries that you can’t remember. With the new evitaLab you don’t have +to worry about that anymore. Just close or refresh your tab or browser and evitaLab will restore all of your tabs from +the last session. + +

+ +

+ +However, there are two exceptions where this doesn’t happen, and for good reason. + +The first exception is when you open a shared link that points to the same evitaLab. This is because the link will be +always be opened in a new browser tab, even if you already have the same evitaLab instance already open, and when you +open a such link (e.g. for a quick look) you don’t want your entire session to be restored as well (there may be 10 tabs +in your last session). Another concern is that you might accidentally close your primary session before this new one and +overwrite it with data from a shared tab. Or you could open multiple links with shared tabs, and again, you probably +don’t want to restore your session for every link you open. + +The session exception is when you open a query example from our documentation. The reasoning is the same as for the +shared tabs link. + +### Query history + +Similarly useful to the session transfer is the query history with the ability to browse through previously executed +queries. We’ve implemented query history in all tabs that support queries, i.e. evitaQL console, GraphQL console and +entity grid. + +Both consoles have separate panel to switch queries with variables in one go. + +![Query history in console](assets/images/12-history-console.png "Query history in console") + +Each combination of connection + catalog has its own list of history records to avoid mixing different data. + +Entity grid has separate histories for both filter and order parts of a query. The history for each input can then be +opened via the preceding icon or with Alt+↓ (or Option+↓ for Mac). + +![Query history in entity grid](assets/images/12-history-entity-grid.png "Query history in entity grid") + +Similar to consoles, each combination of connection + catalog + collection + filter/order has its own list of history +records to avoid mixing different data. + +### Other small features and bug fixes + +* we switched to calendar versioning from semantic versioning +* code editor have status bar with line, column, and caret information +* we fixed too long entity grid cell values occupying entire screen +* entity grid now displays selected data locale its in header +* there is a new keyboard shortcut Ctrl+F to focus the search input in the entity grid property selector +* new evitaDB attribute uniqueness types are displayed in detail in attribute flags +* filterable attribute flag has now note if the filtering is implicit for unique attributes +* there are now tooltips for connections, catalogs and collections in explorer +* and other UI improvements and fixes + +There were many more small bug fixes along the way but these are the most important ones. + +## Planned features in near future + +We still have a lot of ideas in mind, but we cannot do everything at once. Currently, we are planning to open these issues: + +- [status info screen for evitaDB servers](https://github.com/lukashornych/evitalab/issues/103) +- [screen with keyboard shortcuts](https://github.com/lukashornych/evitalab/issues/110) +- [quick access to explorer item actions](https://github.com/lukashornych/evitalab/issues/98) +- [time machine for new upcoming evitaDB catalog versioning features](https://github.com/lukashornych/evitalab/issues/95) + +And [many more](https://github.com/lukashornych/evitalab/issues). + +## Contribution + +Like the last time, if you feel confident, feel free to report a bug or submit a PR on our [GitHub](https://github.com/lukashornych/evitalab) with any +improvements. Any input is greatly appreciated, even small things like fixing typos or writing new tests. diff --git a/documentation/blog/en/assets/images/12-console-visualizer-switch.png b/documentation/blog/en/assets/images/12-console-visualizer-switch.png new file mode 100644 index 000000000..0a2368198 Binary files /dev/null and b/documentation/blog/en/assets/images/12-console-visualizer-switch.png differ diff --git a/documentation/blog/en/assets/images/12-evitalab-after-6-months.full.png b/documentation/blog/en/assets/images/12-evitalab-after-6-months.full.png new file mode 100644 index 000000000..f59e2566b Binary files /dev/null and b/documentation/blog/en/assets/images/12-evitalab-after-6-months.full.png differ diff --git a/documentation/blog/en/assets/images/12-evitalab-after-6-months.png b/documentation/blog/en/assets/images/12-evitalab-after-6-months.png new file mode 100644 index 000000000..11a82a16d Binary files /dev/null and b/documentation/blog/en/assets/images/12-evitalab-after-6-months.png differ diff --git a/documentation/blog/en/assets/images/12-evitaql-support-console.png b/documentation/blog/en/assets/images/12-evitaql-support-console.png new file mode 100644 index 000000000..72da318e8 Binary files /dev/null and b/documentation/blog/en/assets/images/12-evitaql-support-console.png differ diff --git a/documentation/blog/en/assets/images/12-evitaql-support-entity-grid.png b/documentation/blog/en/assets/images/12-evitaql-support-entity-grid.png new file mode 100644 index 000000000..fb21a84a3 Binary files /dev/null and b/documentation/blog/en/assets/images/12-evitaql-support-entity-grid.png differ diff --git a/documentation/blog/en/assets/images/12-history-console.png b/documentation/blog/en/assets/images/12-history-console.png new file mode 100644 index 000000000..c26b2a732 Binary files /dev/null and b/documentation/blog/en/assets/images/12-history-console.png differ diff --git a/documentation/blog/en/assets/images/12-history-entity-grid.png b/documentation/blog/en/assets/images/12-history-entity-grid.png new file mode 100644 index 000000000..bd01ac1a3 Binary files /dev/null and b/documentation/blog/en/assets/images/12-history-entity-grid.png differ diff --git a/documentation/blog/en/assets/images/12-visualizer-facet-summary.png b/documentation/blog/en/assets/images/12-visualizer-facet-summary.png new file mode 100644 index 000000000..274c08f93 Binary files /dev/null and b/documentation/blog/en/assets/images/12-visualizer-facet-summary.png differ diff --git a/documentation/blog/en/assets/images/12-visualizer-hierarchy.png b/documentation/blog/en/assets/images/12-visualizer-hierarchy.png new file mode 100644 index 000000000..68fa812af Binary files /dev/null and b/documentation/blog/en/assets/images/12-visualizer-hierarchy.png differ diff --git a/documentation/blog/en/assets/images/12-visualizer-histogram-narrowed.png b/documentation/blog/en/assets/images/12-visualizer-histogram-narrowed.png new file mode 100644 index 000000000..cdf18be0b Binary files /dev/null and b/documentation/blog/en/assets/images/12-visualizer-histogram-narrowed.png differ diff --git a/documentation/blog/en/assets/images/12-visualizer-histogram.png b/documentation/blog/en/assets/images/12-visualizer-histogram.png new file mode 100644 index 000000000..f3f25f350 Binary files /dev/null and b/documentation/blog/en/assets/images/12-visualizer-histogram.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/03-query-basics.html b/documentation/publishing/root.cz/03-query-basics/03-query-basics.html new file mode 100644 index 000000000..ef31d8f4f --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/03-query-basics.html @@ -0,0 +1,1265 @@ + + + + + + + evitaDB – základy dotazovacího jazyka evitaQL + + +
+

evitaDB – základy dotazovacího jazyka evitaQL

+ +

+ Článek představuje základní principy dotazovacího jazyka evitaQL, konstrukci dotazů a jejich chování. Rozebereme + si nejdůležitější oblasti, ve kterých se evitaDB liší od ostatních databází a ukážeme si, jak je využít ve svůj + prospěch. +

+
+
+ +

+ evitaDB je NoSQL databáze s vlastním dotazovacím jazykem, který byl navržen s ohledem na podobnost v různých + webových API i programovacích jazycích a srozumitelnost nezasvěcenému čtenáři. +

+

+ Na první pohled by se mohlo zdát, že dotazovací evitaQL jazyk trpí syndromem dlouhých názvů, tolik typickým pro + Java vývojáře, kteří jej navrhovali. Pokud se však zamyslíte nad naší argumentací, věříme, že návrh jazyka vám + bude dávat smysl. +

+

+ Nejprve si pojďme ukázat krátký příklad jednoduchého evitaQL dotazu: +

+ + +
query(
+  collection("Product"),
+  filterBy(
+    attributeEquals("status", "ACTIVE"),
+    attributeGreaterThan("battery-life", 10),
+    or(
+      attributeIs("validity", NULL),
+      attributeInRangeNow("validity")
+    )
+  ),
+  orderBy(
+    attributeNatural("orderedQuantity", DESC)
+  ),
+  require(
+    entityFetch(
+      attributeContentAll()
+    )
+  )
+)
+
+ +

+ Vyzkoušejte + si dotaz v evitaLab +

+

+ Dříve, než budete pokračovat ve čtení dál, zkuste odhadnout, co tento dotaz představuje a jaká by měla být + odpověď databázového serveru. Zkusmo jsme tuto otázku položili i ChatGPT (v. 4) a zdá se, že jeho účel + pochopil velmi dobře i přesto, + že evitaQL nebyl v roce 2021 v datech, na kterých se učil. +

+

+ Srozumitelnost jazyka je do jisté míry dána tím, že jeho konstrukce a názvy jednotlivých podmínek odpovídají + konstrukci anglické věty: `query collection XY, filter it by attribute A that + equals to B, order it by attribute C in natural descending order, + require entity to be fetched with entire attribute content`, a nejspíš proto + bylo odvození významu pomocí ChatGPT takto přesné. +

+

+ Velkou výhodou takto konstruovaného jazyka je to, že ve webových GraphQL a REST API je jeho znění velmi podobné. + Zápis v jazyce Java je identický a v případě C# klienta jsou odlišnosti taktéž minimální. Vývojáři používající + různé technologie pro svou práci (např. frontendový tým využívající v JavaScriptu GraphQL formát a backendový + tým využívající Java či C# jazyk) si tedy budou navzájem rozumět, i když uvidí dotaz vytvořený druhým týmem v + odlišné technologii. Sami se můžete o podobnosti dotazů přesvědčit v naší dokumentaci, pokud si + v pravém sloupci budete přepínat mezi různými podporovanými jazyky. +

+

+ Konstrukce jazyka připomíná sadu vnořených funkcí, což dává mnohem větší prostor pro to, aby se v jednotlivých + prostředích mohla převést na nativní konstrukty daného jazyka. Tím získáme možnost využít podpory kompilátorů a + linterů cílových prostředí ke kontrole obsahu dotazu (např. typové kontroly). Řada IDE také díky tomuto přístupu + nabízí vývojářům další podporu ve formě automatického doplňování dotazu, protože na základě typů a schémat ví, + jaké konstrukty (podmínky) dávají smysl v daném místě dotazu. Díky automatickému doplňování věříme, že vývojář + bude zřídkakdy nucen psát celé názvy podmínek, ale bude mu stačit zapsat pár úvodních písmen slov podmínky a + zbytek práce za něj odvede vývojářské prostředí. +

+ +

Klíčové pasáže dotazu

+ +

+ Dotaz se skládá ze 4 hlavních bloků, z nichž každý může za určitých situací chybět – tj. žádný z nich není + bezpodmínečně povinný: +

+
    + +
  1. collection – určuje cílovou kolekci katalogu, na kterou dotaz cílí a může chybět v případě, + že se dotazujeme na entity podle globálně + unikátních atributů. + +
  2. filterBy – umožňuje omezit počet vrácených entit pouze na takové, které splňují filtrovací + podmínku (dokumentace). + +
  3. orderBy – definuje způsob řazení vrácených entit (dokumentace). + +
  4. require – ovlivňuje rozsah (počty, hloubku načtení) vrácených dat, umožňuje ovlivnit + chování stroje při vyhodnocování dotazu a definovat dodatečné požadavky na vedlejší výpočty, které souvisí s + vyfiltrovanými entitami (dokumentace). +
  5. +
+

+ Entity v kolekcích se dají vyhledávat podle primárních + klíčů, existence lokalizace + do konkrétního jazyka, shody hodnot + atributů nebo porovnání + s konstantou na vstupu, překryvu + rozsahových hodnot, řetězcových + operací nad atributy, existencí cen, existence reference na jinou + entitu či atributů definovaných na této referenci či zařazení do hierarchické + struktury. Samozřejmostí je možnost kombinovat více podmínek dohromady pomocí logických operátorů. +

+

+ Pokud nejsou uvedeny požadavky na řazení, jsou entity vždy řazeny vzestupně podle primárního klíče – tedy ve + formě, která je pro databázi „přirozená“. Řadit ovšem můžete podle přirozeného pořadí + hodnot atributů, exaktního + pořadí atributů či primárních + klíčů, cen, atributů referencí + (a to včetně referenci + s kardinalitou „one-to-many“) nebo náhodně. +

+

+ Na výstupu můžeme seznam nalezených entit stránkovat, ovlivňovat jejich + rozsah, jazyk a + to včetně možnosti načítat + graf referencovaných entit do libovolné hloubky s případnou filtrací + či řazen + uzlů v rámci načítaného grafu entit. Kromě požadavků na vrácené entity, si můžeme nechat spočítat podklady pro + zobrazení parametrického + filtru, menu či histogramů + hodnot. Ke každému dotazu si můžeme nechat vrátit i rozpad výpočtu na + straně serveru spolu s informací o času potřebném na jeho jednotlivé kroky (obdoba EXPLAIN v jazyce SQL). +

+

+ Některé z těchto funkcí si v rychlosti rozebereme v dalších kapitolách tohoto článku s důrazem na ty, které jsou + pro evitaDB specifické. +

+ +

Načítání lokalizovaných dat

+ +

+ Velká řada katalogů je lokalizovaná do různých národních prostředí. Uživatel se při práci s aplikací na tato + data kouká typicky optikou jednoho konkrétního vybraného jazyka. Tento scénář evitaDB řeší následujícím dotazem: +

+ +
query(
+  collection("Product"),
+  filterBy(
+    entityPrimaryKeyInSet(103885, 103911, 105715),
+    entityLocaleEquals("cs")
+  ),
+  orderBy(
+    attributeNatural("name", DESC)
+  ),
+  require(
+    entityFetch(
+      attributeContent("name", "descriptionShort"),
+      associatedDataContent("localization")
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Dotaz nám vrátí 3 záznamy v české lokalizaci seřazené sestupně podle české varianty jejich názvu. Pokud by + některý ze jmenovaných produktů českou mutaci neobsahoval, vůbec se ve výsledku nevrátí. Použití podmínky + `entityLocaleEquals` nejen že ovlivňuje filtraci entity, ale zároveň se stává zdrojem pro volbu implicitního + jazyka při získávání hodnot lokalizovaných atributů a asociovaných dat. Pokud změníte hodnotu `locale` na `en`, + získáte hodnoty pro anglický jazyk. Pro identifikaci locale se používá zápis ve formátu tzv. language tagu, který je univerzálním zápisem pro + řadu různých platforem. +

+

+ Ačkoliv tento mechanismus celkem snadno vyřešíte třeba i s běžnou relační databází, jeho nativní podpora + databázovým strojem přináší značné zjednodušení při zápisu dotazů, což bude umocněno funkcionalitami + popisovanými v dalších kapitolách. +

+

+ V některých případech budete potřebovat získat více než jen jediný jazyk entity – typicky při vytváření entit ať + už z administračního rozhraní nebo importem z jiných datových zdrojů. V těchto případech bude konstrukce dotazu + mírně odlišná: +

+ + +
query(
+  collection("Product"),
+  filterBy(
+    entityPrimaryKeyInSet(103885, 103911, 105715)
+  ),
+  require(
+    entityFetch(
+      attributeContent("name", "descriptionShort"),
+      associatedDataContent("localization"),
+      dataInLocales("cs", "en")
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ V dotazu došlo ke dvěma změnám – vypadla podmínka `entityLocaleEquals` byla nahrazena žádostí o vrácení + lokalizací `cs` a `en` v deklaraci `dataInLocales`, která je součástí `require` bloku. +

+

+ Tato změna způsobí, že dotaz vždy vrátí všechny tři entity dle jejich primárních klíčů bez ohledu na + (ne)dostupnost lokalizací. Nalezené entity budou obsahovat lokalizovaná data pro všechny požadované jazyky + (pokud taková mají). +

+ +

Načítání grafu entit (join)

+ +

+ Podobně jako se v relačních databázích používá klauzule JOIN pro spojování záznamů skrz více tabulek, je v + evitaDB možné získávat nejen hlavní entitu, ale skrz reference (odkazy) na další entity celý graf provázaných + entit prakticky do libovolné hloubky. Tento mechanismus má samozřejmě svá technická omezení. Teoreticky byste si + mohli v rámci jednoho dotazu limitně načíst celý obsah databáze, což jednak nedává smysl a jednak byste se + výsledku na větších datových sadách nedočkali ani na seberychlejší databázi. +

+

+ Při načítání entit do hloubky používáme výraz graf entit, protože tento princip byl do značné míry inspirován + přístupem GraphQL. Ve své podstatě odpovídá tomu, jak s logickými celky pracují ORM knihovny. + Tento přístup je pro aplikační vývojáře přirozenější a používá se jim lépe než relační forma práce s daty. +

+

+ Na následujícím příkladě si ukážeme, jak je možné načíst produkt se všemi hodnotami jeho parametrů (např. + červená, Android, 8GB), které se dále odkazují na entitu parametru (barva, operační systém, velikost paměti). + Zároveň si vypíšeme i všechny atributy náležící referenci mezi produktem a hodnotou parametru, mezi které patří + především bool příznak, zda se jedná o vazbu identifikující variantu produktu: +

+ +

+ + Vztahový diagram Produkt ⇒ Parametr + +

+ + +
query(
+  collection("Product"),
+  filterBy(
+    entityPrimaryKeyInSet(103885),
+    entityLocaleEquals("cs")
+  ),
+  require(
+    entityFetch(
+      attributeContent("name"),
+      referenceContentWithAttributes(
+        "parameterValues",
+        entityFetch(
+          attributeContent("code", "name"),
+          referenceContentWithAttributes(
+            "parameter",
+            entityFetch(
+              attributeContent("code", "name")
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Na tomto příkladě si můžete všimnout, že požadovaný jazyk stačí deklarovat jednou a všechny načtené entity + včetně těch vnořených jej respektují. Vyzkoušejte si místo češtiny vyžádat anglické názvy entit. +

+

+ Příklad je do velké míry zjednodušený, protože i v těch velmi jednoduchých katalozích bude mít položka velké + množství relací na okolní entity a nedávalo by smysl se je snažit všechny zohledňovat v tomto článku. Běžné jsou + i reference s kardinalitou „1:N“, které se mohou odkazovat na značné množství okolních entit. Proto jazyk + umožňuje na úrovni jednotlivých referencí definovat filtrovací podmínky a definovat řazení referencí s + kardinalitou větší než jedna: +

+ + +
query(
+  collection("Product"),
+  filterBy(
+    entityPrimaryKeyInSet(103885)
+  ),
+  require(
+    entityFetch(
+      referenceContentWithAttributes(
+        "parameterValues",
+        filterBy(
+          entityHaving(
+            referenceHaving(
+              "parameter",
+              entityHaving(
+                attributeContains("code", "r")
+              )
+            )
+          )
+        ),
+        orderBy(
+          entityProperty(
+            attributeNatural("code", DESC)
+          )
+        ),
+        entityFetch(
+          attributeContent("code"),
+          referenceContentWithAttributes(
+            "parameter",
+            entityFetch(
+              attributeContent("code")
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Tento dotaz je prakticky shodný s předchozí ukázkou, pouze při načítání hodnot parametrů vrátí pouze ty, které + patří do parametru s kódem obsahujícím písmeno `r`. Zároveň tyto hodnoty parametrů seřadí sestupně podle jejich + kódu. To zajistí nové podmínky `filterBy` a `orderBy` deklarované na úrovni deklarace zajišťující načtení + reference `parameterValues`. +

+

Parametrizované filtry (facety)

+ + +

+ Parametrizované filtry dávají smysl u katalogů s velkým množstvím položek, ve kterých by se uživatel jen těžko + vyznal. Parametrické filtry jsme zmiňovali už v prvním + článku této série a vidíte je běžně na internetu, takže zde se budeme soustředit pouze na to, jak vám s nimi + může pomoci právě evitaDB. +

+

+ Podklady pro zobrazení filtru si můžete nechat připravit v rámci tzv. vedlejších výpočtů, které jsou spojené se + základním dotazem na položky katalogu. Dotaz obsahující parametrický filtr by mohl vypadat například následovně: +

+ +
query(
+  collection("Product"),
+  filterBy(
+    attributeEquals("status", "ACTIVE"),
+    userFilter(
+      facetHaving(
+        "groups",
+        entityHaving(
+          attributeEquals("code", "sale")
+        )
+      )
+    )
+  ),
+  require(
+    facetSummary(
+      COUNTS,
+      entityFetch(
+        attributeContent("code")
+      ),
+      entityGroupFetch(
+        attributeContent("code")
+      )
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Klíčovými položkami tohoto dotazu je `facetSummary` v bloku `require` a `userFilter` v bloku `filterBy`. Z + dotazu je patrné, že se snažíme vypsat entity typu `Product`, které splňují nějaké základní vlastnosti – v tomto + případě je to reprezentováno podmínkou, že atribut `status` musí obsahovat hodnotu `ACTIVE` (tzv. systémová + podmínka) a také uživatelem definované vlastnosti – v tomto případě musí obsahovat referenci `groups` na entitu + s kódem `sale`. Rozdělení na systémovou a uživatelskou část filtrovací podmínky je klíčové pro výpočet hodnot v + rámci `facetSummary`, jak si vysvětlíme následně. +

+

+ Požadavek na výpočet `facetSummary` vám pro všechny položky, které splňují systémové podmínky základního dotazu, + vrátí seznam odkazovaných entit s informací o počtu položek, které se na danou entitu odkazují. Tyto entity jsou + seskupeny do logických celků (skupin) podle informací nastavených ve schématu katalogu. +

+

+ Pokud si přečtete dokumentaci o tvorbě + schématu, zjistíte, že na úrovni schématu reference je možné označit danou referenci jako `faceted`. Zároveň + je možné u každé reference nastavit vazbu na sekundární entitu, která reprezentuje její zařazení do nějaké + logické skupiny. Tím, že je tato informace nastavená už na úrovni schématu, si může databázový stroj dopředu + připravit požadované indexy a zároveň tento přístup zjednodušuje následné sestavování dotazů, kde již není třeba + tyto informace neustále opakovat. +

+

+ V našem dotazu tedy stačí pouze definovat požadavek na výpočet podkladů pro parametrický filtr s žádostí o + dotažení atributu `code` jak pro odkazovanou entitu, tak i pro entitu, která reprezentuje logické seskupení + odkazovaných entit. evitaDB pak už ví, že si má všímat všech referencí, označených ve schématu jako `faceted` a + ví vše o těchto odkazovaných entitách. +

+

+ Pokud si dotaz spustíte v nástroji evitaLab, vrátí se vám výsledek + primárně ve formátu JSON – tedy tak, jak jej budete pravděpodobně konzumovat ve své aplikaci, ale máte zde i + možnost v pravé části přepnout pohled na vizualizaci typizovaného parametrizovaného filtru pro jednodušší + porozumění vráceným datům. Náhled bude vypadat následovně: +

+

+ + Výpis parametrů s počty produktů + +

+

+ Z vizualizace je patrné, že evitaDB vrátila informaci o odkazovaných entitách, kdy na úrovni každé této entity + je dostupná informace, kolik produktů se váže ke každé jednotlivé referenci na cílovou entitu (pro entitu `sale` + – výprodej – to je 39 produktů, pro `for-men-group` je to 239 atp.). Zároveň je u všech entit, které jsou + vyžadované tzv. uživatelským filtrem, informace o tom, že tyto entity jsou součásti požadovaného výběru, a tudíž + je jejich položka `zaškrtnutá`. Tyto podklady jsou vypočteny i pro všechny ostatní reference produktu, které + jsou ve schématu označeny jako `faceted` – tj. pro sklady, štítky, kategorie, značky a hodnoty parametrů. Pokud + si rozkliknete právě hodnoty parametrů, uvidíte, že ty jsou členěny do dvou úrovní, kdy první úroveň + reprezentuje parametry a teprve v nich jsou informace o hodnotách. +

+

+ Dotaz reprezentuje pouze základní výstup pro parametrizovaný filtr, který dokážete získat i pomocí + alternativních databází, jako jsou Elasticsearch, Typesense, Meilisearch nebo Algolia. V evitaDB + však můžete při výpočtu požádat o výpočet tzv. „dopadové analýzy“, pro kterou ve výše uvedených databázích + neexistuje alternativa. +

+

+ Dopadová analýza spočítá ke každé nabízené entitě informaci o tom, jaký by mělo její zahrnutí do filtru dopad na + výsledek dotazu. Prakticky to znamená vypočítat pro každou takovou položku další dodatečný dotaz vycházející ze + stávajícího dotazu a rozšířený o podmínku na existenci reference pro tuto, v současnosti nevybranou, entitu. +

+

+ Pro výpočet dopadové analýzy nám stačí změnit typ výpočtu z `COUNTS` na `IMPACT`: +

+ +
query(
+  collection("Product"),
+  filterBy(
+    attributeEquals("status", "ACTIVE"),
+    userFilter(
+      facetHaving(
+        "groups",
+        entityHaving(
+          attributeEquals("code", "sale")
+        )
+      )
+    )
+  ),
+  require(
+    facetSummary(
+      IMPACT,
+      entityFetch(
+        attributeContent("code")
+      ),
+      entityGroupFetch(
+        attributeContent("code")
+      )
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Výpočet je logicky výkonnostně mnohem náročnější, ale ve výsledku u každé položky uvidíte informaci o počtu + produktů, které z výsledku zmizí nebo přibudou, pokud do uživatelského výběru zahrnete podmínku na existenci + vazby na odpovídající entitu. Pokud se podíváme do nástroje evitaLab na výsledky vizualizace tohoto dotazu pro + parametr `Typ displeje`, uvidíme, že výběrem vlastnosti `TFT` displej by ve výběru ze současných 39 produktů + zůstalo pouze 12 (tj. o 27 bychom přišli). V případě `OLED` displejů bychom přišli téměř o celý výběr a zůstal + by nám pouze jediný produkt, který je aktivní a je ve skupině výprodej. +

+

+ + Dopadová analýza parametrického filtru + +

+

+ Výpočty podkladů pro parametrické filtry vychází z předpokladu „běžných vztahů“ položek v nabídce – tedy že + položky ve stejné skupině se spojují logickou vazbou OR a položky v různých skupinách / odlišných referencích se + spojují logickou vazbou AND. V praxi se občas setkáváme s odlišnými požadavky, a proto je možné tyto vztahy v + rámci dotazu upravit – například stanovit, že logická skupina „alergeny“ se chová tak, že výběr položky „buráky“ + znamená vyloučení + všech produktů vztahujících se k burákům z výběru. Popřípadě možnost definovat, že u reference typu „štítky“ se + jednotlivé entity kombinují + logickým AND – tedy že zaškrtnutí štítků „novinka“ a „skladem“, které jsou ve stejné logické skupině + znamená, že se vyberou produkty, které jsou na skladě a zároveň se jedná o novinky. Tyto vztahy mají dopad jak + na chování podmínky `facetHaving` uvnitř `filterBy` bloku, tak na chování výpočtu v rámci `facetSummary`. +

+

+ Výchozí chování `facetSummary`, kdy se vypočtou všechny údaje pro úplnou sadu referencí označenou jako + `faceted`, je na řadě míst nežádoucí, protože dává příliš velký výsledek. Výpočet je tedy možné omezit + pouze na určité typy referencí nebo v rámci konkrétního typu reference omezit pouze na entity, které splňují + určitou podmínku. Toto chování si můžeme ukázat na příkladu hodnot parametrů (např. červená), které spadají do + parametrů (např. barva). Produkt má obvykle celou sadu parametrů, ale pouze podle některých má smysl filtrovat. + Můžeme si tedy na úrovni parametru vést informaci o tom, zda má být daný parametr zahrnutý do filtru či slouží + pouze k zobrazení dat na detailu produktu. Udělejme to pomocí jednoduchého boolean atributu `isVisibleInFilter`, + který bude nastaven na `true` u těch parametrů, které mají být v nabídce uživatelského filtru a upravme dotaz + následovně: +

+ +
query(
+  collection("Product"),
+  filterBy(
+    attributeEquals("status", "ACTIVE"),
+    userFilter(
+      facetHaving(
+        "groups",
+        entityHaving(
+          attributeEquals("code", "sale")
+        )
+      )
+    )
+  ),
+  require(
+    facetSummaryOfReference(
+      "parameterValues",
+      IMPACT,
+      filterGroupBy(
+        attributeEquals("isVisibleInFilter", true)
+      ),
+      entityFetch(
+        attributeContent("code")
+      ),
+      entityGroupFetch(
+        attributeContent("code")
+      )
+    )
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Vidíme, že ve výsledku dotazu zbyla pouze nabídka parametrů, která je ještě znatelně menší než nabídka původní. + Kromě filtrování obsahu parametrického filtru je možné nabídku položek i seřadit. + V rámci načítání entity parametrického filtru samozřejmě funguje i načítání grafu do hloubky, takže ke každé + skupině či odkazované entitě si můžete načíst všechna potřebná data v rámci jednoho dotazu. +

+ +

Histogramy

+ +

+ Histogramy se občas používají pro vizualizaci rozložení hodnot s velkou kardinalitou na omezené ploše. V praxi + se příliš nevídají, ačkoliv jsou šikovnou pomůckou uživateli při výběru v intervalovém filtru. +

+

+ V rámci evitaDB query si můžeme aktuálně říci o výpočet histogramu pro libovolný filtrovatelný atribut číselného + typu, ale v blízké budoucnosti plánujeme rozšíření i o výpočet + histogramu přes reference. O kalkulaci histogramu pro atribut si říkáme následujícím způsobem: +

+ +
query(
+  collection("Product"),
+  filterBy(
+    priceValidInNow(),
+    priceInPriceLists("basic"),
+    priceInCurrency("EUR"),
+    userFilter(
+      priceBetween(100, 2000),
+      attributeBetween(
+        "battery-capacity", 2000, 6000
+      )
+    )
+  ),
+  require(
+    priceHistogram(30),
+    attributeHistogram(30, "battery-capacity")
+  )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ V bloku `require` si požádáme o výpočet `priceHistogram` a `attributeHistogram` s uvedením počtu požadovaných + sloupců pro výstupní histogram a v případě atributu i o jeho název. Blok `filterBy` opět obsahuje systémovou a + uživatelskou podmínku. Uživatelská část podmínky obsahuje rozsah stanovený uživatelem, které mají být vzaty v + potaz při výběru odpovídajících entit. +

+

+ Výstupní kalkulaci si opět představíme ve formě vizualizace, kterou nám nabízí nástroj evitaLab: +

+

+ + Vizualizace histogramu v evitaLab + +

+

+ Vrácená data nám umožňují vykreslit histogram s četnostmi produktů v rámci různých cenových hladin a číselné + hodnoty kapacity baterie. Při výpočtu histogramu se bere v potaz celý dotaz vyjma podmínky týkající se daného + atributu / ceny v uživatelské části filtrovací podmínky (`userFilter`). Pokud by tomu tak nebylo, uživatel by + nikdy nebyl schopný zase rozšířit svůj původní výběr. Součástí vypočtených sloupců je i informace, jestli daný + sloupec nebo jeho část byla součástí uživatelského filtru či nikoliv, což umožňuje vizuálně odlišit část + histogramu reprezentovanou současným výběrem produktů. +

+

+ Standardně databáze vrací počet sloupců přesně odpovídající hodnotě požadované v klauzuli histogramu. V rámci + uživatelského testování se ovšem ukázalo, že u menšího počtu hodnot lépe funguje tzv. adaptivní přístup, kdy je + počet sloupců přizpůsoben datům. Mějme hypotetickou situaci, kdy chceme vizualizovat histogram se 100 sloupci, + ale současnému dotazu odpovídají pouze nízké jednotky položek – např. dvě. Pak bychom měli histogram, kde by + byly pouze dva sloupce, a to první a poslední, a mezi nimi by byl prázdný prostor. +

+

+ Tento výstup jednak nevypadá vizuálně dobře a často se kvůli šířce sloupců špatně vybírá ten správný rozsah. + Proto můžete v histogramu požádat o tzv. „optimální“ výstup, který zaručuje, že nikdy nebude vrácen větší počet + sloupců než jste požádali, ale v případě velkých mezer mezi sloupci histogramu bude jejich počet snížen tak, aby + mezera nebyla širší než jeden sloupec +

+ +

Hierarchické struktury

+ +

+ Valná většina katalogů pohlíží na položky skrze hierarchicky organizované menu kategorií různého druhu typicky + tak, že zobrazuje položky z kategorie, kterou má uživatel vybranou, a zároveň i ze všech podkategorií této + kategorie. Vzhledem k tomu, že se jedná o tak běžný scénář, má evitaDB pro tuto oblast celou sadu výrazových + prostředků a zároveň optimalizuje své indexy tak, aby dotazy do hierarchické struktury byly rychlejší, než + dotazy bez tohoto zacílení. +

+

+ V našich příkladech budeme vycházet z následující struktury kategorií, které můžete nalézt i v naší ukázkové + datové sadě: +

+

+ + Ukázková hierarchie kategorií + +

+

+ Ukažme si nejprve úplně typický příklad dotazu, který vypíše všechny produkty z kategorie Accessories + (Příslušenství): +

+ + +
query(
+    collection("Product"),
+    filterBy(
+        hierarchyWithin(
+            "categories",
+            attributeEquals("code", "accessories")
+        )
+    ),
+    require(
+        entityFetch(
+            attributeContent("code")
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Dotaz vyhledá všechny záznamy z kolekce produktů, které mají referenci s názvem `categories` odkazující se na + entitu s kódem `accessories`. Ze schématu se dozvíme, že reference `categories` cílí na entitu s názvem + `Category`, která je označena jako hierarchická. Pokud by nebyla, evitaDB by u tohoto typu dotazu vrátila chybu. + Z této informace si evitaDB odvodí, že chcete vrátit všechny kódy produktů v kategorii `accessories` a všech + jejích podřízených kategorií. Samozřejmě je možné dotaz upravit tak, že se zobrazí jen produkty v kategorii + přímo zařazené nebo si vylistovat nikoliv seznam produktů, ale přímo podkategorií dané + kategorie. V dokumentaci najdete + ještě řadu dalších možností. +

+

+ Zajímavé jsou především podřízené podmínky `having` + a `excluding`. + Ty umožňují při procházení hierarchie (tj. stromu kategorií) některé části (podstromy) vynechat. Občas jste si + mohli všimnout, že v nákupních domech je určitá část regálů za plentou – protože se připravuje nový prodejní + prostor se specializovanou nabídkou. Obdobně i v katalozích se často připravují nové části, do kterých mají + přístup pouze zaměstnanci, kteří na nich pracují. Tyto funkce nám podobné scénáře umožňují řešit celkem + jednoduše: +

+ +
query(
+    collection("Product"),
+    filterBy(
+        hierarchyWithin(
+            "categories",
+            attributeEquals("code", "accessories"),
+            excluding(
+                attributeEquals("code", "wireless-headphones")
+            )
+        )
+    ),
+    require(
+        entityFetch(
+            attributeContent("code")
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Výše uvedený dotaz simuluje podobný případ – jako návštěvník vidím v kategorii `accessories` všechny produkty, + které do ní patří vyjma těch, které jsou zařazeny do podstromu kategorie `wireless-headphones`. Uživatel + vystupující jako zaměstnanec, by danou podmínku v dotazu neměl, a tudíž by viděl i za zmíněnou hypotetickou + „plentu“. Samozřejmě můžeme celý problém ještě o něco více zobecnit a umožnit uživatelům vidět např. všechny + produkty z kategorií, které mají hodnotu atributu `access` nastavenou na `PUBLIC` atp. +

+

+ Podobně elegantním způsobem se dají řešit i časově omezené nabídky. Dejme tomu, že v kategorii příslušenství si + chceme dopředu připravit „Vánoční nabídku“, která obsahuje LED osvětlení vánočních stromků, pyrotechniku a + podobně. Pokud v entitě kategorie vytvoříme atribut typu `DateTimeRange` s názvem `validity` a nastavíme jeho + hodnotu pouze na vánoční období, můžeme potom definovat následující dotaz: +

+ +
query(
+    collection("Product"),
+    filterBy(
+        hierarchyWithin(
+            "categories",
+            attributeEquals("code", "accessories"),
+            having(
+                or(
+                    attributeIsNull("validity"),
+                    attributeInRangeNow("validity")
+                )
+            )
+        )
+    ),
+    require(
+        entityFetch(
+            attributeContent("code")
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Tedy: vypiš mi všechny produkty z kategorie `accessories` za předpokladu, že jsou zařazeny v kategorii bez + definované platnosti (`validity`) nebo mají definovaný rozsah platnosti, do které spadá současný okamžik. +

+

+ Některé položky bývají zařazeny v různých kategoriích – např. žvýkačky v obchodech uvidíte v sekci „sladkosti“, + ale také před pokladnami mezi produkty, na které máte dost času se dívat než zaplatíte. Pokud obchodní dům + oplotí sekci sladkostí, protože je předělává do nové podoby, měli byste přestat mít možnost koupit žvýkačky u + pokladny? Jistěže ne. Stejně se zachová i evitaDB a pokud nalezne alespoň jednu referenci produktu do viditelné + části hierarchického stromu, zahrne tento produkt do výsledků vyhledávání. +

+ +

Transpozice hierarchie

+ +

+ Tím však možnosti hierarchického vyhledávání nekončí. Kromě výpisu záznamů náležejících do konkrétního místa + stromu běžně potřebujeme současně tuto hierarchickou strukturu vizualizovat v podobě nějakého menu. Bohužel + neexistuje nic jako „univerzální menu“ – možností jak pohlížet a vizualizovat hierarchické struktury je celá + řada. Oblíbená jsou třeba „mega-menu“: +

+

+ + Mega menu + +

+

+ Běžně také vidíme jednoduchý výpis nejbližších podřízených kategorií: +

+

+ + Prostý výpis podřízených kategorií + +

+

+ Či plně dynamická rozklikávací menu: +

+

+ + Rozklikávací menu + +

+

+ Až po různá hybridní řešení, kdy se zobrazují třeba jen kategorie první úrovně a cesta k aktuálně vybrané + kategorii se zobrazením kategorií stejné úrovně, jako třeba na následujícím obrázku: +

+

+ + Hybridní levé menu + +

+

+ Zcela běžně na stejné stránce potkáte i více různých druhů menu najednou – např. mega-menu, výpis nejbližších + podřízených kategorií a levé vertikální menu současně. +

+

+ Otázka tedy zní, jak získat všechny potřebné údaje pro zobrazení menu souvisejících s aktuálním výpisem položek + z daného místa hierarchie a příliš nekomplikovat dotazovací jazyk? +

+

+ Pro tyto účely evitaDB využívá možnosti bloku `require`, který dovoluje výpočet přidružených kalkulací + souvisejících se základním dotazem. V rámci tohoto bloku je možné nechat si vypočítat všechny + potřebné podklady pro to, abychom dokázali sestavit taková menu, jaká budeme potřebovat. Stačí vytvořit + požadavek na vytvoření daného řezu hierarchií, pojmenovat si ho a pak si už jen vyzvednout výsledek kalkulace ve + výsledných datech. Pro demonstraci si pojďme ukázat, jak by mohla vypadat kalkulace hybridního menu: +

+ + +
query(
+    collection("Product"),
+    filterBy(
+        hierarchyWithin(
+            "categories",
+            attributeEquals("code", "audio")
+        )
+    ),
+    require(
+        hierarchyOfReference(
+            "categories",
+            fromRoot(
+                "topLevel",
+                entityFetch(attributeContent("code")),
+                stopAt(level(1))
+            ),
+            parents(
+                "parents",
+                entityFetch(attributeContent("code"))
+            ),
+            siblings(
+                "siblings",
+                entityFetch(attributeContent("code"))
+            )
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Tento dotaz kromě produktů vrátí i 3 složky dodatečné kalkulace. Kalkulace `topLevel` obsahuje hierarchické + záznamy propojené s vypsanými produkty na kořenové úrovni. Kalkulace `parents` vypíše osu nadřízených + hierarchických záznamů vůči záznamu `audio`, na který cílí dotaz pro výpis produktů, a nakonec kalkulace + `siblings` vypíše osu sousedních hierarchických záznamů (tj. záznamů sdílejících stejného rodiče jako záznam + `audio`). Z těchto dat je pak možné poměrně jednoduše vytvořit kombinované hybridní menu. Záměrně je vybraný + jeden ze složitějších případů užití, aby bylo možné demonstrovat kombinace různých řezů hierarchií. Vytvoření + megamenu je podstatně jednodušší záležitostí. +

+ +
query(
+    collection("Product"),
+    require(
+        hierarchyOfReference(
+            "categories",
+            fromRoot(
+                "megaMenu",
+                entityFetch(attributeContent("code")),
+                stopAt(level(2))
+            )
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Tip: když si tento dotaz vyzkoušíte v evitaLab + a přepnete záložku výsledků na vizualizaci, uvidíte fragmenty menu v mnohem srozumitelnější podobě. +

+

+ Ke každé položce hierarchického menu je možné si nechat vypočítat + následující údaje: +

+
    + +
  1. Počet podřízených hierarchických úrovní. + +
  2. Počet záznamů výpisu, které se vztahují k danému hierarchickému záznamu. +
  3. +
+

+ Jedná se o prostá čísla, která napoví, jestli dává smysl danou kategorii otevřít, i když jsme si v rámci + kalkulací nenechali tyto části stromu vypsat, protože je nutně nepotřebujeme. +

+ + +
query(
+    collection("Product"),
+    require(
+        hierarchyOfReference(
+            "categories",
+            fromRoot(
+                "megaMenuWithCounts",
+                entityFetch(attributeContent("code")),
+                stopAt(level(2)),
+                statistics(
+                    CHILDREN_COUNT,
+                    QUERIED_ENTITY_COUNT
+                )
+            )
+        )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Čísla korektně reflektují podmínky stanovené ve filtrační části dotazu – pokud jsou tedy některé podstromy + podmínkou vyloučeny, nebudou započteny do těchto součtů ani přímo (tj. na úrovni počtu podřízených + hierarchických úrovní) ani transitivně (tj. položky do nich zařazené se nezapočítají do počtu záznamů v dané + části stromu). Položky zařazené do stromu se načítají očekávaným způsobem – tedy pro strom: +

+

+ + Ukázkový strom kategorií + +

+

+ Počet položek zařazených do stromu `Portables` tvoří součet položek zařazených do třech podřízených kategorií + plus počet položek zařazených přímo do kategorie `Portables`. Pokud je některá z položek zařazena zároveň do + více kategorií (např. do `Tablets` a `E-readers` zároveň) je do součtu zahrnuta pouze jednou. +

+

Nalezení prodejní ceny

+ + +

+ Stanovení prodejní ceny je potřeba pouze pro třídění položek podle ceny (od nejdražší / nejlevnější) a pro + nalezení položek v určité cenové hladině. Pokud u svého katalogu tuto funkcionalitu nepotřebujete, celá tato + kapitola se vás netýká. +

+

+ Určení prodejní ceny může být v B2C segmentu velmi přímočaré – tyto katalogy si často drží jen jedinou prodejní + cenu či cenu akční. V B2B segmentu je naopak cenotvorba velmi pestrá a různé ERP systémy, které bývají primárním + zdrojem cen, přistupují k tvorbě prodejní ceny odlišně. Proto evitaDB obsahuje velmi jednoduchý algoritmus pro + výpočet prodejní ceny, který jednak umožňuje tuto cenu spočítat relativně rychle a zároveň umožňuje tyto + složitější algoritmy do tohoto zjednodušeného přístupu převést. +

+

+ Každá položka katalogu může mít jednu i více cen v různých měnách, přiřazené k různým ceníkům. Při vyhledávání + ceny se potom hledá první cena, která odpovídá kombinaci požadované měny a sady ceníků v pořadí dle důležitosti + (tj. pořadí ceníků v položeném dotazu hraje klíčovou roli). Pojďme si hned jeden takový dotaz ukázat: +

+ +
query(
+    collection("Product"),
+    filterBy(
+        priceInPriceLists("management-price", "employee-basic-price", "basic"),
+        priceInCurrency("EUR")
+    ),
+    require(
+      entityFetch(
+        attributeContent("code"),
+        priceContentRespectingFilter()
+      )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Pro tento dotaz se algoritmus bude nejdříve snažit u každé položky najít cenu v měně EUR v ceníku + `management-price`, a pokud ji nenajde, zkusí ji najít v ceníku `employee-basic-price`. Pokud nebude ani zde, + vyzkouší ještě ceník `basic`. Pokud nenajde žádnou cenu, produkt ve výsledné sadě nebude. Algoritmus je velmi + jednoduchý, ale doposud se nám vždy podařilo najít způsob, jak na něj cenové politiky na straně zákazníka + převést. Často to ovšem vyžaduje předpočítání cen, které na straně ERP neexistují (protože se počítají + dynamicky) a trochu kreativity. Stále + zvažujeme přínosy možných rozšíření algoritmu, ale zároveň se nechceme připravit o stávající jednoduchost a + pochopitelnost. +

+

+ Dalším faktorem, který ve výpočtu ceny často hraje roli, je časové hledisko. Na úrovni ceny je možné stanovit + její časovou platnost a do filtračního bloku přidat `priceValidIn` + podmínku, která v daném časovém okamžiku neplatné ceny vyloučí. +

+

+ Simulace výpočtu je dostupná i v našem nástroji evitaLab. Pokud si zobrazíte + tabulku entit, které obsahují ceny (v případě demo datasetu se jedná o entitu `Product`), můžete se + prokliknutím buňky s cenou produktu dostat do podrobnějšího výpisu všech cen produktu. V tom můžete filtrovat + podle ceníku a měny, což vám umožňuje i náhled výpočtu prodejní ceny v různých situacích, a tudíž i možnost se s + principy výpočtu seznámit blíže: +

+

+ + Výpis cen cen v tabulce + +

+

+ Výpis produktů je možné také podle prodejní ceny filtrovat. Typicky chceme mít možnost vylistovat pouze + produkty, které lze koupit v cenovém rozpětí, na které máme připravené finanční prostředky. Podobný dotaz včetně + třídění produktů dle prodejní ceny vzestupně (od nejlevnějšího k nejdražšímu) by tedy vypadal takto: +

+ + +
query(
+    collection("Product"),
+    filterBy(
+        priceInPriceLists("management-price", "employee-basic-price", "basic"),
+        priceInCurrency("EUR"),
+        userFilter(
+           priceBetween(100.0, 125.0)
+        )
+    ),
+    orderBy(
+      priceNatural(ASC)
+    ),
+    require(
+      entityFetch(
+        attributeContent("code"),
+        priceContentRespectingFilter()
+      )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ V dotazu vidíte typické použití, kdy podmínka `priceBetween` je umístěna v kontejneru `userFilter` a to proto, + že argumenty této podmínky ovlivňuje uživatel svým zásahem a mohou být za určitých podmínek „porušeny“, kdežto + podmínky ležící mimo tento kontejner porušeny být nikdy nesmí. K porušení podmínek dochází například v případě + výpočtu `facetSummary`, kdy není vhodné, aby nastavení cenového rozmezí ovlivňovalo výpočet základního počtu + produktů pro jednotlivé vlastnosti. +

+

+ Při výpočtu prodejní ceny se standardně používá cena s daní. V případě B2B segmentu je však vhodné pracovat s + cenami bez daně, protože plátce DPH zajímá právě tato cena. Přepnutí výpočtu na ceny bez DPH se provádí pomocí + `require` požadavku `priceType`. +

+ +

Výpočet ceny pro virtuální produkty s agregovanými cenami

+ +

Základní produkty

+ +

+ V prostředí e-commerce se běžně setkáváme s tzv. základními produkty (často také nazývanými mateřské, primární + či v angličtině master / basic / parent), které zastřešují sadu variantních produktů. Typickým příkladem mohou + být trička v módním katalogu, která se vyrábí v různých velikostech či barevných odstínech, a přesto se jedná o + stejná trička se společným motivem. Protože by byl výpis produktů v tomto případě velmi nepřehledný seskupují se + tyto variantní produkty do jednoho společného (zastřešujícího), nicméně virtuálního produktu, který je ve + výpisech zastupuje (byť se sám o sobě nedá koupit). +

+

+ V tomto případě potřebujeme ze všech prodejních cen variantních produktů vybrat jednu z cen, která bude + zastupovat celou sadu. Výběr jediné ceny je nutný z toho důvodu, aby bylo možné produkt společně s ostatními + řadit podle prodejní ceny nebo podle prodejní ceny filtrovat. +

+

+ Tuto úlohu modelujeme tak, že k záznamu virtuálního základního produktu přiřadíme ceny všech jeho variantních + produktů a použijeme pole `innerRecordId` pro odlišení sad cen jedné varianty od cen varianty druhé. Virtuálnímu + produktu je dále nutné nastavit režim výpočtu ceny na `FIRST_OCCURRENCE`. Tato kombinace způsobí, že pro daný + produkt se nejprve vypočítají prodejní ceny pro variantní produkty (tj. separátně pro každou shodnou hodnotu + `innerRecordId`) a následně se vybere nejnižší z těchto prodejních cen, která se stane cenou prodejní pro + zastupující virtuální produkt. Drobně odlišné chování bude v případě použití `priceBetween` podmínky, kdy dojde + před volbou finální ceny k vyfiltrování prodejních cen variantních produktů podle zvoleného rozsahu a teprve + potom výběr nejnižší ceny pouze z těch, které zbyly. Tj. z pohledu uživatele dojde k nalezení virtuálního + produktu, pokud alespoň jednu z jeho variant lze v požadovaném cenovém rozsahu koupit a tento produkt bude + následně označen právě touto nejnižší cenou z požadovaného cenového rozsahu. +

+

+ Způsob dotazování je samozřejmě shodný – změněný způsob výpočtu je daný nastavením údajů na dané entitě. + Následující dotaz cílí na produkty, u kterých víme, že se jedná o základní produkty a můžeme tak lépe + experimentovat s odlišným výpočtem: +

+ +
query(
+    collection("Product"),
+    filterBy(
+        attributeEquals("productType", "MASTER"),
+        priceInPriceLists("management-price", "employee-basic-price", "basic"),
+        priceInCurrency("EUR"),
+        userFilter(
+           priceBetween(100.0, 125.0)
+        )
+    ),
+    require(
+      entityFetch(
+        attributeContent("code"),
+        priceContentRespectingFilter()
+      )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

+ Poznámka: do budoucna plánujeme ještě plnohodnotnou podporu seskupování (groupBy) na základě + některých atributů entity. Ta by měla umožnit řešit úlohu s variantními produkty ještě jiným způsobem, který + má zároveň další pozitivní dopady na problematiku parametrického (facetového) filtrování. +

+ +

Produktové sady (komplety)

+ +

+ Existuje ještě další druh virtuálních produktů a to jsou produkty, které se skládají z více položek + (pod-produktů) a jsou oceňovány zvlášť. Příkladem může být skříňka, která se skládá z korpusu, dvířek, pantů a + madel. Cena skříňky se pak skládá ze součtu cen všech těchto částí, přičemž v B2B prostředí může být tato cena + vypočtená různě pro různé zákazníky. Například zákazník „A“ má 30% slevu na madla a panty, kdežto zákazník „B“ + 15% slevu na korpus. Vzhledem k různorodým slevám na různé části není možné vypočítat všechny kombinace slev + dopředu a je nutné finální prodejní cenu počítat v reálném čase unikátně pro každého ze zákazníků. +

+

+ Způsob práce s cenami je podobný tomu pro „základní produkty“ popsané v minulé kapitole. Na úrovni virtuálního + kompletu jsou evidované ceny všech jeho částí, které se od sebe odlišují identifikátorem v `innerRecordId` ceny. + Nicméně na úrovni entity je nastavena výpočetní strategie `SUM`. Pro tyto případy pak postupuje algoritmus tak, + že nejdříve vypočte prodejní ceny pro každou z jeho částí dle `innerRecordId`, následně všechny prodejní ceny + sečte a tím dojde k výsledné prodejní ceně celého kompletu, která se používá pro následné třídění a filtrování + produktů dle ceny. +

+

+ Následujícím dotazem si můžete toto chování sami vyzkoušet: +

+ +
query(
+    collection("Product"),
+    filterBy(
+        attributeEquals("productType", "SET"),
+        priceInPriceLists("management-price", "employee-basic-price", "basic"),
+        priceInCurrency("EUR"),
+        userFilter(
+           priceBetween(100.0, 125.0)
+        )
+    ),
+    require(
+      entityFetch(
+        attributeContent("code"),
+        priceContentRespectingFilter()
+      )
+    )
+)
+
+

+ Vyzkoušejte + si dotaz v evitaLab +

+ +

Závěr

+ +

+ Celým dotazovacím jazykem se prolíná myšlenka získat jediným dotazem všechna data potřebná pro zpracování + uživatelského scénáře. Čím méně dotazů, tím menší daň bude nutné zaplatit ve fixních nákladech za uskutečněné + požadavky na databázový server (režie na zpracování HTTP požadavku jako takového). Zároveň databáze vidí mnohem + širší kontext a umožňuje jí to lépe optimalizovat provedení dotazu a znovu použít již vypočtené mezivýsledky při + zpracování dotazu. +

+

+ Ačkoliv byla tato kapitola celkem dlouhá, je patrné, že dotazovací jazyk není tak bohatý jako jazyk SQL, ale + pokrývá základní functionality, které budete pro vývoj katalogového systému potřebovat. V budoucnosti chceme + přidat alespoň základní podporu pro prostorové + dotazy, které by nám dovolily vyhledávat body zájmu v prostoru (například výdejnomaty v oblasti). Stejně tak + plánujeme podporu fulltextového vyhledávání. Pokud + máte v dané oblasti expertízu a chtěli byste nám ve vývoji pomoci, ozvěte se nám na našem Discord kanálu – jakoukoliv pomoc či konzultace s radostí uvítáme. +

+

+ V dalším dílu našeho seriálu si povíme o webových API (GraphQL, REST, gRPC), které databáze automaticky + vystavuje, a které můžete využít při vývoji svých aplikací. Věříme, že po přečtení dalšího dílu a vyzkoušení + těchto API pochopíte hlouběji, proč je dotazovací jazyk designován takovým způsobem, jakým je. +

+ +
+ + \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/category-listing.png b/documentation/publishing/root.cz/03-query-basics/category-listing.png new file mode 100644 index 000000000..24807d9c1 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/category-listing.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/deep-fetch-filtering-and-sorting.evitaql b/documentation/publishing/root.cz/03-query-basics/deep-fetch-filtering-and-sorting.evitaql new file mode 100644 index 000000000..243b1033b --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/deep-fetch-filtering-and-sorting.evitaql @@ -0,0 +1,37 @@ +query( + collection("Product"), + filterBy( + entityPrimaryKeyInSet(103885) + ), + require( + entityFetch( + referenceContentWithAttributes( + "parameterValues", + filterBy( + entityHaving( + referenceHaving( + "parameter", + entityHaving( + attributeContains("code", "r") + ) + ) + ) + ), + orderBy( + entityProperty( + attributeNatural("code", DESC) + ) + ), + entityFetch( + attributeContent("code"), + referenceContentWithAttributes( + "parameter", + entityFetch( + attributeContent("code") + ) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/deep-fetch.evitaql b/documentation/publishing/root.cz/03-query-basics/deep-fetch.evitaql new file mode 100644 index 000000000..354b30afe --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/deep-fetch.evitaql @@ -0,0 +1,24 @@ +query( + collection("Product"), + filterBy( + entityPrimaryKeyInSet(103885), + entityLocaleEquals("cs") + ), + require( + entityFetch( + attributeContent("name"), + referenceContentWithAttributes( + "parameterValues", + entityFetch( + attributeContent("code", "name"), + referenceContentWithAttributes( + "parameter", + entityFetch( + attributeContent("code", "name") + ) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/dynamic-menu.png b/documentation/publishing/root.cz/03-query-basics/dynamic-menu.png new file mode 100644 index 000000000..a215b90af Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/dynamic-menu.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/erd.png b/documentation/publishing/root.cz/03-query-basics/erd.png new file mode 100644 index 000000000..3b4d9cd22 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/erd.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.evitaql b/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.evitaql new file mode 100644 index 000000000..a645fa0e1 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.evitaql @@ -0,0 +1,25 @@ +query( + collection("Product"), + filterBy( + attributeEquals("status", "ACTIVE"), + userFilter( + facetHaving( + "groups", + entityHaving( + attributeEquals("code", "sale") + ) + ) + ) + ), + require( + facetSummary( + IMPACT, + entityFetch( + attributeContent("code") + ), + entityGroupFetch( + attributeContent("code") + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.png b/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.png new file mode 100644 index 000000000..0f7c22e44 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/facet-summary-impact.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/facet-summary-of-reference.evitaql b/documentation/publishing/root.cz/03-query-basics/facet-summary-of-reference.evitaql new file mode 100644 index 000000000..7a1c45d96 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/facet-summary-of-reference.evitaql @@ -0,0 +1,29 @@ +query( + collection("Product"), + filterBy( + attributeEquals("status", "ACTIVE"), + userFilter( + facetHaving( + "groups", + entityHaving( + attributeEquals("code", "sale") + ) + ) + ) + ), + require( + facetSummaryOfReference( + "parameterValues", + IMPACT, + filterGroupBy( + attributeEquals("isVisibleInFilter", true) + ), + entityFetch( + attributeContent("code") + ), + entityGroupFetch( + attributeContent("code") + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/facet-summary.evitaql b/documentation/publishing/root.cz/03-query-basics/facet-summary.evitaql new file mode 100644 index 000000000..35b74fede --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/facet-summary.evitaql @@ -0,0 +1,25 @@ +query( + collection("Product"), + filterBy( + attributeEquals("status", "ACTIVE"), + userFilter( + facetHaving( + "groups", + entityHaving( + attributeEquals("code", "sale") + ) + ) + ) + ), + require( + facetSummary( + COUNTS, + entityFetch( + attributeContent("code") + ), + entityGroupFetch( + attributeContent("code") + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/facet-summary.png b/documentation/publishing/root.cz/03-query-basics/facet-summary.png new file mode 100644 index 000000000..ebc622a93 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/facet-summary.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-dataset.png b/documentation/publishing/root.cz/03-query-basics/hierarchy-dataset.png new file mode 100644 index 000000000..10d2e043a Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/hierarchy-dataset.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-mega-menu.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-mega-menu.evitaql new file mode 100644 index 000000000..784661734 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-mega-menu.evitaql @@ -0,0 +1,13 @@ +query( + collection("Product"), + require( + hierarchyOfReference( + "categories", + fromRoot( + "megaMenu", + entityFetch(attributeContent("code")), + stopAt(level(2)) + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-of-reference.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-of-reference.evitaql new file mode 100644 index 000000000..05609d734 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-of-reference.evitaql @@ -0,0 +1,27 @@ +query( + collection("Product"), + filterBy( + hierarchyWithin( + "categories", + attributeEquals("code", "audio") + ) + ), + require( + hierarchyOfReference( + "categories", + fromRoot( + "topLevel", + entityFetch(attributeContent("code")), + stopAt(level(1)) + ), + parents( + "parents", + entityFetch(attributeContent("code")) + ), + siblings( + "siblings", + entityFetch(attributeContent("code")) + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-statistics.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-statistics.evitaql new file mode 100644 index 000000000..a8ca28ee3 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-statistics.evitaql @@ -0,0 +1,17 @@ +query( + collection("Product"), + require( + hierarchyOfReference( + "categories", + fromRoot( + "megaMenuWithCounts", + entityFetch(attributeContent("code")), + stopAt(level(2)), + statistics( + CHILDREN_COUNT, + QUERIED_ENTITY_COUNT + ) + ) + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-within-excluding.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-within-excluding.evitaql new file mode 100644 index 000000000..a3c4d5e70 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-within-excluding.evitaql @@ -0,0 +1,17 @@ +query( + collection("Product"), + filterBy( + hierarchyWithin( + "categories", + attributeEquals("code", "accessories"), + excluding( + attributeEquals("code", "wireless-headphones") + ) + ) + ), + require( + entityFetch( + attributeContent("code") + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-within-having.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-within-having.evitaql new file mode 100644 index 000000000..3d8fbb12c --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-within-having.evitaql @@ -0,0 +1,20 @@ +query( + collection("Product"), + filterBy( + hierarchyWithin( + "categories", + attributeEquals("code", "accessories"), + having( + or( + attributeIsNull("validity"), + attributeInRangeNow("validity") + ) + ) + ) + ), + require( + entityFetch( + attributeContent("code") + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/hierarchy-within.evitaql b/documentation/publishing/root.cz/03-query-basics/hierarchy-within.evitaql new file mode 100644 index 000000000..f26661c38 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/hierarchy-within.evitaql @@ -0,0 +1,14 @@ +query( + collection("Product"), + filterBy( + hierarchyWithin( + "categories", + attributeEquals("code", "accessories") + ) + ), + require( + entityFetch( + attributeContent("code") + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/histogram.evitaql b/documentation/publishing/root.cz/03-query-basics/histogram.evitaql new file mode 100644 index 000000000..09109408a --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/histogram.evitaql @@ -0,0 +1,18 @@ +query( + collection("Product"), + filterBy( + priceValidInNow(), + priceInPriceLists("basic"), + priceInCurrency("EUR"), + userFilter( + priceBetween(100, 2000), + attributeBetween( + "battery-capacity", 2000, 6000 + ) + ) + ), + require( + priceHistogram(30), + attributeHistogram(30, "battery-capacity") + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/histogram.png b/documentation/publishing/root.cz/03-query-basics/histogram.png new file mode 100644 index 000000000..77fc42816 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/histogram.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/hybrid-menu.png b/documentation/publishing/root.cz/03-query-basics/hybrid-menu.png new file mode 100644 index 000000000..f6df7988d Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/hybrid-menu.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/localization-all.evitaql b/documentation/publishing/root.cz/03-query-basics/localization-all.evitaql new file mode 100644 index 000000000..50a15a367 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/localization-all.evitaql @@ -0,0 +1,13 @@ +query( + collection("Product"), + filterBy( + entityPrimaryKeyInSet(103885, 103911, 105715) + ), + require( + entityFetch( + attributeContent("name", "descriptionShort"), + associatedDataContent("localization"), + dataInLocales("cs", "en") + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/localization.evitaql b/documentation/publishing/root.cz/03-query-basics/localization.evitaql new file mode 100644 index 000000000..0d5c77f57 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/localization.evitaql @@ -0,0 +1,16 @@ +query( + collection("Product"), + filterBy( + entityPrimaryKeyInSet(103885, 103911, 105715), + entityLocaleEquals("cs") + ), + orderBy( + attributeNatural("name", DESC) + ), + require( + entityFetch( + attributeContent("name", "descriptionShort"), + associatedDataContent("localization") + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/megamenu.png b/documentation/publishing/root.cz/03-query-basics/megamenu.png new file mode 100644 index 000000000..66a1e5da7 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/megamenu.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/mini-tree.png b/documentation/publishing/root.cz/03-query-basics/mini-tree.png new file mode 100644 index 000000000..328d7b1f3 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/mini-tree.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/price-between.evitaql b/documentation/publishing/root.cz/03-query-basics/price-between.evitaql new file mode 100644 index 000000000..07cf8c81e --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/price-between.evitaql @@ -0,0 +1,17 @@ +query( + collection("Product"), + filterBy( + attributeEquals("productType", "MASTER"), + priceInPriceLists("management-price", "employee-basic-price", "basic"), + priceInCurrency("EUR"), + userFilter( + priceBetween(100.0, 125.0) + ) + ), + require( + entityFetch( + attributeContent("code"), + priceContentRespectingFilter() + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/price-filter.evitaql b/documentation/publishing/root.cz/03-query-basics/price-filter.evitaql new file mode 100644 index 000000000..123589f50 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/price-filter.evitaql @@ -0,0 +1,13 @@ +query( + collection("Product"), + filterBy( + priceInPriceLists("management-price", "employee-basic-price", "basic"), + priceInCurrency("EUR") + ), + require( + entityFetch( + attributeContent("code"), + priceContentRespectingFilter() + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/price-grid.png b/documentation/publishing/root.cz/03-query-basics/price-grid.png new file mode 100644 index 000000000..81adb82f9 Binary files /dev/null and b/documentation/publishing/root.cz/03-query-basics/price-grid.png differ diff --git a/documentation/publishing/root.cz/03-query-basics/price-master.evitaql b/documentation/publishing/root.cz/03-query-basics/price-master.evitaql new file mode 100644 index 000000000..07cf8c81e --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/price-master.evitaql @@ -0,0 +1,17 @@ +query( + collection("Product"), + filterBy( + attributeEquals("productType", "MASTER"), + priceInPriceLists("management-price", "employee-basic-price", "basic"), + priceInCurrency("EUR"), + userFilter( + priceBetween(100.0, 125.0) + ) + ), + require( + entityFetch( + attributeContent("code"), + priceContentRespectingFilter() + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/price-ordering.evitaql b/documentation/publishing/root.cz/03-query-basics/price-ordering.evitaql new file mode 100644 index 000000000..4f7e51df3 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/price-ordering.evitaql @@ -0,0 +1,19 @@ +query( + collection("Product"), + filterBy( + priceInPriceLists("management-price", "employee-basic-price", "basic"), + priceInCurrency("EUR"), + userFilter( + priceBetween(100.0, 125.0) + ) + ), + orderBy( + priceNatural(ASC) + ), + require( + entityFetch( + attributeContent("code"), + priceContentRespectingFilter() + ) + ) +) \ No newline at end of file diff --git a/documentation/publishing/root.cz/03-query-basics/price-set.evitaql b/documentation/publishing/root.cz/03-query-basics/price-set.evitaql new file mode 100644 index 000000000..501392ed1 --- /dev/null +++ b/documentation/publishing/root.cz/03-query-basics/price-set.evitaql @@ -0,0 +1,17 @@ +query( + collection("Product"), + filterBy( + attributeEquals("productType", "SET"), + priceInPriceLists("management-price", "employee-basic-price", "basic"), + priceInCurrency("EUR"), + userFilter( + priceBetween(100.0, 125.0) + ) + ), + require( + entityFetch( + attributeContent("code"), + priceContentRespectingFilter() + ) + ) +) \ No newline at end of file diff --git a/documentation/user/en/get-started/create-first-database.md b/documentation/user/en/get-started/create-first-database.md index 6cfd2306b..1569900b3 100644 --- a/documentation/user/en/get-started/create-first-database.md +++ b/documentation/user/en/get-started/create-first-database.md @@ -9,7 +9,7 @@ proofreading: 'done' preferredLang: 'java' --- - + We assume you already have the following snippet of the code from the [previous chapter](run-evitadb.md): @@ -20,9 +20,9 @@ We assume you already have the following snippet of the code from the [previous So the evitaDB instance is now up and running and ready to communicate. - +
- + We assume that you already have the following Docker image up and running from the [previous chapter](run-evitadb.md): @@ -40,26 +40,26 @@ docker run --name evitadb -i --rm -p 5555:5555 -p 5556:5556 -p 5557:5557 \ So the web API server is now up and running and ready to communicate. - +
- + ## Define a new catalog with a schema -Now you can use evita_api/src/main/java/io/evitadb/api/EvitaContract.java -EvitaDB.Client/EvitaClient.cs +Now you can use evita_api/src/main/java/io/evitadb/api/EvitaContract.java +EvitaDB.Client/EvitaClient.cs to define a new catalog and create predefined schemas for multiple collections: `Brand`, `Category` and `Product`. Each collection contains some attributes (either localized or non-localized), category is marked as a hierarchical entity that forms a tree, product is enabled to have prices: - + [Example of defining catalog and schema for entity collections](/documentation/user/en/get-started/example/define-catalog-with-schema.java) - +
- + ## Define a new catalog with a schema @@ -82,9 +82,9 @@ a tree, product is enabled to have prices: [Example of creating empty catalog](/documentation/user/en/get-started/example/define-schema-for-catalog.graphql)
-
+ - + ## Define a new catalog with a schema @@ -107,9 +107,9 @@ a tree, product is enabled to have prices: [Example of creating empty catalog](/documentation/user/en/get-started/example/define-schema-for-catalog.rest) - + - + ## Open session to catalog and insert your first entity @@ -120,9 +120,9 @@ Once the catalog is created and the schema is known, you can insert a first enti [Example of inserting an entity](/documentation/user/en/get-started/example/create-first-entity.java) -The session is implicitly opened for the scope of the `updateCatalog` method. The analogous method `queryCatalog` on -the evitaDB contract`UpdateCatalog` method. The analogous method `QueryCatalog` on -the evitaDB class level also opens a session, but only in read-only mode, which doesn't allow updating the catalog. +The session is implicitly opened for the scope of the `updateCatalog` method. The analogous method `queryCatalog` on +the evitaDB contract`UpdateCatalog` method. The analogous method `QueryCatalog` on +the evitaDB class level also opens a session, but only in read-only mode, which doesn't allow updating the catalog. Differentiating between read-write and read-only sessions allows evitaDB to optimize query processing and distribute the load in the cluster. @@ -133,8 +133,8 @@ Let's see how you can retrieve the entity you just created in another read-only [Example of reading an entity by primary key](/documentation/user/en/get-started/example/read-entity-by-pk.java) - - + + ## Open session to catalog and insert your first entity @@ -161,8 +161,8 @@ as mentioned above. [Example of reading an entity by primary key](/documentation/user/en/get-started/example/read-entity-by-pk.graphql) - - + + ## Open session to catalog and insert your first entity @@ -189,9 +189,9 @@ as mentioned above. [Example of reading an entity by primary key](/documentation/user/en/get-started/example/read-entity-by-pk.rest) - + - + ## Create a small dataset @@ -205,9 +205,9 @@ Once you learn the basics, you can create a small dataset to work with: That's a lot of code, but in reality you'd probably write a transformation function from the primary model you already have in the relational database. The example shows how to define attributes, associated data, references, and prices. - + - + ## List existing entities @@ -232,9 +232,9 @@ Or you can filter all products by price in EUR greater than €300 and order by [Example of filtering and ordering products by price](/documentation/user/en/get-started/example/filter-order-products-by-price.java) - + - + ## Update any of existing entities @@ -248,13 +248,13 @@ Updating an entity is similar to creating a new entity: The main difference is that you first fetch the entity with all the data you want to update from the evitaDB server and apply changes to it. The fetched entity is immutable, so you need to open it for writing first. This action creates a builder that wraps the original immutable object and allows the changes to be captured. These changes are eventually -collected and passed to the server in the "`upsertVia``UpsertVia` method. +collected and passed to the server in the "`upsertVia``UpsertVia` method. For more information, see the [write API description](../use/api/write-data.md#upsert). - + - + ## Update any of existing entities @@ -270,8 +270,8 @@ that mutate already existing data. For more information, see the [write API description](../use/api/write-data.md#upsert). - - + + ## Update any of existing entities @@ -287,62 +287,62 @@ that mutate already existing data. For more information, see the [write API description](../use/api/write-data.md#upsert). - + - + ## Delete any of existing entities You can delete entity by is primary key: - + [Example of deleting entity by PK](/documentation/user/en/get-started/example/delete-entity-by-pk.java) - - + + [Example of deleting entity by PK](/documentation/user/en/get-started/example/delete-entity-by-pk.cs) - + Or, you can issue a query that removes all the entities that match the query: - + [Example of deleting entity by query](/documentation/user/en/get-started/example/delete-entity-by-query.java) - - + + [Example of deleting entity by query](/documentation/user/en/get-started/example/delete-entity-by-query.cs) - + When you delete a hierarchical entity, you can choose whether or not to delete it with all of its child entities: - + [Example of deleting hierarchical entity](/documentation/user/en/get-started/example/delete-hierarchical-entity.java) - - + + [Example of deleting hierarchical entity](/documentation/user/en/get-started/example/delete-hierarchical-entity.cs) - + For more complex examples and explanations, see the [write API chapter](../use/api/write-data.md#removal). -
+ - + ## Delete any of existing entities @@ -356,8 +356,8 @@ would use to insert, update or retrieve entities: For more complex examples and explanations, see the [write API chapter](../use/api/write-data.md#removal). - - + + ## Delete any of existing entities @@ -378,13 +378,13 @@ would use to insert, update or retrieve entities: For more complex examples and explanations, see the [write API chapter](../use/api/write-data.md#removal). - + - + Creating new catalog in other APIs than Java, GraphQL and REST is being prepared. - + ## What's next? diff --git a/documentation/user/en/get-started/query-our-dataset.md b/documentation/user/en/get-started/query-our-dataset.md index 1d9ea0519..037559f35 100644 --- a/documentation/user/en/get-started/query-our-dataset.md +++ b/documentation/user/en/get-started/query-our-dataset.md @@ -1,8 +1,8 @@ --- title: Query our dataset perex: | - This article will show you how to connect to our demo instance or spin up a demo instance on your own hardware and - experiment with the evitaDB query language. + This article will show you how to connect to our demo instance or spin up a demo instance on your own hardware and + experiment with the evitaDB query language. date: '17.1.2023' author: 'Ing. Jan Novotný' proofreading: 'done' @@ -10,7 +10,7 @@ preferredLang: 'java' --- While it is much better to play with the schema and data that suits your own e-commerce use case, we believe that -many of you will want to test the Query API without too much work. Therefore, we have created a sample schema of +many of you will want to test the Query API without too much work. Therefore, we have created a sample schema of the virtual e-commerce store with data for more than a thousand products for you to play with right away. There are two ways in which you can play with this data set: @@ -20,17 +20,17 @@ There are two ways in which you can play with this data set: ## Use our evitaDB.io server instance -We host the demo dataset directly on the [evitadb.io](https://evitadb.io) site, but to make sure it works reliably for -all of you, we had to make it read-only. So you cannot make any changes to it. But you can still use it to test all our +We host the demo dataset directly on the [evitadb.io](https://evitadb.io) site, but to make sure it works reliably for +all of you, we had to make it read-only. So you cannot make any changes to it. But you can still use it to test all our web APIs and all supported drivers. -The next limitation is that the server is hosted on cheap shared infrastructure of -[Contabo hosting](https://contabo.com/en/vps/) (which has been known to buy old servers to provide low-cost hosting +The next limitation is that the server is hosted on cheap shared infrastructure of +[Contabo hosting](https://contabo.com/en/vps/) (which has been known to buy old servers to provide low-cost hosting services) with following specs: ![Server specs](assets/contabo-hosting.png) -If you experience slow responses, let us know and +If you experience slow responses, let us know and [try evitaDB on your hardware instead](#run-your-own-evitadb-server-with-our-dataset). You can access all our APIs on these addresses: @@ -43,7 +43,7 @@ You can access all our APIs on these addresses: ## Run your own evitaDB server with our dataset -This option requires more work, but you will have control over the performance, and you will be able to modify any data +This option requires more work, but you will have control over the performance, and you will be able to modify any data in the set. To access the dataset on your hardware, you need to: 1. [download the archive with the dataset](https://evitadb.io/download/evita-demo-dataset.zip) @@ -65,8 +65,8 @@ in the set. To access the dataset on your hardware, you need to: docker run --name evitadb -i --net=host \ -v "./data:/evita/data" \ index.docker.io/evitadb/evitadb:latest - - # there is open issue https://github.com/docker/roadmap/issues/238 for Windows / Mac OS + + # there is open issue https://github.com/docker/roadmap/issues/238 for Windows / Mac OS # and you need to open ports manually and propagate host IP address to the container docker run --name evitadb -i -p 5555:5555 -p 5556:5556 -p 5557:5557 \ -e "api.exposedOn=localhost" \ @@ -78,11 +78,11 @@ When this procedure is completed you should see the similar output in the consol ```plain - _ _ ____ ____ - _____ _(_) |_ __ _| _ \| __ ) - / _ \ \ / / | __/ _` | | | | _ \ + _ _ ____ ____ + _____ _(_) |_ __ _| _ \| __ ) + / _ \ \ / / | __/ _` | | | | _ \ | __/\ V /| | || (_| | |_| | |_) | - \___| \_/ |_|\__\__,_|____/|____/ + \___| \_/ |_|\__\__,_|____/|____/ alpha build 0.8.ALPHA Visit us at: https://evitadb.io @@ -125,21 +125,21 @@ Supply the certificate for production manually and set `useGeneratedCertificate` It means that your evitaDB server is up and running, and also that it has loaded the `evita` catalog dataset with some thousands of products. - + ## Connect the Java client Open your Java IDE and create an evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java instance: - + [Connect the demo server](/documentation/user/en/get-started/example/connect-demo-server.java) -After that you can create a new session and try any of the evitaQL queries described in +After that you can create a new session and try any of the evitaQL queries described in [the reference documentation](../query/basics.md): - + [Query the demo server](/documentation/user/en/get-started/example/query-demo-server.java) @@ -157,15 +157,15 @@ If you need more hints for querying the data, try [the query API chapter](../use - + - + ## Connect the C# client Open your .NET IDE and create an instance of EvitaDB.Client/EvitaClient.cs: - + [Connect the demo server](/documentation/user/en/get-started/example/connect-demo-server.cs) @@ -177,8 +177,8 @@ Open your .NET IDE and create an instance of EvitaDB.Client/EvitaCl -In the initialization process, the client needs to get `server-name` from evitaDB's *system* endpoint and in case of -usage of generated self-signed certificates, it needs to get the certificate from the server. Since both of these operations +In the initialization process, the client needs to get `server-name` from evitaDB's *system* endpoint and in case of +usage of generated self-signed certificates, it needs to get the certificate from the server. Since both of these operations are asynchronous in .NET, we decided to make the initialization process asynchronous as well. These asynchronous calls cannot be done in the constructor (without blocking the main application thread, which could cause serious problems in your application), so we decided to use static async method instead. @@ -204,9 +204,9 @@ For complete instructions on setting up a C# client, see [the C# drivers chapter If you need more hints for querying the data, try [the query API chapter](../use/query-api.md). - + - + ## Connect to the GraphQL API @@ -234,9 +234,9 @@ If you need more hints for querying the data, try [the query API chapter](../use - + - + ## Connect to the REST API @@ -264,4 +264,4 @@ If you need more hints for querying the data, try [the query API chapter](../use - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/get-started/run-evitadb.md b/documentation/user/en/get-started/run-evitadb.md index b722eddec..a9c628cf1 100644 --- a/documentation/user/en/get-started/run-evitadb.md +++ b/documentation/user/en/get-started/run-evitadb.md @@ -12,7 +12,7 @@ evitaDB is a [Java application](https://openjdk.org/), and you can run it as an [a separate service](../operate/run.md) connected to applications via the HTTPS protocol using one of the provided web APIs. - + @@ -191,8 +191,8 @@ API `rest` listening on https://your-domain:5555/rest/ API `system` listening on http://your-domain:5557/system/ ``` - - + + ### Install Docker @@ -256,7 +256,7 @@ API `lab` listening on https://localhost:5555/lab/ More information about running evitaDB Server in Docker is available in the [separate chapter](../operate/run.md). - + ## What's next? diff --git a/documentation/user/en/operate/monitor.md b/documentation/user/en/operate/monitor.md index b72bf5187..8b9796690 100644 --- a/documentation/user/en/operate/monitor.md +++ b/documentation/user/en/operate/monitor.md @@ -1,8 +1,8 @@ --- title: Monitor perex: | - evitaDB's monitoring facilities are designed to help you monitor running evitaDB instances as well as to help you - optimise your application during development. All monitoring facilities are based on our operational experience and + evitaDB's monitoring facilities are designed to help you monitor running evitaDB instances as well as to help you + optimise your application during development. All monitoring facilities are based on our operational experience and development of e-commerce projects. date: '17.1.2023' author: 'Ing. Jan Novotný' @@ -23,7 +23,7 @@ only application log messages are enabled, the access log messages must be expli ### Access log -If the `accessLog` property is set to `true` in the [configuration](configure.md#api-configuration), the server will log +If the `accessLog` property is set to `true` in the [configuration](configure.md#api-configuration), the server will log access log messages for all APIs using the [Slf4j](https://www.slf4j.org/) logging facade. These messages are logged at the `INFO` level and contain the `ACCESS_LOG` marker which you can use to separate standard messages from access log messages. @@ -39,7 +39,7 @@ evitaDB server comes ready with several custom utilities for easier configuratio *Note:* These utilities are only available in evitaDB server because the rest of the evitaDB codebase doesn't rely on a concrete implementation of the [Slf4j](https://www.slf4j.org/) logging facade. -If the evitaDB is used as embedded instance, the following tools are not available, but can be used as reference to +If the evitaDB is used as embedded instance, the following tools are not available, but can be used as reference to custom implementation in chosen framework. #### Log filters @@ -101,24 +101,24 @@ The layout is the `io.evitadb.server.log.AppLogJsonLayout` layout to log app log ## Client and request identification In order to monitor which requests each client executes against evitaDB, each client and each request can be identified by -a unique identifier. In this way, evitaDB calls can be grouped by requests and clients. This may be useful, for example, +a unique identifier. In this way, evitaDB calls can be grouped by requests and clients. This may be useful, for example, to see if a particular client is executing queries optimally and not creating unnecessary duplicate queries. Both identifiers are provided by the client itself. The client identifier is expected to be a constant for a particular client, e.g. `Next.js application`, and will group together all calls to a evitaDB from this client. The request identifier is expected to be a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) -but can be any string value, and will group together all evitaDB calls with this request identifier for a particular client. -The request definition (what a request identifier represents) is up to the client to decide, for example, a single request +but can be any string value, and will group together all evitaDB calls with this request identifier for a particular client. +The request definition (what a request identifier represents) is up to the client to decide, for example, a single request for JavaScript client may group together all evitaDB calls for a single page render. ### Configuration - + This mechanism is not part of an evitaQL language. Check documentation for your specific client for more information. - - + + If you are using the Java remote client, you are suggested to provide the `clientId` in evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/config/EvitaClientConfiguration.java @@ -133,8 +133,8 @@ method on evita_api/src/main/java/io/evitadb/api/EvitaSessionContra If you use embedded variant of evitaDB server there is no sense to provide `clientId` since there is only one client. The `requestId` is then provided the same way as described above. - - + + To pass the request identification using GraphQL API, our GraphQL API utilizes [GraphQL extensions](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#request-parameters). Therefore, to pass request identification information to the evitaDB, pass the following JSON object within the `extensions` @@ -149,8 +149,8 @@ property of a GraphQL request: Both identifiers are optional. - - + + In order to pass request identification using REST API, our REST API utilizes [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). Therefore, to pass request identification information to the evitaDB, pass the following HTTP headers: @@ -162,7 +162,7 @@ X-EvitaDB-RequestID: 05e620b2-5b40-4932-b585-bf3bb6bde4b3 Both headers are optional. - + ### Logging diff --git a/documentation/user/en/operate/tls.md b/documentation/user/en/operate/tls.md index b09b1c692..0ea3dcf34 100644 --- a/documentation/user/en/operate/tls.md +++ b/documentation/user/en/operate/tls.md @@ -1,8 +1,8 @@ --- title: Setting up TLS perex: | - All evitaDB APIs support the secure layer (HTTPS). The gRPC is completely based on the HTTP/2 protocol, which is - binary and requires encryption. Because of this fact, all evitaDB external APIs work by default on secure protocol + All evitaDB APIs support the secure layer (HTTPS). The gRPC is completely based on the HTTP/2 protocol, which is + binary and requires encryption. Because of this fact, all evitaDB external APIs work by default on secure protocol to keep the security uniform. date: '1.3.2023' author: 'Bc. Tomáš Pozler' @@ -14,15 +14,15 @@ proofreading: 'done'
certificate authority
- the certificate authority is an entity that stores, signs, and issues digital certificates. A digital certificate - certifies the ownership of a public key by the named subject of the certificate. This allows others (relying - parties) to rely upon signatures or on assertions made about the private key that corresponds to the certified - public key. A CA acts as a trusted third party—trusted both by the subject (owner) of the certificate and by + the certificate authority is an entity that stores, signs, and issues digital certificates. A digital certificate + certifies the ownership of a public key by the named subject of the certificate. This allows others (relying + parties) to rely upon signatures or on assertions made about the private key that corresponds to the certified + public key. A CA acts as a trusted third party—trusted both by the subject (owner) of the certificate and by the party relying upon the certificate. [source](https://en.wikipedia.org/wiki/Certificate_authority)
certificate
- the certificate is an electronic document used to prove the validity of a public key, and it contains a public + the certificate is an electronic document used to prove the validity of a public key, and it contains a public key along with a lot of additional information [source](https://en.wikipedia.org/wiki/Public_key_certificate)
private key
@@ -33,8 +33,8 @@ proofreading: 'done'
public key
- the public key is the second part public/private key pair - it may be freely distributed and its ownership - does not entitle to anything, it only serves to prove the authenticity of the private key + the public key is the second part public/private key pair - it may be freely distributed and its ownership + does not entitle to anything, it only serves to prove the authenticity of the private key [see more](https://en.wikipedia.org/wiki/Public-key_cryptography)
@@ -51,13 +51,13 @@ We don't want to make things complicated for developers and newcomers, but that is secure, because it can't be. The evitaDB server automatically generates a self-signed certificate authority and issues the server certificate required for TLS. This certificate will not be trusted by the clients unless you force them to. Usually it's just a matter of toggling some switches and for development purposes it's good enough. For -production environments, we strongly recommend issuing your own certificate using the [Let's Encrypt](https://letsencrypt.org) +production environments, we strongly recommend issuing your own certificate using the [Let's Encrypt](https://letsencrypt.org) authority, which can be automated and is part of all certificate trust chains these days. If you are familiar with certificate handling, you can skip the entire [create a certificate](#creating-a-certificate) -chapter and go to [configuration](configure.md#tls-configuration) or read about [mTLS](#mutual-tls-for-grpc) support for +chapter and go to [configuration](configure.md#tls-configuration) or read about [mTLS](#mutual-tls-for-grpc) support for the gRPC protocol. ## Creating a certificate @@ -73,34 +73,34 @@ It is possible to divide certificates into two groups according to the certifica You can buy a certificate from commercial certificate authorities, or you can generate one for free using [Let's Encrypt](https://letsencrypt.org). You can find lots of information about -this process on the web, so we won't duplicate it here. To generate a free server certificate, follow the instructions +this process on the web, so we won't duplicate it here. To generate a free server certificate, follow the instructions on the [Certbot site](https://certbot.eff.org/). ### Self-signed certificate authority -In this guide, we will focus on the second group: self-signed certificates. When using [mTLS](#mutual-tls-for-grpc), it is -necessary for the server to have access to a certificate authority that trusts it, and for clients that +In this guide, we will focus on the second group: self-signed certificates. When using [mTLS](#mutual-tls-for-grpc), it is +necessary for the server to have access to a certificate authority that trusts it, and for clients that prove their identity with a certificate issued by that authority to allow communication. To generate a certificate, we will use the [OpenSSL](https://www.openssl.org/) tool. It is pre-installed on many Linux distributions, as well as on newer versions of the MacOS system. On Windows operating systems, you will need to download and install the tool. - + -If you need to connect to a server that provides a self-signed certificate from the Node.js application, you need to set -the variable `NODE_TLS_REJECT_UNAUTHORIZED` to the value `0`. However, this setting will cause Node.JS to log a warning +If you need to connect to a server that provides a self-signed certificate from the Node.js application, you need to set +the variable `NODE_TLS_REJECT_UNAUTHORIZED` to the value `0`. However, this setting will cause Node.JS to log a warning message: ```plain -Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure +Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification. ``` - + #### Creating certificate authority @@ -108,17 +108,17 @@ To create certificate authority execute following command: ```shell openssl req -x509 \ - -newkey rsa:2048 \ + -newkey rsa:2048 \ -keyout rootCA.key \ -out rootCA.crt \ -days 365 ``` -It generates a certificate `rootCA.crt` and a private key `rootCA.key` for +It generates a certificate `rootCA.crt` and a private key `rootCA.key` for the certificate authority (after confirmation you have to enter a password). -After running the commands in steps 1 and 2, you must enter a password - if you want an unencrypted certificate without +After running the commands in steps 1 and 2, you must enter a password - if you want an unencrypted certificate without a password, specify the `-nodes' parameter in the command. @@ -139,7 +139,7 @@ a password, specify the `-nodes' parameter in the command. `-x509` - produces a x509 certificate - according to a standard that defines the format of digital + produces a x509 certificate - according to a standard that defines the format of digital certificates used in SSL/TLS connections @@ -174,8 +174,8 @@ a password, specify the `-nodes' parameter in the command. #### Certificate signing request -Now you need to create a text file called `domain.ext` with the following content. You need to replace `[domain]` in DNS -section with the name of the domain (or [multiple domains](https://easyengine.io/wordpress-nginx/tutorials/ssl/multidomain-ssl-subject-alternative-names/)) +Now you need to create a text file called `domain.ext` with the following content. You need to replace `[domain]` in DNS +section with the name of the domain (or [multiple domains](https://easyengine.io/wordpress-nginx/tutorials/ssl/multidomain-ssl-subject-alternative-names/)) where your going to run the evitaDB server: ```plain @@ -186,7 +186,7 @@ subjectAltName = @alt_names DNS.1 = [domain] ``` -Then you need to create the certificate signing request `domain.csr` using following command: +Then you need to create the certificate signing request `domain.csr` using following command: ```shell openssl req -newkey rsa:2048 \ @@ -204,7 +204,7 @@ Now you are ready for the final step. Finally, you're ready to generate signed certificate which you can use for evitaDB server or any of the clients in case the [mTLS](#mutual-tls-for-grpc) is enabled. -Generate new certificate signed by the [certificate authority](#creating-certificate-authority) +Generate new certificate signed by the [certificate authority](#creating-certificate-authority) represented by the `rootCA.crt` and its private key `rootCA.key` using the following command: ```shell @@ -213,11 +213,11 @@ openssl x509 -req -CA rootCA.crt -CAkey rootCA.key \ -extfile domain.ext ``` -You can repeat this command multiple times to generate different certificates both for server side and for each +You can repeat this command multiple times to generate different certificates both for server side and for each of the clients. -Do not use the same signed certificate for the server and the client! Do not use the same certificate for different +Do not use the same signed certificate for the server and the client! Do not use the same certificate for different clients! Each entity in the communication must be represented (identified) by a different certificate. If you follow these recommendations, you'll be able to control the rejection of each client separately. If you issue a @@ -283,7 +283,7 @@ Both the server and the client can be provided with: ## Mutual TLS for gRPC The gRPC API, and thus evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java, -also offers the possibility of authentication via [mutual TLS](https://en.wikipedia.org/wiki/Mutual_authentication), in +also offers the possibility of authentication via [mutual TLS](https://en.wikipedia.org/wiki/Mutual_authentication), in which client and server verify their identities with the help of a certificate exchange. @@ -305,7 +305,7 @@ section `api.endpoints.gRPC.mTLS`. At the same place it is possible to configure are allowed to communicate with the gRPC server. The client that doesn't present itself with the accepted certificate will be rejected by the server. -The client needs to configure path to its certificate, private key and optionally password to +The client needs to configure path to its certificate, private key and optionally password to a private key in [configuration](../use/connectors/java.md). We recommend the use of `mTLS` because it prevents a large number of attacks and thus emphasizes the security of @@ -325,8 +325,8 @@ Examples of attacks prevented: The `mTLS` is enabled by default but in a way that is not secure and should be used only in development. When the evitaDB starts and `generateAndUseSelfSigned` is set to `true` (default), it generates three public/private key pairs: -1. certificate authority in `evitaDB-CA-selfSigned.crt` and - its private key in `evitaDB-CA-selfSigned.key` files +1. certificate authority in `evitaDB-CA-selfSigned.crt` and + its private key in `evitaDB-CA-selfSigned.key` files 2. server certificate in `server.crt` and its private key in `server.key` files 3. client certificate in `client.crt` and its private key in `client.key` files @@ -356,8 +356,8 @@ problems in test/production environments. ##### How we can validate communication integrity? -If you need to verify that the client communicates with the server directly without any -[man-in-the-middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack), you may check the fingerprints of +If you need to verify that the client communicates with the server directly without any +[man-in-the-middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack), you may check the fingerprints of the used certificate authority both on the server side and the client. **Server side fingerprint** @@ -381,5 +381,5 @@ Client logs the fingerprint using [configured logging library](run.md#control-lo For each of the gRPC client generate their own certificate using trusted certificate authority (such as [Let's Encrypt](https://letsencrypt.org)), or your own [self-signed authority](#creating-certificate-authority). -Disable `generateAndUseSelfSigned` and configure server certificate and each of client certificates in +Disable `generateAndUseSelfSigned` and configure server certificate and each of client certificates in [configuration](configure.md#tls-configuration). diff --git a/documentation/user/en/query/basics.md b/documentation/user/en/query/basics.md index ff515390e..48d664558 100644 --- a/documentation/user/en/query/basics.md +++ b/documentation/user/en/query/basics.md @@ -10,16 +10,16 @@ proofreading: 'done' preferredLang: 'evitaql' --- - + The evitaDB query language consists of a nested set of functions representing individual "constraints". Each constraint (function) has its name and set of arguments enclosed in brackets `constraintName(arguments)`, argument can be a plain value of supported [data type](../use/data-types.md) or another constraint. Arguments and constraints are separated by a comma -`argument1, argument2`. Strings are enclosed in `'this is string'` or `"this is string"`. +`argument1, argument2`. Strings are enclosed in `'this is string'` or `"this is string"`. - - + + The evitaDB query language consists of a nested JSON objects and primitives representing individual "constraints". Each constraint (represented either by nested object or simple primitive value) has its name specified by the property key @@ -37,13 +37,13 @@ and its support arguments: There also may be different combinations of these. - + This language is expected to be used by human operators, at the code level the query is represented by a query object tree, which can be constructed directly without any intermediate string language form (as opposed to the SQL language, which is strictly string typed). -Query has these four _logical_ parts: +Query has these four _logical_ parts: - **[header](#header):** defines the queried entity collection (it's mandatory unless the filter contains constraints targeting globally unique attributes) @@ -57,12 +57,12 @@ Query has these four _logical_ ## Grammar - + The grammar of a query is as follows: - - + + The grammar of a full query is as follows: - + @@ -76,7 +76,7 @@ Or more complex one: [Example of grammar of a complex query](/documentation/user/en/query/examples/complexGrammar.evitaql) - + Where the _header_ part (queried collection) is part of the GraphQL query name itself, and the _filter_, _order_, and _require_ parts are defined using GraphQL arguments of that GraphQL query. @@ -89,17 +89,17 @@ what the domain evitaDB schema allows you to fetch. There are other simpler variations of the GraphQL query grammar described [here](../use/api/query-data.md#defining-queries-in-graphql-api) in more detail, but the underlying logic is always the same. - - + + Where the _header_ part (queried collection) is part a URL path, and the _filter_, _order_, and _require_ parts are defined as properties of the input JSON object. There are other simpler variations of the REST query grammar described [here](../use/api/query-data.md#defining-queries-in-rest-api) in more detail, but the underlying logic is always the same. - + - + Any part of the query is optional. Only the `collection` part is usually mandatory, but there is an exception to this rule. If the `filterBy` part contains a constraint that targets a globally unique attribute, the `collection` part can be omitted @@ -108,31 +108,31 @@ However, there can be at most one part of each `collection`, `filterBy`, `orderB Any part can be swapped (the order is not important). I.e. the following query is still a valid query and represents the simplest query possible: - - + + Almost any part of the query is optional. Only the `collection` is usually mandatory, but there is an exception to this rule. -You always need to use specific GraphQL queryREST endpoint +You always need to use specific GraphQL queryREST endpoint where the name of the collection is already defined, however, you can -use generic GraphQL queryREST endpoint +use generic GraphQL queryREST endpoint (although, it is very limited due to the nature of the generated schema) and use a constraint that targets a globally unique attribute. In this case, the `collection` part can be omitted because evitaDB can pick the implicit collection of that globally unique attribute automatically. -Other parts defined using arguments are optional, but due to the nature of the GraphQL, you have to define at least -one output field. -Other parts defined using properties of input JSON object are optional. +Other parts defined using arguments are optional, but due to the nature of the GraphQL, you have to define at least +one output field. +Other parts defined using properties of input JSON object are optional. However, there can be at most one part of each _header_, _filter_, _order_, and _require_ in the query. -Another specific in the GraphQLREST +Another specific in the GraphQLREST query grammar is that the constraint names usually contains classifiers of targeted data (e.g. name of attribute). This is important difference from other APIs, and it's because this way the -GraphQLREST +GraphQLREST schema for constraint property value can be specific to the constraint and targeted data and an IDE can provide proper auto-completion and validation of the constraint arguments. I.e. the following query is still a valid query and represents the simplest query possible: - + @@ -140,14 +140,14 @@ I.e. the following query is still a valid query and represents the simplest quer ... or even this one (although it is recommended to keep the order for better readability: -`collection`, `filterBy`, `orderBy`, `require`): +`collection`, `filterBy`, `orderBy`, `require`): [Example random order of query parts](/documentation/user/en/query/examples/randomOrderQuery.evitaql) - + @@ -155,11 +155,11 @@ I.e. the following query is still a valid query and represents the simplest quer ##### Want to read more about how the grammar was designed? -You can read more about the specifics of the GraphQLREST +You can read more about the specifics of the GraphQLREST query grammar [here](/documentation/blog/en/02-designing-evita-query-language-for-graphql-api.md). - + ### Syntax format @@ -188,18 +188,18 @@ constraintName( - + This syntax format is currently specific to the base evitaQL language and doesn't reflect the differences in the -GraphQLREST API. +GraphQLREST API. However, you can still benefit from this syntax as the naming and accepted arguments are the same (only in slightly different format). -The more specific GraphQL constraints/queries do have specific documentation however. +The more specific GraphQL constraints/queries do have specific documentation however. - + #### Variadic arguments @@ -223,12 +223,12 @@ character:
`argument:string+`
- argument at this position accepts an array of [Strings](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[strings](https://learn.microsoft.com/en-us/dotnet/api/system.string) + argument at this position accepts an array of [Strings](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[strings](https://learn.microsoft.com/en-us/dotnet/api/system.string) that has to have at least one item
`argument:int*`
- argument at this position accepts an array of [ints](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[ints](https://learn.microsoft.com/en-us/dotnet/api/system.int32) + argument at this position accepts an array of [ints](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[ints](https://learn.microsoft.com/en-us/dotnet/api/system.int32) and may have zero or multiple items
`filterConstraint:any*`
@@ -253,12 +253,12 @@ Mandatory argument is denoted by `!` (exclamation) sign or in case of variadic a
`argument:string`
- argument at this position accepts a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) + argument at this position accepts a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) value, that may be null
`argument:int!`
- argument at this position accepts an [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) + argument at this position accepts an [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) value that is mandatory and must be provided
@@ -306,7 +306,7 @@ To make constraints more understandable, we have created a set of internal rules 1. the name of the entity should be in a form (tense) that matches the English query phrase: *query collection ..., and filter entities by ..., and order result by ..., and require ...* - the query should be understandable to someone who is not familiar with evitaDB's syntax and internal mechanisms. -2. The constraint name starts with the part of the entity it targets - i.e., `entity`, `attribute`, `reference` - followed usually by classifier of targeted data, which is followed by a word that captures the essence of the constraint. +2. The constraint name starts with the part of the entity it targets - i.e., `entity`, `attribute`, `reference` - followed usually by classifier of targeted data, which is followed by a word that captures the essence of the constraint. 3. If the constraint only makes sense in the context of some parent constraint, it must not be usable anywhere else, and might relax rule #2 (since the context will be apparent from the parent constraint). ## Generic query rules @@ -323,11 +323,11 @@ the automatic conversion. If the constraint targets an attribute that is of array type, the constraint automatically matches an entity in case **any** of the attribute array items satisfies it. -For example let's have a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) +For example let's have a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) array attribute named `oneDayDeliveryCountries` with the following values: `GB`, `FR`, `CZ`. The filtering constraint -[`attributeEquals`](filtering/comparable.md#attribute-equals) worded as follows: `attributeEquals("oneDayDeliveryCountries", "GB")` -`attributeOneDayDeliveryCountriesEquals: "GB"` -`"attributeOneDayDeliveryCountriesEquals": "GB"` +[`attributeEquals`](filtering/comparable.md#attribute-equals) worded as follows: `attributeEquals("oneDayDeliveryCountries", "GB")` +`attributeOneDayDeliveryCountriesEquals: "GB"` +`"attributeOneDayDeliveryCountriesEquals": "GB"` will match the entity, because the *GB* is one of the array values. Let's look at a more complicated, but more useful example. Let's have a [`DateTimeRange`](../use/data-types.md#datetimerange) @@ -340,23 +340,23 @@ array attribute called `validity` that contains multiple time periods when the e ``` In short, the entity is only valid in January, June, and December 2023. If we want to know if it's possible to access -(e.g. buy a product) in May using the constraint `attributeInRange("validity", "2023-05-05T00:00:00+01:00")` -`attributeValidityInRange: "2023-05-05T00:00:00+01:00"` -`"attributeValidityInRange": "2023-05-05T00:00:00+01:00"`, the result +(e.g. buy a product) in May using the constraint `attributeInRange("validity", "2023-05-05T00:00:00+01:00")` +`attributeValidityInRange: "2023-05-05T00:00:00+01:00"` +`"attributeValidityInRange": "2023-05-05T00:00:00+01:00"`, the result will be empty because none of the `validity` array ranges matches that date and time. Of course, if we ask for an entity that is valid in June using -`attributeInRange("validity", "2023-06-05T00:00:00+01:00")` -`attributeValidityInRange: "2023-06-05T00:00:00+01:00"` -`"attributeValidityInRange": "2023-06-05T00:00:00+01:00"`, the entity will be returned +`attributeInRange("validity", "2023-06-05T00:00:00+01:00")` +`attributeValidityInRange: "2023-06-05T00:00:00+01:00"` +`"attributeValidityInRange": "2023-06-05T00:00:00+01:00"`, the entity will be returned because there is a single date/time range in the array that satisfies this constraint. ## Header -Only a `collection` constraint is allowed in this part of the query. -Only a collection definition is allowed and is defined as part of a GraphQL query namean endpoint URL. +Only a `collection` constraint is allowed in this part of the query. +Only a collection definition is allowed and is defined as part of a GraphQL query namean endpoint URL. It defines the entity type that the query will target. It can be omitted -when using generic GraphQL queryendpoint +when using generic GraphQL queryendpoint if the [filterBy](#filter-by) contains a constraint that targets a globally unique attribute. This is useful for one of the most important e-commerce scenarios, where the requested URI needs to match one of the existing entities (see the [routing](../solve/routing.md) chapter for a detailed guide). @@ -383,7 +383,7 @@ Constant constraints directly specify the entity primary keys that are expected ### Localization constraints Localization constraints allow you to narrow down the [localized attributes](../use/data-model.md#localized-attributes) -to a single [locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html)[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo), which is used +to a single [locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html)[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo), which is used to pick the correct values for comparison in other filter constraints that target those attributes: - [entity locale equals](filtering/locale.md#entity-locale-equals) @@ -405,7 +405,7 @@ the resulting output to only include values that satisfy the constraint. ### String constraints String constraints are similar to [Comparable](#comparable-constraints), but operate only on the -[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) attribute datatype and +[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) attribute datatype and allow operations specific to it: - [attribute contains](filtering/string.md#attribute-contains) @@ -415,7 +415,7 @@ allow operations specific to it: ### Range constraints String constraints are similar to [Comparable](#comparable-constraints), but operate only on the -evita_common/src/main/java/io/evitadb/dataType/Range.javaEvitaDB.Client/DataTypes/Range.cs attribute datatype and +evita_common/src/main/java/io/evitadb/dataType/Range.javaEvitaDB.Client/DataTypes/Range.cs attribute datatype and allow operations specific to it: - [attribute in range](filtering/range.md#attribute-in-range) @@ -486,21 +486,21 @@ Currently, these requirements are available to you: Paging requirements control how large and which subset of the large filtered entity set is actually returned in the output. - + - [page](requirements/paging.md#page) - [strip](requirements/paging.md#strip) - - + + - [`list` queries](requirements/paging.md#pagination-of-list-queries) - [`query` queries - `recordPage`](requirements/paging.md#page-recordpage) - [`query` queries - `recordStrip`](requirements/paging.md#page-recordstrip) - + ### Fetching (completeness) -Fetching requirements control the completeness of the returned entities. By default, only a -evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityReference.javaEvitaDB.Client/Models/Data/Structure/EntityReference.cs -is returned in query response. In order an entity body is returned, some of the following requirements needs to be part +Fetching requirements control the completeness of the returned entities. By default, only a +evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityReference.javaEvitaDB.Client/Models/Data/Structure/EntityReference.cs +is returned in query response. In order an entity body is returned, some of the following requirements needs to be part of it: - [entity fetch](requirements/fetching.md#entity-fetch) @@ -510,9 +510,9 @@ of it: - [price content](requirements/fetching.md#price-content) - [reference content](requirements/fetching.md#reference-content) - [hierarchy content](requirements/fetching.md#hierarchy-content) - + - [data in locale](requirements/fetching.md#data-in-locales) - + ### Hierarchy @@ -540,9 +540,9 @@ the summary could include a calculation of how many entities will be left when t the filter: - [facet summary](requirements/facet.md#facet-summary) - + - [facet summary of reference](requirements/facet.md#facet-summary-of-reference) - + - [facet conjunction](requirements/facet.md#facet-groups-conjunction) - [facet disjunction](requirements/facet.md#facet-groups-disjunction) - [facet negation](requirements/facet.md#facet-groups-negation) diff --git a/documentation/user/en/query/filtering/behavioral.md b/documentation/user/en/query/filtering/behavioral.md index f35031a29..34b917961 100644 --- a/documentation/user/en/query/filtering/behavioral.md +++ b/documentation/user/en/query/filtering/behavioral.md @@ -2,7 +2,7 @@ title: Behavioral filtering containers date: '7.11.2023' perex: | - Special behavioral filtering constraint containers are used only for the definition of a filter constraint scope, + Special behavioral filtering constraint containers are used only for the definition of a filter constraint scope, which has a different treatment in calculations. author: 'Ing. Jan Novotný' proofreading: 'done' @@ -17,7 +17,7 @@ userFilter( ) ``` -
+
filterConstraint:any+
one or more mandatory filter constraints that will produce logical conjunction @@ -25,7 +25,7 @@ userFilter(
-The evita_query/src/main/java/io/evitadb/api/query/filter/UserFilter.javaEvitaDB.Client/Queries/Filter/UserFilter.cs +The evita_query/src/main/java/io/evitadb/api/query/filter/UserFilter.javaEvitaDB.Client/Queries/Filter/UserFilter.cs works identically to the [`and`](logical.md#and) constraint, but it distinguishes the filter scope, which is controlled by the user through some kind of user interface, from the rest of the query, which contains the mandatory constraints on the result set. The user-defined scope can be modified during certain calculations (such as the [facet](../requirements/facet.md) @@ -42,7 +42,7 @@ the `userFilter` container: And compare it to the situation when we remove the `userFilter` container: -| Facet summary with `facetHaving` in `userFilter` | Facet summary without `userFilter` scope | +| Facet summary with `facetHaving` in `userFilter` | Facet summary without `userFilter` scope | |---------------------------------------------------|------------------------------------------------| | ![Before](assets/user-filter-before.png "Before") | ![After](assets/user-filter-after.png "After") | diff --git a/documentation/user/en/query/filtering/comparable.md b/documentation/user/en/query/filtering/comparable.md index 548d327fe..af51b560b 100644 --- a/documentation/user/en/query/filtering/comparable.md +++ b/documentation/user/en/query/filtering/comparable.md @@ -2,30 +2,30 @@ title: Comparable filtering date: '29.5.2023' perex: | - All attribute data types in evitaDB have mutually comparable values - it is always possible to unambiguously tell - whether two values are the same, one is smaller than the other, or vice versa. This fact underlies the basic set of - filtering constraints that you will commonly use when building queries. + All attribute data types in evitaDB have mutually comparable values - it is always possible to unambiguously tell + whether two values are the same, one is smaller than the other, or vice versa. This fact underlies the basic set of + filtering constraints that you will commonly use when building queries. author: 'Ing. Jan Novotný' proofreading: 'done' preferredLang: 'evitaql' --- -In the context of the limitations described in this chapter, you might be interested in the general rules for handling +In the context of the limitations described in this chapter, you might be interested in the general rules for handling data types and arrays described in [the query language basics](../basics.md#generic-query-rules). -When you compare two **[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)****[string](https://learn.microsoft.com/en-us/dotnet/api/system.string)** -data types, the strings are compared alphabetically from the beginning of the string. For example, *Walther* is greater -than *Adam*, but *Jasmine* is not greater than *Joanna*. The correct [collator](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/Collator.html)[culture info](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo) is used to compare the localized attribute string, so that the order is consistent with the national customs of +When you compare two **[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)****[string](https://learn.microsoft.com/en-us/dotnet/api/system.string)** +data types, the strings are compared alphabetically from the beginning of the string. For example, *Walther* is greater +than *Adam*, but *Jasmine* is not greater than *Joanna*. The correct [collator](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/Collator.html)[culture info](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo) is used to compare the localized attribute string, so that the order is consistent with the national customs of the language. When you compare two **[Range](../../use/data-types.md#numberrange)** data types, the larger one is the one whose left boundary is greater than the left boundary of the other value. If both left boundaries are equal, the greater is the one with the greater right boundary. -The **[boolean](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)****[bool](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool)** data type is compared as +The **[boolean](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)****[bool](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool)** data type is compared as a numeric value, where the *true* is 1, and *false* is 0. @@ -67,23 +67,23 @@ Returns exactly one product with *code* equal to *apple-iphone-13-pro-3*. ##### Product found by a `code` attribute - + [Product with `code` attribute equal to `apple-iphone-13-pro-3`](/documentation/user/en/query/filtering/examples/comparable/attribute-equals.evitaql.md) - + - + [Product with `code` attribute equal to `apple-iphone-13-pro-3`](/documentation/user/en/query/filtering/examples/comparable/attribute-equals.graphql.json.md) - + - + [Product with `code` attribute equal to `apple-iphone-13-pro-3`](/documentation/user/en/query/filtering/examples/comparable/attribute-equals.rest.json.md) - + @@ -126,23 +126,23 @@ Returns exactly several products with *battery-life* greater than *40* hours. ##### Products with `battery-life` attribute greater than 40 hours - + [Products with `battery-life` attribute greater than 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than.evitaql.md) - + - + [Products with `battery-life` attribute greater than 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than.graphql.json.md) - + - + [Products with `battery-life` attribute greater than 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than.rest.json.md) - + @@ -169,7 +169,7 @@ attributeGreaterThanEquals(
The `attributeGreaterThanEquals` compares the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) -with the value in the second argument and is satisfied only if the entity attribute is greater than or equal to +with the value in the second argument and is satisfied only if the entity attribute is greater than or equal to the value. @@ -187,23 +187,23 @@ Returns exactly several products with *battery-life* greater than or equal to *4 ##### Products with `battery-life` attribute greater than or equal to 40 hours - + [Products with `battery-life` attribute greater than or equal to 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than-equals.evitaql.md) - + - + [Products with `battery-life` attribute greater than or equal to 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than-equals.graphql.json.md) - + - + [Products with `battery-life` attribute greater than or equal to 40 hours](/documentation/user/en/query/filtering/examples/comparable/attribute-greater-than-equals.rest.json.md) - + @@ -246,23 +246,23 @@ Returns exactly several products with *battery-capacity* less than *125* mWH. ##### Products with `battery-capacity` attribute less than 125 mWH - + [Products with `battery-life` attribute less than 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than.evitaql.md) - + - + [Products with `battery-life` attribute less than 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than.graphql.json.md) - + - + [Products with `battery-life` attribute less than 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than.rest.json.md) - + @@ -305,23 +305,23 @@ Returns exactly several products with *battery-capacity* less than or equal to * ##### Products with `battery-capacity` attribute less than or equal to 125 mWH - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than-equals.evitaql.md) - + - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than-equals.graphql.json.md) - + - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-less-than-equals.rest.json.md) - + @@ -371,23 +371,23 @@ Returns exactly several products with *battery-capacity* between *125* and *160* ##### Products with `battery-capacity` attribute is between 125 mWH and 160 mWH - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-between.evitaql.md) - + - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-between.graphql.json.md) - + - + [Products with `battery-life` attribute less than or equal to 125 mWH](/documentation/user/en/query/filtering/examples/comparable/attribute-between.rest.json.md) - + @@ -420,7 +420,7 @@ for strict equality with any of the passed values. [Product found by a `code` attribute in given set](/documentation/user/en/query/filtering/examples/comparable/attribute-in-set.evitaql) -Returns exactly three product with *code* matching one of the arguments. Last of the products was not found +Returns exactly three product with *code* matching one of the arguments. Last of the products was not found in the database and is missing in the result. @@ -430,23 +430,23 @@ in the database and is missing in the result. ##### Product found by a `code` attribute in given set - + [Product found by a `code` attribute in given set](/documentation/user/en/query/filtering/examples/comparable/attribute-in-set.evitaql.md) - + - + [Product found by a `code` attribute in given set](/documentation/user/en/query/filtering/examples/comparable/attribute-in-set.graphql.json.md) - + - + [Product found by a `code` attribute in given set](/documentation/user/en/query/filtering/examples/comparable/attribute-in-set.rest.json.md) - + @@ -467,7 +467,7 @@ attributeIs(
-The `attributeIs` can be used to test for the existence of an entity +The `attributeIs` can be used to test for the existence of an entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) of a given name. @@ -484,23 +484,23 @@ Returns hundreds of products with the *catalogNumber* attribute set. ##### Products with `catalogNumber` present - + [Product with `catalogNumber` attribute present](/documentation/user/en/query/filtering/examples/comparable/attribute-is-not-null.evitaql.md) - + - + [Product with `catalogNumber` attribute present](/documentation/user/en/query/filtering/examples/comparable/attribute-is-not-null.graphql.json.md) - + - + [Product with `catalogNumber` attribute present](/documentation/user/en/query/filtering/examples/comparable/attribute-is-not-null.rest.json.md) - +
@@ -520,22 +520,22 @@ When you try to list products without such attribute: ##### Products with `catalog-number` missing - + [Product with `catalog-number` attribute missing](/documentation/user/en/query/filtering/examples/comparable/attribute-is-null.evitaql.md) - + - + [Product with `catalog-number` attribute missing](/documentation/user/en/query/filtering/examples/comparable/attribute-is-null.graphql.json.md) - + - + [Product with `catalog-number` attribute missing](/documentation/user/en/query/filtering/examples/comparable/attribute-is-null.rest.json.md) - +
\ No newline at end of file diff --git a/documentation/user/en/query/filtering/constant.md b/documentation/user/en/query/filtering/constant.md index 1972519d8..f91ccc211 100644 --- a/documentation/user/en/query/filtering/constant.md +++ b/documentation/user/en/query/filtering/constant.md @@ -1,9 +1,9 @@ --- title: Constant filtering perex: | - If you need to retrieve entities by their entity primary keys, or verify that entities with particular primary keys - exist in the database, the constant filter constraint is the place to go. Filtering entities by their primary keys is - the fastest way to access entities in evitaDB. + If you need to retrieve entities by their entity primary keys, or verify that entities with particular primary keys + exist in the database, the constant filter constraint is the place to go. Filtering entities by their primary keys is + the fastest way to access entities in evitaDB. date: '26.5.2023' author: 'Ing. Jan Novotný' proofreading: 'done' @@ -25,7 +25,7 @@ entityPrimaryKeyInSet( -The constraint limits the list of returned entities by exactly specifying their entity primary keys. +The constraint limits the list of returned entities by exactly specifying their entity primary keys. @@ -38,8 +38,8 @@ their primary keys, unless the `orderBy` clause is used in the query. -If you want the entities to be returned in the exact order of the primary keys used in the argument -of the `entityPrimaryKeyInSet` constraint, use the +If you want the entities to be returned in the exact order of the primary keys used in the argument +of the `entityPrimaryKeyInSet` constraint, use the [`entityPrimaryKeyInFilter`](../ordering/constant.md#exact-entity-primary-key-order-used-in-filter) ordering constraint. @@ -52,22 +52,22 @@ ordering constraint. ##### List of products filtered by entity primary key - + [Entities filtered by the primary keys](/documentation/user/en/query/filtering/examples/constant/entity-primary-key-in-set.evitaql.md) - + - + [Entities filtered by the primary keys](/documentation/user/en/query/filtering/examples/constant/entity-primary-key-in-set.graphql.json.md) - + - + [Entities filtered by the primary keys](/documentation/user/en/query/filtering/examples/constant/entity-primary-key-in-set.rest.json.md) - + diff --git a/documentation/user/en/query/filtering/hierarchy.md b/documentation/user/en/query/filtering/hierarchy.md index 204dee73d..9b8370c7a 100644 --- a/documentation/user/en/query/filtering/hierarchy.md +++ b/documentation/user/en/query/filtering/hierarchy.md @@ -1,9 +1,9 @@ --- title: Hierarchy filtering perex: | - Hierarchy filtering allows you to query tree-oriented structures or items that refer to a node in that structure. + Hierarchy filtering allows you to query tree-oriented structures or items that refer to a node in that structure. In e-commerce projects, the hierarchy structure is represented by a category tree and the items that refer to it are - usually products or some kind of "inventory". This functionality is closely related to menu traversal and listing + usually products or some kind of "inventory". This functionality is closely related to menu traversal and listing the items relevant to the currently viewed category. date: '5.5.2023' author: 'Ing. Jan Novotný' @@ -11,14 +11,14 @@ proofreading: 'done' preferredLang: 'evitaql' --- -Hierarchy filtering can be applied only to entities [marked as hierarchical](../../use/data-model.md#hierarchy-placement) -or to entities that [reference](../../use/data-model.md#references) these hierarchical entities. Hierarchy filtering -allows filtering all direct or transitive children of a given hierarchy node, or entities that are directly or -transitively related to the requested hierarchy node or its children. Filtering allows to exclude (hide) several parts -of the tree from evaluation, which can be useful in situation when part of the store should be (temporarily) hidden +Hierarchy filtering can be applied only to entities [marked as hierarchical](../../use/data-model.md#hierarchy-placement) +or to entities that [reference](../../use/data-model.md#references) these hierarchical entities. Hierarchy filtering +allows filtering all direct or transitive children of a given hierarchy node, or entities that are directly or +transitively related to the requested hierarchy node or its children. Filtering allows to exclude (hide) several parts +of the tree from evaluation, which can be useful in situation when part of the store should be (temporarily) hidden from (some of) clients. -In addition to filtering, there are query [requirement extensions](../requirements/hierarchy.md) that allow you to +In addition to filtering, there are query [requirement extensions](../requirements/hierarchy.md) that allow you to compute data to help render (dynamic or static) menus that describe the hierarchy context you request in the query. **The typical use-cases related to hierarchy constraints:** @@ -33,9 +33,9 @@ There could be at most one single `hierarchyWithin` or `hierarchyRoot` filter co ## Hierarchy within -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyWithin.javaEvitaDB.Client/Queries/Filter/HierarchyWithin.cs -allows you to restrict the search to only those entities that are part of the hierarchy tree starting with the root -node identified by the first argument of this constraint. In e-commerce systems the typical representative of +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyWithin.javaEvitaDB.Client/Queries/Filter/HierarchyWithin.cs +allows you to restrict the search to only those entities that are part of the hierarchy tree starting with the root +node identified by the first argument of this constraint. In e-commerce systems the typical representative of a hierarchical entity is a *category*, which will be used in all of our examples. The examples in this chapter will focus on the category *Accessories* in our [demo dataset](../../get-started/query-our-dataset) with following layout: @@ -53,12 +53,12 @@ hierarchyWithin(
filterConstraint:any!
- a single mandatory filter constraint that identifies **one or more** hierarchy nodes that act as hierarchy roots; + a single mandatory filter constraint that identifies **one or more** hierarchy nodes that act as hierarchy roots; multiple constraints must be enclosed in [AND](../logical.md#and) / [OR](../logical.md#or) containers
filterConstraint:(directRelation|having|excluding|excludingRoot)*
- optional constraints allow you to narrow the scope of the hierarchy; + optional constraints allow you to narrow the scope of the hierarchy; none or all of the constraints may be present:
  • [directRelation](#direct-relation)
  • @@ -69,7 +69,7 @@ hierarchyWithin(
-The most straightforward usage is filtering the hierarchical entities themselves. +The most straightforward usage is filtering the hierarchical entities themselves. To list all nested categories of *Accessories* category issue this query: @@ -87,23 +87,23 @@ To list all nested categories of *Accessories* category issue this query: ##### List of all subcategories of the *Accessories* category - + [Single root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-simple.evitaql.md) - + - + [Single root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-simple.graphql.json.md) - + - + [Single root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-simple.rest.json.md) - + @@ -111,13 +111,13 @@ The first argument specifies the filter targets the attributes of the `Category` [attributeEquals](comparable.md#attribute-equals) for unique attribute `code`, but you can select the category by localized `url` attribute (but then you need to provide also [entityLocaleEquals](locale.md#entity-locale-equals) constraint for determining the proper language), or using [entityPrimaryKeyInSet](constant.md#entity-primary-key-in-set) -and passing category primary key. +and passing category primary key. -##### Can the parent node filter constraint match multiple ones? +##### Can the parent node filter constraint match multiple ones? Yes, it can. Although, it's apparently one of the edge cases, it's possible. This query: @@ -129,23 +129,23 @@ Yes, it can. Although, it's apparently one of the edge cases, it's possible. Thi ... will return all subcategories of the *Wireless headphones* and *Wired headphones* and their subcategories: - + [Multi-root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-multi.evitaql.md) - + - + [Multi-root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-multi.graphql.json.md) - + - + [Multi-root hierarchy example](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-multi.rest.json.md) - + ![Accessories category listing](assets/accessories-category-listing-multi.png "Accessories category listing") @@ -164,19 +164,19 @@ hierarchyWithin(
argument:string!
- a mandatory name of the queried entity [reference schema](../../use/schema.md#reference) that represents - the relationship to the hierarchical entity type, your entity may target different hierarchical entities in - different reference types, or it may target the same hierarchical entity through multiple semantically different + a mandatory name of the queried entity [reference schema](../../use/schema.md#reference) that represents + the relationship to the hierarchical entity type, your entity may target different hierarchical entities in + different reference types, or it may target the same hierarchical entity through multiple semantically different references, and that is why the reference name is used instead of the target entity type.
filterConstraint:any!
- a single mandatory filter constraint that identifies **one or more** hierarchy nodes that act as hierarchy roots; + a single mandatory filter constraint that identifies **one or more** hierarchy nodes that act as hierarchy roots; multiple constraints must be enclosed in [AND](../logical.md#and) / [OR](../logical.md#or) containers
filterConstraint:(directRelation|having|excluding|excludingRoot)*
- optional constraints allow you to narrow the scope of the hierarchy; + optional constraints allow you to narrow the scope of the hierarchy; none or all of the constraints may be present:
  • [directRelation](#direct-relation)
  • @@ -196,7 +196,7 @@ products in the *Accessories* category of our [demo dataset](../../get-started/q [Product listing from *Accessories* category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-simple.evitaql) -Products assigned to two or more subcategories of *Accessories* category will only appear once in the response (contrary +Products assigned to two or more subcategories of *Accessories* category will only appear once in the response (contrary to what you might expect if you have experience with SQL). The query returns the first page of a total of 26 pages of items. @@ -208,23 +208,23 @@ The query returns the first page of a total of 26 pages of items. ##### List of all products in the *Accessories* category or its subcategories - + [Product listing from *Accessories* category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-simple.evitaql.md) - + - + [Product listing from *Accessories* category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-simple.graphql.json.md) - + - + [Product listing from *Accessories* category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-simple.rest.json.md) - + @@ -235,13 +235,13 @@ address this shortcoming. ## Hierarchy within root -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyWithinRoot.javaEvitaDB.Client/Queries/Filter/HierarchyWithinRoot.cs +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyWithinRoot.javaEvitaDB.Client/Queries/Filter/HierarchyWithinRoot.cs allows you to restrict the search to only those entities that are part of the entire hierarchy tree. In e-commerce systems the typical representative of a hierarchical entity is a *category*, which will be used in all of our examples. -The single difference to [hierarchyWithin constraint](#hierarchy-within) is that it doesn't accept a root node +The single difference to [hierarchyWithin constraint](#hierarchy-within) is that it doesn't accept a root node specification. Because evitaDB accepts multiple root nodes in your entity hierarchy, it may be helpful to imagine -there is an invisible "virtual" top root above all the top nodes (whose `parent` property remains `NULL`) you have in +there is an invisible "virtual" top root above all the top nodes (whose `parent` property remains `NULL`) you have in your entity hierarchy and this virtual top root is targeted by this constraint. ![Root categories listing](assets/category-listing.png "Root categories listing") @@ -257,7 +257,7 @@ hierarchyWithinRoot(
    filterConstraint:(directRelation|having|excluding)*
    - optional constraints allow you to narrow the scope of the hierarchy; + optional constraints allow you to narrow the scope of the hierarchy; none or all of the constraints may be present:
    • [directRelation](#direct-relation)
    • @@ -267,7 +267,7 @@ hierarchyWithinRoot(
    -The `hierarchyWithinRoot`, which targets the `Category` collection itself, returns all categories except those that +The `hierarchyWithinRoot`, which targets the `Category` collection itself, returns all categories except those that would point to non-existent parent nodes, such hierarchy nodes are called [orphans](../../use/schema.md#orphan-hierarchy-nodes) and do not satisfy any hierarchy query. @@ -285,23 +285,23 @@ The query returns the first page of a total of 2 pages of items. ##### List of all categories in the hierarchy tree - + [Category listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-simple.evitaql.md) - + - + [Category listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-simple.graphql.json.md) - + - + [Category listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-simple.rest.json.md) - + @@ -309,7 +309,7 @@ The query returns the first page of a total of 2 pages of items. ```evitaql-syntax hierarchyWithinRoot( - argument:string!, + argument:string!, filterConstraint:(having|excluding)* ) ``` @@ -317,19 +317,19 @@ hierarchyWithinRoot(
    argument:string!
    - a mandatory name of the queried entity [reference schema](../../use/schema.md#reference) that represents + a mandatory name of the queried entity [reference schema](../../use/schema.md#reference) that represents the relationship to the hierarchical entity type, your entity may target different hierarchical entities in - different reference types, or it may target the same hierarchical entity through multiple semantically different + different reference types, or it may target the same hierarchical entity through multiple semantically different references, and that is why the reference name is used instead of the target entity type.
    filterConstraint:(having|excluding)*
    - optional constraints allow you to narrow the scope of the hierarchy; + optional constraints allow you to narrow the scope of the hierarchy; none or all of the constraints may be present:
    • [directRelation](#direct-relation)
    • -
    • [having](#having)
    • -
    • [excluding](#excluding)
    • +
    • [having](#having)
    • +
    • [excluding](#excluding)
    @@ -343,8 +343,8 @@ products assigned to any category of our [demo dataset](../../get-started/query- [Product listing assigned to a category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-reference-simple.evitaql) -Products assigned to only one [orphan category](../../use/schema.md#orphan-hierarchy-nodes) will be missing from -the result. Products assigned to two or more categories will only appear once in the response (contrary to what you +Products assigned to only one [orphan category](../../use/schema.md#orphan-hierarchy-nodes) will be missing from +the result. Products assigned to two or more categories will only appear once in the response (contrary to what you might expect if you have experience with SQL). The query returns the first page of a total of 212 pages of items: @@ -356,33 +356,33 @@ The query returns the first page of a total of 212 pages of items: ##### List of all products assigned to any category in the hierarchy tree - + [Product listing assigned to a category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-reference-simple.evitaql.md) - + - + [Product listing assigned to a category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-reference-simple.graphql.json.md) - + - + [Product listing assigned to a category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-root-reference-simple.rest.json.md) - + ## Direct relation -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyDirectRelation.javaEvitaDB.Client/Queries/Filter/HierarchyDirectRelation.cs -is a constraint that can only be used within `hierarchyWithin` or `hierarchyWithinRoot` parent constraints. It simply -makes no sense anywhere else because it changes the default behavior of those constraints. Hierarchy constraints return -all hierarchy children of the parent node or entities that are transitively or directly related to them and the parent -node itself. If the `directRelation` is used as a sub-constraint, this behavior changes and only direct descendants or +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyDirectRelation.javaEvitaDB.Client/Queries/Filter/HierarchyDirectRelation.cs +is a constraint that can only be used within `hierarchyWithin` or `hierarchyWithinRoot` parent constraints. It simply +makes no sense anywhere else because it changes the default behavior of those constraints. Hierarchy constraints return +all hierarchy children of the parent node or entities that are transitively or directly related to them and the parent +node itself. If the `directRelation` is used as a sub-constraint, this behavior changes and only direct descendants or directly referencing entities are matched. ```evitaql-syntax @@ -407,23 +407,23 @@ top root - so only the top-level categories are returned. ##### List of all root categories of the hierarchy - + [Top categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-top-categories.evitaql.md) - + - + [Top categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-top-categories.graphql.json.md) - + - + [Top categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-top-categories.rest.json.md) - + @@ -441,35 +441,35 @@ In the case of the `hierarchyWithin` the result will contain direct children of ##### List of all direct subcategories of the *Accessories* category - + [Accessories children categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-direct-categories.evitaql.md) - + - + [Accessories children categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-direct-categories.graphql.json.md) - + - + [Accessories children categories listing](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-direct-categories.rest.json.md) - + ### Referenced entity -If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is +If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is a product assigned to a category), it can only be used in the `hierarchyWithin` parent constraint. -In the case of `hierarchyWithinRoot`, the `directRelation` constraint makes no sense because no entity can be assigned +In the case of `hierarchyWithinRoot`, the `directRelation` constraint makes no sense because no entity can be assigned to a "virtual" top parent root. -So we can only list products that are directly related to a certain category - if we try to list products that have +So we can only list products that are directly related to a certain category - if we try to list products that have *Accessories* category assigned: @@ -477,7 +477,7 @@ So we can only list products that are directly related to a certain category - i [Products directly assigned to Accessories category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-direct-categories.evitaql) -... we get an empty result. There are no products directly assigned to the *Accessories* category, they all refer to +... we get an empty result. There are no products directly assigned to the *Accessories* category, they all refer to some of its subcategories. Let's try the *Smartwatches* subcategory: @@ -494,32 +494,32 @@ some of its subcategories. Let's try the *Smartwatches* subcategory: ##### List of all products directly related to the *Smartwatches* category - + [Product directly assigned to Smartwatches category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-direct-categories-smart.evitaql.md) - + - + [Product directly assigned to Smartwatches category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-direct-categories-smart.graphql.json.md) - + - + [Product directly assigned to Smartwatches category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-direct-categories-smart.rest.json.md) - + ## Excluding root -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyExcludingRoot.javaEvitaDB.Client/Queries/Filter/HierarchyExcludingRoot.cs +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyExcludingRoot.javaEvitaDB.Client/Queries/Filter/HierarchyExcludingRoot.cs is a constraint that can only be used within `hierarchyWithin` or `hierarchyWithinRoot` parent constraints. It simply makes no sense anywhere else because it changes the default behavior of those constraints. Hierarchy constraints return -all hierarchy children of the parent node or entities that are transitively or directly related to them and the parent +all hierarchy children of the parent node or entities that are transitively or directly related to them and the parent node itself. When the `excludingRoot` is used as a sub-constraint, this behavior changes and the parent node itself or the entities directly related to that parent node are be excluded from the result. @@ -529,8 +529,8 @@ excludingRoot() ### Self -If the hierarchy constraint targets the hierarchy entity, the `excludingRoot` will omit the requested parent node from -the result. In the case of the `hierarchyWithinRoot` constraint, the parent is an invisible "virtual" top root, and this +If the hierarchy constraint targets the hierarchy entity, the `excludingRoot` will omit the requested parent node from +the result. In the case of the `hierarchyWithinRoot` constraint, the parent is an invisible "virtual" top root, and this constraint makes no sense. @@ -547,30 +547,30 @@ As we can see the requested parent category *Accessories* is excluded from the r ##### List of all subcategories of the *Accessories* category except the *Accessories* category itself - + [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding-root.evitaql.md) - + - + [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding-root.graphql.json.md) - + - + [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding-root.rest.json.md) - + ### Referenced entity If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is -a product assigned to a category), the `excludingRoot` constraint can only be used in the `hierarchyWithin` parent +a product assigned to a category), the `excludingRoot` constraint can only be used in the `hierarchyWithin` parent constraint. In the case of `hierarchyWithinRoot`, the `excludingRoot` constraint makes no sense because no entity can be assigned @@ -596,39 +596,39 @@ assigned to *Exotic keyboards*: ##### List of all products related to subcategories of the *Keyboard* category except to the *Keyboard* category itself - + [Products in subcategories of Keyboard category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-excluding-root.evitaql.md) - + - + [Products in subcategories of Keyboard category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-excluding-root.graphql.json.md) - + - + [Products in subcategories of Keyboard category](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-excluding-root.rest.json.md) - + ## Having -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyHaving.javaEvitaDB.Client/Queries/Filter/HierarchyHaving.cs +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyHaving.javaEvitaDB.Client/Queries/Filter/HierarchyHaving.cs is a constraint that can only be used within `hierarchyWithin` or `hierarchyWithinRoot` parent constraints. It simply makes no sense anywhere else because it changes the default behavior of those constraints. Hierarchy constraints return all hierarchy children of the parent node or entities that are transitively or directly related to them, and the parent node itself. The `having` constraint allows you to set a constraint that must be fulfilled by all categories in the category scope -in order to be accepted by hierarchy within filter. This constraint is especially useful if you want to conditionally -display certain parts of the tree. Imagine you have a category *Christmas Sale* that should only be available during +in order to be accepted by hierarchy within filter. This constraint is especially useful if you want to conditionally +display certain parts of the tree. Imagine you have a category *Christmas Sale* that should only be available during a certain period of the year, or a category *B2B Partners* that should only be accessible to a certain role of users. -All of these scenarios can take advantage of the `having` constraint (but there are other approaches to solving the +All of these scenarios can take advantage of the `having` constraint (but there are other approaches to solving the above use cases). @@ -638,8 +638,8 @@ above use cases). ##### The lookup stops at the first node that doesn't satisfy the constraint! -The hierarchical query traverses from the root nodes to the leaf nodes. For each of the nodes, the engine checks whether -the `having` constraint is still valid, and if not, it excludes that hierarchy node and all of its child nodes (entire +The hierarchical query traverses from the root nodes to the leaf nodes. For each of the nodes, the engine checks whether +the `having` constraint is still valid, and if not, it excludes that hierarchy node and all of its child nodes (entire subtree). @@ -653,17 +653,17 @@ having(
    filterConstraint:+
    - one or more mandatory constraints that must be satisfied by all returned hierarchy nodes and that mark + one or more mandatory constraints that must be satisfied by all returned hierarchy nodes and that mark the visible part of the tree, the implicit relation between constraints is logical conjunction (boolean AND)
    ### Self -When the hierarchy constraint targets the hierarchy entity, the children that don't satisfy the inner constraints (and +When the hierarchy constraint targets the hierarchy entity, the children that don't satisfy the inner constraints (and their children, whether they satisfy them or not) are excluded from the result. -For demonstration purposes, let's list all categories within the *Accessories* category, but only those that are valid +For demonstration purposes, let's list all categories within the *Accessories* category, but only those that are valid at 01:00 AM on October 1, 2023. ![Accessories category listing with validity constraint](assets/accessories-category-listing-validity.png "Accessories category listing with validity constraint") @@ -673,8 +673,8 @@ at 01:00 AM on October 1, 2023. [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-having.evitaql)
    -Because the category *Christmas electronics* has its validity set to be valid only between December 1st and December -24th, it will be omitted from the result. If it had subcategories, they would also be omitted (even if they had no +Because the category *Christmas electronics* has its validity set to be valid only between December 1st and December +24th, it will be omitted from the result. If it had subcategories, they would also be omitted (even if they had no validity restrictions). @@ -684,31 +684,31 @@ validity restrictions). ##### List of all valid subcategories of the *Accessories* category - + [Accessories category listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-having.evitaql.md) - + - + [Accessories category listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-having.graphql.json.md) - + - + [Accessories category listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-having.rest.json.md) - + ### Referenced entity -If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is -a product assigned to a category), the `having` constraint is evaluated against the hierarchical entity (category), but -affects the queried non-hierarchical entities (products). It excludes all products referencing categories that don't +If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is +a product assigned to a category), the `having` constraint is evaluated against the hierarchical entity (category), but +affects the queried non-hierarchical entities (products). It excludes all products referencing categories that don't satisfy the `having` inner constraints. Let's use again our example with *Christmas electronics* that is valid only between 1st and 24th December. To list all @@ -719,7 +719,7 @@ products available at 01:00 AM on October 1, 2023, issue a following query: [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having.evitaql)
    -You can see that Christmas products like *Retlux Blue christmas lightning*, *Retlux Warm white christmas lightning* or +You can see that Christmas products like *Retlux Blue christmas lightning*, *Retlux Warm white christmas lightning* or *Emos Candlestick* are not present in the listing. @@ -729,23 +729,23 @@ You can see that Christmas products like *Retlux Blue christmas lightning*, *Ret ##### List of all *Accessories* products valid in October 2023 - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having.evitaql.md) - + - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having.graphql.json.md) - + - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having.rest.json.md) - + @@ -765,23 +765,23 @@ When you change the date and time in range constraint for *validity* attribute t ##### List of all *Accessories* products valid in December 2023 - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having-december.evitaql.md) - + - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having-december.graphql.json.md) - + - + [Accessories category product listing with validity constraint](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-having-december.rest.json.md) - + @@ -792,19 +792,19 @@ When you change the date and time in range constraint for *validity* attribute t ##### What if the product is linked to two categories - one that meets the constraint and one that does not? -In the situation where the single product, let's say *Garmin Vivosmart 5*, is in both the excluded category *Christmas +In the situation where the single product, let's say *Garmin Vivosmart 5*, is in both the excluded category *Christmas Electronics* and the included category *Smartwatches*, as on the following schematics: ![Accessories category listing with validity constraint](assets/accessories-category-listing-validity.png "Accessories category listing with validity constraint") -... it will remain in the query result because there is at least one product reference that is part of the visible part +... it will remain in the query result because there is at least one product reference that is part of the visible part of the tree. ## Excluding -The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyExcluding.javaEvitaDB.Client/Queries/Filter/HierarchyExcluding.cs +The constraint evita_query/src/main/java/io/evitadb/api/query/filter/HierarchyExcluding.javaEvitaDB.Client/Queries/Filter/HierarchyExcluding.cs is a constraint that can only be used within `hierarchyWithin` or `hierarchyWithinRoot` parent constraints. It simply makes no sense anywhere else because it changes the default behavior of those constraints. Hierarchy constraints return all hierarchy children of the parent node or entities that are transitively or directly related to them, and the parent @@ -812,7 +812,7 @@ node itself. The `excluding` constraint allows you to exclude one or more subtrees from the scope of the filter. This constraint is the exact opposite of the [`having`](#having) constraint. If the constraint is true for a hierarchy entity, it and all -of its children are excluded from the query. The `excluding` constraint is the same as declaring +of its children are excluded from the query. The `excluding` constraint is the same as declaring `having(not(expression))`, but for the sake of readability it has its own constraint. @@ -823,7 +823,7 @@ of its children are excluded from the query. The `excluding` constraint is the s The hierarchical query traverses from the root nodes to the leaf nodes. For each of the nodes, the engine checks whether -the `excluding` constraint is satisfied valid, and if so, it excludes that hierarchy node and all of its child nodes +the `excluding` constraint is satisfied valid, and if so, it excludes that hierarchy node and all of its child nodes (entire subtree). @@ -837,7 +837,7 @@ excluding(
    filterConstraint:+
    - one or more mandatory constraints that must be satisfied by all returned hierarchy nodes and that mark + one or more mandatory constraints that must be satisfied by all returned hierarchy nodes and that mark the visible part of the tree, the implicit relation between constraints is logical conjunction (boolean AND)
    @@ -866,34 +866,34 @@ The category *Wireless Headphones* and all its subcategories will not be shown i ##### List of all subcategories of the *Accessories* category except *Wireless headphones* - + [Accessories category listing excluding *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding.evitaql.md) - + - + [Accessories category listing excluding *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding.graphql.json.md) - + - + [Accessories category listing excluding *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-self-excluding.rest.json.md) - + ### Referenced entity If the hierarchy constraint targets a non-hierarchical entity that references the hierarchical one (typical example is -a product assigned to a category), the `excluding` constraint is evaluated against the hierarchical entity (category), -but affects the queried non-hierarchical entities (products). It excludes all products referencing categories that +a product assigned to a category), the `excluding` constraint is evaluated against the hierarchical entity (category), +but affects the queried non-hierarchical entities (products). It excludes all products referencing categories that satisfy the `excluding` inner constraints. -Let's go back to our example query that excludes the *Wireless Headphones* category subtree. To list all products +Let's go back to our example query that excludes the *Wireless Headphones* category subtree. To list all products available in the *Accessories* category except those related to the *Wireless Headphones* category or its subcategories, issue the following query: @@ -902,7 +902,7 @@ issue the following query: [Category listing excluding parent](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-except.evitaql) -You can see that wireless headphone products like *Huawei FreeBuds 4*, *Jabra Elite 3* or *Adidas FWD-02 Sport* are not +You can see that wireless headphone products like *Huawei FreeBuds 4*, *Jabra Elite 3* or *Adidas FWD-02 Sport* are not present in the listing. @@ -912,23 +912,23 @@ present in the listing. ##### List of all *Accessories* products except *Wireless headphones* - + [Accessories category product listing except *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-except.evitaql.md) - + - + [Accessories category product listing except *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-except.graphql.json.md) - + - + [Accessories category product listing except *Wireless headphones*](/documentation/user/en/query/filtering/examples/hierarchy/hierarchy-within-reference-except.rest.json.md) - + diff --git a/documentation/user/en/query/filtering/locale.md b/documentation/user/en/query/filtering/locale.md index 4eccee3bc..7cecf8494 100644 --- a/documentation/user/en/query/filtering/locale.md +++ b/documentation/user/en/query/filtering/locale.md @@ -1,9 +1,9 @@ --- title: Locale filtering perex: | - Numerous e-commerce applications function in various regions and rely on localized data. While product labels and - descriptions are clear examples, there are also several numeric values that must be specific to each locale due to - the distinction between the metric system and imperial units. That's why evitaDB offers first-class support for + Numerous e-commerce applications function in various regions and rely on localized data. While product labels and + descriptions are clear examples, there are also several numeric values that must be specific to each locale due to + the distinction between the metric system and imperial units. That's why evitaDB offers first-class support for localization in its data structures and query language. date: '27.5.2023' author: 'Ing. Jan Novotný' @@ -22,13 +22,13 @@ entityLocaleEquals(
    argument:string!
    - a mandatory specification of the [locale](https://en.wikipedia.org/wiki/IETF_language_tag) to which all - localized attributes targeted by the query must conform; examples of a valid language tags are: `en-US` or + a mandatory specification of the [locale](https://en.wikipedia.org/wiki/IETF_language_tag) to which all + localized attributes targeted by the query must conform; examples of a valid language tags are: `en-US` or `en-GB`, `cs` or `cs-CZ`, `de` or `de-AT`, `de-CH`, `fr` or `fr-CA` etc.
    -If you are working with evitaDB in Java, you can use [`Locale`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html)[`CultureInfo`](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo) +If you are working with evitaDB in Java, you can use [`Locale`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html)[`CultureInfo`](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo) instead of the language tag. This is a natural way to work with locale specific data on the platform. @@ -39,54 +39,54 @@ instead of the language tag. This is a natural way to work with locale specific The language tag, also known as the locale or language identifier, is a standardized format used to represent a specific -language or locale in computer systems and software. It provides a way to identify and differentiate languages, +language or locale in computer systems and software. It provides a way to identify and differentiate languages, dialects, and regional variations. -The most commonly used format for language tags is the [BCP 47](https://www.rfc-editor.org/info/bcp47) (IETF Best +The most commonly used format for language tags is the [BCP 47](https://www.rfc-editor.org/info/bcp47) (IETF Best Current Practice 47) standard. BCP 47 defines a syntax and set of rules for constructing language tags. -A language tag is typically constructed using a combination of subtags that represent various components. Here's an +A language tag is typically constructed using a combination of subtags that represent various components. Here's an example breakdown of a language tag: `en-US`. -1. **Primary Language Subtag:** In the example above, *en* represents the primary language subtag, which indicates +1. **Primary Language Subtag:** In the example above, *en* represents the primary language subtag, which indicates English as the primary language. -2. **Region Subtag:** The region subtag is optional and represents a specific region or country associated with +2. **Region Subtag:** The region subtag is optional and represents a specific region or country associated with the language. In the example, *US* represents the United States. -Language tags can also include additional subtags to specify variations such as script, variant, and extensions, +Language tags can also include additional subtags to specify variations such as script, variant, and extensions, allowing for more granular language identification. - + In the GraphQL API, for ease of use, we convert all locales defined in stored data into an enum for better code completion. However, the GraphQL doesn't support hyphens in enum items, and thus we use underscores instead. Otherwise, the syntax is the same. - + If any filter constraint of the query targets a localized attribute, the `entityLocaleEquals` must also be provided, -otherwise the query interpreter will return an error. Localized attributes **must** be identified by both their name +otherwise the query interpreter will return an error. Localized attributes **must** be identified by both their name and language tag in order to be used. -Only a single occurrence of `entityLocaleEquals` is allowed in the filter part of the query. Currently, there is no way -to switch context between different parts of the filter and build queries such as *find a product whose name in `en-US` +Only a single occurrence of `entityLocaleEquals` is allowed in the filter part of the query. Currently, there is no way +to switch context between different parts of the filter and build queries such as *find a product whose name in `en-US` is "screwdriver" or in `cs` is "šroubovák"*. -Also, it's not possible to omit the language specification for a localized attribute and ask questions like: *find +Also, it's not possible to omit the language specification for a localized attribute and ask questions like: *find a product whose name in any language is "screwdriver"*. -While it's technically possible to implement support for these tasks in evitaDB, they represent edge cases, and there +While it's technically possible to implement support for these tasks in evitaDB, they represent edge cases, and there were more important scenarios to handle. -To test the locale specific query, we need to focus on the *Vouchers for shareholders* category in our -[demo dataset](/documentation/get-started/query-our-dataset). We know that there are products that have only English +To test the locale specific query, we need to focus on the *Vouchers for shareholders* category in our +[demo dataset](/documentation/get-started/query-our-dataset). We know that there are products that have only English (*en_US*) localization. To select the products with English localization, we can issue this query: @@ -104,30 +104,30 @@ To test the locale specific query, we need to focus on the *Vouchers for shareho ##### List of all products with English localization in category - + [List of all products with English localization](/documentation/user/en/query/filtering/examples/locale/locale.evitaql.md) - + - + [List of all products with English localization](/documentation/user/en/query/filtering/examples/locale/locale.graphql.json.md) - + - + [List of all products with English localization](/documentation/user/en/query/filtering/examples/locale/locale.rest.json.md) - + -You will notice that the output contains two columns: *code* and *name*. The *code* is not a localized attribute, while -the *name* is. The names listed in the response reflect the English locale that is part of the filter constraint. +You will notice that the output contains two columns: *code* and *name*. The *code* is not a localized attribute, while +the *name* is. The names listed in the response reflect the English locale that is part of the filter constraint. -If you use `entityLocaleEquals` in your filter, all returned localized data (both -[attributes](../../use/data-model.md#localized-attributes) and [associated data](../../use/data-model.md#localized-associated-data)) -will respect the filtered locale. If you need data for locales other than the one used in the filter constraint, +If you use `entityLocaleEquals` in your filter, all returned localized data (both +[attributes](../../use/data-model.md#localized-attributes) and [associated data](../../use/data-model.md#localized-associated-data)) +will respect the filtered locale. If you need data for locales other than the one used in the filter constraint, you can use the require constraint [`data-in-locale`](../requirements/fetching.md#data-in-locale). @@ -148,22 +148,22 @@ But when we request products in Czech locale: ##### List of all products with Czech localization in category - + [List of all products with Czech localization](/documentation/user/en/query/filtering/examples/locale/locale_missing.evitaql.md) - + - + [List of all products with Czech localization](/documentation/user/en/query/filtering/examples/locale/locale_missing.graphql.json.md) - + - + [List of all products with Czech localization](/documentation/user/en/query/filtering/examples/locale/locale_missing.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/filtering/logical.md b/documentation/user/en/query/filtering/logical.md index 5c3474cd6..7ee25a78c 100644 --- a/documentation/user/en/query/filtering/logical.md +++ b/documentation/user/en/query/filtering/logical.md @@ -1,7 +1,7 @@ --- title: Logical filtering perex: | - Logical expressions are the cornerstone of any query language and evitaDB is no different. They allow you to combine + Logical expressions are the cornerstone of any query language and evitaDB is no different. They allow you to combine multiple filter expressions into one unambiguous expression. date: '26.5.2023' author: 'Ing. Jan Novotný' @@ -16,7 +16,7 @@ preferredLang: 'evitaql' ##### What if the logical binding is not set explicitly? -To make the query language more concise, we omit logical binding in container-type filtering constraints and assume +To make the query language more concise, we omit logical binding in container-type filtering constraints and assume a logical conjunctive relation "and at the same time" ([`and`](#and)) unless an explicit binding is set. For example, you can issue the following query: @@ -25,8 +25,8 @@ For example, you can issue the following query: [Implicit binding example](/documentation/user/en/query/filtering/examples/logical/implicit-binding.evitaql) -As you can see - there is no logical binding between `entityPrimaryKeyInSet` and `attributeEquals` constraints, and for -this case the logical conjunction will be applied, which will result in a single returned product with *code* +As you can see - there is no logical binding between `entityPrimaryKeyInSet` and `attributeEquals` constraints, and for +this case the logical conjunction will be applied, which will result in a single returned product with *code* *lenovo-thinkpad-t495-2* in the response. @@ -39,14 +39,14 @@ and( ) ``` -
    +
    filterConstraint:any+
    one or more mandatory filter constraints that will produce logical conjunction
    -The evita_query/src/main/java/io/evitadb/api/query/filter/And.javaEvitaDB.Client/Queries/Filter/And.cs container represents +The evita_query/src/main/java/io/evitadb/api/query/filter/And.javaEvitaDB.Client/Queries/Filter/And.cs container represents a [logical conjunction](https://en.wikipedia.org/wiki/Logical_conjunction), that is demonstrated on following table: | A | B | A ∧ B | @@ -63,7 +63,7 @@ The following query: [Logical conjunction example](/documentation/user/en/query/filtering/examples/logical/and.evitaql) -... returns a single result - product with entity primary key *106742*, which is the only one that all three +... returns a single result - product with entity primary key *106742*, which is the only one that all three `entityPrimaryKeyInSet` constraints have in common. @@ -73,23 +73,23 @@ The following query: ##### List of all products matching conjunction filter - + [Logical conjunction example result](/documentation/user/en/query/filtering/examples/logical/and.evitaql.md) - + - + [Logical conjunction example result](/documentation/user/en/query/filtering/examples/logical/and.graphql.json.md) - + - + [Logical conjunction example result](/documentation/user/en/query/filtering/examples/logical/and.rest.json.md) - + @@ -101,14 +101,14 @@ or( ) ``` -
    +
    filterConstraint:any+
    one or more mandatory filter constraints that will produce logical disjunction
    -The evita_query/src/main/java/io/evitadb/api/query/filter/Or.javaEvitaDB.Client/Queries/Filter/Or.cs container represents +The evita_query/src/main/java/io/evitadb/api/query/filter/Or.javaEvitaDB.Client/Queries/Filter/Or.cs container represents a [logical disjunction](https://en.wikipedia.org/wiki/Logical_disjunction), that is demonstrated on following table: | A | B | A ∨ B | @@ -134,23 +134,23 @@ The following query: ##### List of all products matching disjunction filter - + [Logical disjunction example result](/documentation/user/en/query/filtering/examples/logical/or.evitaql.md) - + - + [Logical disjunction example result](/documentation/user/en/query/filtering/examples/logical/or.graphql.json.md) - + - + [Logical disjunction example result](/documentation/user/en/query/filtering/examples/logical/or.rest.json.md) - + @@ -162,14 +162,14 @@ not( ) ``` -
    +
    filterConstraint:any!
    one or more mandatory filter constraints that will be subtracted from the superset of all entities
    -The evita_query/src/main/java/io/evitadb/api/query/filter/Not.javaEvitaDB.Client/Queries/Filter/Not.cs container represents +The evita_query/src/main/java/io/evitadb/api/query/filter/Not.javaEvitaDB.Client/Queries/Filter/Not.cs container represents a [logical negation](https://en.wikipedia.org/wiki/Negation), that is demonstrated on following table: | A | ¬ A | @@ -193,23 +193,23 @@ The following query: ##### List of all products matching negation filter - + [Logical negation example result](/documentation/user/en/query/filtering/examples/logical/not.evitaql.md) - + - + [Logical negation example result](/documentation/user/en/query/filtering/examples/logical/not.graphql.json.md) - + - + [Logical negation example result](/documentation/user/en/query/filtering/examples/logical/not.rest.json.md) - + @@ -229,22 +229,22 @@ Because this situation is hard to visualize - let's narrow our super set to only ##### List of all products matching negation filter (narrowed) - + [Logical negation example result (narrowed)](/documentation/user/en/query/filtering/examples/logical/not-narrowed.evitaql.md) - + - + [Logical negation example result (narrowed)](/documentation/user/en/query/filtering/examples/logical/not-narrowed.graphql.json.md) - + - + [Logical negation example result (narrowed)](/documentation/user/en/query/filtering/examples/logical/not-narrowed.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/filtering/price.md b/documentation/user/en/query/filtering/price.md index 9b48f93e4..e037b71aa 100644 --- a/documentation/user/en/query/filtering/price.md +++ b/documentation/user/en/query/filtering/price.md @@ -2,16 +2,16 @@ title: Price filtering date: '7.11.2023' perex: | - In the realm of e-commerce, users expect to see prices that are personalized to their context: local currency for easy - understanding, accurate selling prices from the correct price list, and timely offers that may only be valid during - specific periods. Catering to these expectations with sophisticated database filtering not only enhances user + In the realm of e-commerce, users expect to see prices that are personalized to their context: local currency for easy + understanding, accurate selling prices from the correct price list, and timely offers that may only be valid during + specific periods. Catering to these expectations with sophisticated database filtering not only enhances user experience but also streamlines the shopping process, boosting satisfaction and sales. author: 'Ing. Jan Novotný' proofreading: 'done' preferredLang: 'evitaql' --- -This chapter contains the description of evitaDB constraints that help you to control the price for sale selection and +This chapter contains the description of evitaDB constraints that help you to control the price for sale selection and to filter products by price. ## Quick guide to filtering by price @@ -30,7 +30,7 @@ To correctly identify an appropriate selling price, you must specify all three c 1. [`priceInCurrency`](#price-in-currency) - the currency of the price for sale 2. [`priceValidIn`](#price-valid-in) - the date and time at which the price for the sale must be valid -3. [`priceInPriceLists`](#price-in-price-lists) - the set of price lists for which the customer is eligible, sorted +3. [`priceInPriceLists`](#price-in-price-lists) - the set of price lists for which the customer is eligible, sorted from most preferred to least preferred. @@ -39,8 +39,8 @@ Only a single occurrence of any of these three constraints is allowed in the fil is no way to switch context between different parts of the filter and build queries such as *find a product whose price is either in "CZK" or "EUR" currency at this or that time* using this constraint. -While it's technically possible to implement support for these tasks in evitaDB, they represent edge cases and there -were more important scenarios to handle. Multiple combinations of these constraints will effectively stop finding +While it's technically possible to implement support for these tasks in evitaDB, they represent edge cases and there +were more important scenarios to handle. Multiple combinations of these constraints will effectively stop finding a correct selling price and would only allow returning matching entities without a selling price. @@ -55,35 +55,35 @@ a correct selling price and would only allow returning matching entities without The result set contains only products that have a valid price for sale in EUR currency: - + [The result of listing products with valid EUR price](/documentation/user/en/query/filtering/examples/price/price.evitaql.md) - - + + [The result of listing products with valid EUR price](/documentation/user/en/query/filtering/examples/price/price.graphql.json.md) - - + + [The result of listing products with valid EUR price](/documentation/user/en/query/filtering/examples/price/price.rest.json.md) - + ### Price for sale selection in a nutshell -If you find any statements in this chapter unclear, please read the [price for sale calculation algorithm documentation](/documentation/user/en/deep-dive/price-for-sale-calculation.md), where you will find more examples and step-by-step +If you find any statements in this chapter unclear, please read the [price for sale calculation algorithm documentation](/documentation/user/en/deep-dive/price-for-sale-calculation.md), where you will find more examples and step-by-step breakdown of the procedure. -The price for sale selection depends on evita_api/src/main/java/io/evitadb/api/requestResponse/data/PriceInnerRecordHandling.javaEvitaDB.Client/Models/Data/PriceInnerRecordHandling.cs -mode the [entity has set](../../use/data-model.md#entity), but for all of the modes there is a common denominator - +The price for sale selection depends on evita_api/src/main/java/io/evitadb/api/requestResponse/data/PriceInnerRecordHandling.javaEvitaDB.Client/Models/Data/PriceInnerRecordHandling.cs +mode the [entity has set](../../use/data-model.md#entity), but for all of the modes there is a common denominator - the price for sale is selected from [prices](../../use/data-model.md#prices) marked as `sellable` that conform to the selected [currency](#price-in-currency) and [price lists](#price-in-price-lists) and are valid at the specified [time](#price-valid-in). The first price that matches all of these criteria in the order of the price lists in the @@ -94,14 +94,14 @@ For non-default price inner record handling modes, the price is calculated this
    FIRST_OCCURRENCE
    - The sales price is selected as the lowest sales price calculated separately for blocks of prices with the same + The sales price is selected as the lowest sales price calculated separately for blocks of prices with the same inner record id. If the [price between](#price-between) constraint is specified, the price is the lowest selling price valid for the specified price range.
    SUM
    - The sales price is calculated as the sum of the sales prices calculated separately for blocks of prices with - the same inner record ID. If the [price between](#price-between) constraint is specified, the sales price is + The sales price is calculated as the sum of the sales prices calculated separately for blocks of prices with + the same inner record ID. If the [price between](#price-between) constraint is specified, the sales price is valid only if the total is within the specified price range.
    @@ -123,22 +123,22 @@ priceInCurrency(
- + -If you are working with evitaDB in Java, you can use [`Currency`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Currency.html) -instead of the [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) ISO code. +If you are working with evitaDB in Java, you can use [`Currency`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Currency.html) +instead of the [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) ISO code. This is a natural way to work with locale specific data on the platform. - - + + If you are working with evitaDB in C#, you can use custom EvitaDB.Client/DataTypes/Currency.cs class -which was created for compliance with evitaDB Java API. It's a simple wrapper around [string](https://docs.microsoft.com/en-us/dotnet/api/system.string) ISO code, +which was created for compliance with evitaDB Java API. It's a simple wrapper around [string](https://docs.microsoft.com/en-us/dotnet/api/system.string) ISO code, that may be provided in its raw form without the need to create an instance of the class. - + -The evita_query/src/main/java/io/evitadb/api/query/filter/PriceInCurrency.javaEvitaDB.Client/Queries/Filter/PriceInCurrency.cs constraint +The evita_query/src/main/java/io/evitadb/api/query/filter/PriceInCurrency.javaEvitaDB.Client/Queries/Filter/PriceInCurrency.cs constraint can be used to limit the result set to entities that have a price in the specified currency. Except for the [standard use-case](#typical-usage-of-price-constraints) you can also create query with this constraint only: @@ -158,21 +158,21 @@ use-case](#typical-usage-of-price-constraints) you can also create query with th The result set contains only products that have at least one price in EUR currency: - + [The result of listing products with any price in EUR currency](/documentation/user/en/query/filtering/examples/price/price-in-currency.evitaql.md) - - + + [The result of listing products with any price in EUR currency](/documentation/user/en/query/filtering/examples/price/price-in-currency.graphql.json.md) - - + + [The result of listing products with any price in EUR currency](/documentation/user/en/query/filtering/examples/price/price-in-currency.rest.json.md) - +
@@ -187,21 +187,21 @@ priceInPriceLists(
argument:string+
- A mandatory specification of one or more price list names in order of priority from most preferred to least + A mandatory specification of one or more price list names in order of priority from most preferred to least preferred.
-The evita_query/src/main/java/io/evitadb/api/query/filter/PriceInPriceLists.javaEvitaDB.Client/Queries/Filter/PriceInPriceLists.cs constraint -defines the allowed set(s) of price lists that the entity must have to be included in the result set. The order of -the price lists in the argument is important for the final price for sale calculation - see the -[price for sale calculation algorithm documentation](/documentation/user/en/deep-dive/price-for-sale-calculation.md). -Price list names are represented by plain [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://docs.microsoft.com/en-us/dotnet/api/system.string) -and are case-sensitive. Price lists don't have to be stored in the database as an entity, and if they are, they are not -currently associated with the price list code defined in the prices of other entities. The pricing structure is simple +The evita_query/src/main/java/io/evitadb/api/query/filter/PriceInPriceLists.javaEvitaDB.Client/Queries/Filter/PriceInPriceLists.cs constraint +defines the allowed set(s) of price lists that the entity must have to be included in the result set. The order of +the price lists in the argument is important for the final price for sale calculation - see the +[price for sale calculation algorithm documentation](/documentation/user/en/deep-dive/price-for-sale-calculation.md). +Price list names are represented by plain [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://docs.microsoft.com/en-us/dotnet/api/system.string) +and are case-sensitive. Price lists don't have to be stored in the database as an entity, and if they are, they are not +currently associated with the price list code defined in the prices of other entities. The pricing structure is simple and flat for now (but this may change in the future). -Except for the [standard use-case](#typical-usage-of-price-constraints) you can also create query with this constraint +Except for the [standard use-case](#typical-usage-of-price-constraints) you can also create query with this constraint only: @@ -220,21 +220,21 @@ only: The result set contains only products that have at least one price in one of the VIP price lists mentioned: - + [The result of listing products with any price in one of the VIP price lists](/documentation/user/en/query/filtering/examples/price/price-in-price-lists.evitaql.md) - - + + [The result of listing products with any price in one of the VIP price lists](/documentation/user/en/query/filtering/examples/price/price-in-price-lists.graphql.json.md) - - + + [The result of listing products with any price in one of the VIP price lists](/documentation/user/en/query/filtering/examples/price/price-in-price-lists.rest.json.md) - + @@ -250,16 +250,16 @@ priceValidIn(
argument:offsetDateTime!
A mandatory argument of date and time (with offset) in the format `yyyy-MM-ddTHH:mm:ssXXX`, for example - `2007-12-03T10:15:30+01:00`. In Java language you can use directly [OffsetDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/OffsetDateTime.html)In C# language you can use directly [DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset) + `2007-12-03T10:15:30+01:00`. In Java language you can use directly [OffsetDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/OffsetDateTime.html)In C# language you can use directly [DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset)
-The evita_query/src/main/java/io/evitadb/api/query/filter/PriceValidIn.javaEvitaDB.Client/Queries/Filter/PriceValidIn.cs excludes all +The evita_query/src/main/java/io/evitadb/api/query/filter/PriceValidIn.javaEvitaDB.Client/Queries/Filter/PriceValidIn.cs excludes all entities that don't have a valid price for sale at the specified date and time. If the price doesn't have a validity property specified, it passes all validity checks. -To demonstrate the effect of validity constraints, let's create a query that lists products in the *Christmas -Electronics* category and tries to access prices in their *Christmas Price List*, with a fallback to the *Basic Price +To demonstrate the effect of validity constraints, let's create a query that lists products in the *Christmas +Electronics* category and tries to access prices in their *Christmas Price List*, with a fallback to the *Basic Price List*, using a spring holiday date and time as the reference point for the price validity check: @@ -278,21 +278,21 @@ Now let's update the query to use a date and time in December: As you can see, you'll get a somewhat different sale price because the Christmas prices have now been applied: - + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in-correct.evitaql.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in-correct.graphql.json.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in-correct.rest.json.md) - + @@ -304,21 +304,21 @@ As you can see, you'll get a somewhat different sale price because the Christmas The prices for the sale in May were different, because the Christmas prices were not valid at that time: - + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in.evitaql.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in.graphql.json.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-valid-in.rest.json.md) - + @@ -341,18 +341,18 @@ priceBetween( ) ``` - +
argument:bigDecimal!
A mandatory argument of the price range lower bound. The price range is inclusive, so the price must be greater - than or equal to the lower bound. In the Java language you can use directly [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) in plain text format, you must use the string representation of the number. + than or equal to the lower bound. In the Java language you can use directly [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) in plain text format, you must use the string representation of the number.
argument:bigDecimal!
A mandatory argument of the price range upper bound. The price range is inclusive, so the price must be lesser - than or equal to the upper bound. In the Java language you can use directly [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) in plain text format, you must use the string representation of the number. + than or equal to the upper bound. In the Java language you can use directly [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) in plain text format, you must use the string representation of the number.
@@ -362,20 +362,20 @@ typically set by the user interface to allow the user to filter products by pric the [`userFilter`](behavioral.md#user-filter) constraint container so that it can be properly handled by the [facet](../requirements/facet.md) or [histogram](../requirements/histogram.md) computations. -
+ - +
argument:decimal!
A mandatory argument of the price range lower bound. The price range is inclusive, so the price must be greater - than or equal to the lower bound. In the C# language you can use directly [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) in plain text format, you must use the string representation of the number. + than or equal to the lower bound. In the C# language you can use directly [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) in plain text format, you must use the string representation of the number.
argument:decimal!
A mandatory argument of the price range upper bound. The price range is inclusive, so the price must be lesser - than or equal to the upper bound. In the C# language you can use directly [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) in plain text format, you must use the string representation of the number. + than or equal to the upper bound. In the C# language you can use directly [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) in plain text format, you must use the string representation of the number.
@@ -385,7 +385,7 @@ typically set by the user interface to allow the user to filter products by pric the [`userFilter`](behavioral.md#user-filter) constraint container so that it can be properly handled by the [facet](../requirements/facet.md) or [histogram](../requirements/histogram.md) computations. -
+ To demonstrate the price range constraint, let's create a query that lists products in the *E-readers* category and filters only those between `€150` and `€170.5`: @@ -398,18 +398,18 @@ filters only those between `€150` and `€170.5`: The range is quite narrow, so the result set contains only a single product: - + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-between.evitaql.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-between.graphql.json.md) - - + + [Compare December prices with May prices](/documentation/user/en/query/filtering/examples/price/price-between.rest.json.md) - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/query/filtering/range.md b/documentation/user/en/query/filtering/range.md index 6ae510490..012abd88e 100644 --- a/documentation/user/en/query/filtering/range.md +++ b/documentation/user/en/query/filtering/range.md @@ -3,7 +3,7 @@ title: Range filtering date: '17.1.2023' perex: | Range filtering is used to filter entities by the value of their attributes that are of a range type. It allows you to - reduce the entity set to those entities whose range attribute includes the parameter value. If the parameter value is + reduce the entity set to those entities whose range attribute includes the parameter value. If the parameter value is itself a range, only those entities with an overlapping range attribute will be matched. author: 'Ing. Jan Novotný' proofreading: 'done' @@ -11,7 +11,7 @@ preferredLang: 'evitaql' --- -In the context of the limitations described in this chapter, you might be interested in the general rules for handling +In the context of the limitations described in this chapter, you might be interested in the general rules for handling data types and arrays described in [the query language basics](../basics.md#generic-query-rules). @@ -22,13 +22,13 @@ attributeInRange( argument:string!, argument:comparable! ) -``` +```
argument:string!
- the name of the [entity attribute](../../use/schema.md#attributes) whose [number range](../../use/data-types.md#numberrange) - or [datetime range](../../use/data-types.md#datetimerange) value starts, ends, or encloses the value + the name of the [entity attribute](../../use/schema.md#attributes) whose [number range](../../use/data-types.md#numberrange) + or [datetime range](../../use/data-types.md#datetimerange) value starts, ends, or encloses the value in the second argument
argument:comparable!
@@ -38,7 +38,7 @@ attributeInRange(
The `attributeInRange` checks whether the value in the second argument is within the range of the attribute value. -The value is within the range if it is equal to the start or end of the range or if it is between the start and end of +The value is within the range if it is equal to the start or end of the range or if it is between the start and end of the range. @@ -46,9 +46,9 @@ the range. [Products valid for December '23](/documentation/user/en/query/filtering/examples/range/attribute-in-range.evitaql) -Returns a list of products with a *valid* date/time range that includes the date "2023-12-05T12:00:00+01:00" - these are -the products targeted for the holiday sale. In a real-world query, you would probably want to combine this constraint -with [attribute is](comparable.md#attribute-is) `NULL` using the [logical OR](logical.md#or) operator to also match +Returns a list of products with a *valid* date/time range that includes the date "2023-12-05T12:00:00+01:00" - these are +the products targeted for the holiday sale. In a real-world query, you would probably want to combine this constraint +with [attribute is](comparable.md#attribute-is) `NULL` using the [logical OR](logical.md#or) operator to also match products that have no date/time range attribute at all. @@ -58,23 +58,23 @@ products that have no date/time range attribute at all. ##### Products valid for December '23 - + [Products valid for December '23](/documentation/user/en/query/filtering/examples/range/attribute-in-range.evitaql.md) - + - + [Products valid for December '23](/documentation/user/en/query/filtering/examples/range/attribute-in-range.graphql.json.md) - + - + [Products valid for December '23](/documentation/user/en/query/filtering/examples/range/attribute-in-range.rest.json.md) - + @@ -84,19 +84,19 @@ products that have no date/time range attribute at all. attributeInRangeNow( argument:string! ) -``` +```
argument:string!
- the name of the [entity attribute](../../use/schema.md#attributes) whose [number range](../../use/data-types.md#numberrange) - or [datetime range](../../use/data-types.md#datetimerange) value starts, ends, or encloses the value + the name of the [entity attribute](../../use/schema.md#attributes) whose [number range](../../use/data-types.md#numberrange) + or [datetime range](../../use/data-types.md#datetimerange) value starts, ends, or encloses the value in the second argument
The `attributeInRangeNow` checks whether the current date and time is within the range of the attribute value. -Current date and time is within the range if it is equal to the start or end of the range or if it is between the start +Current date and time is within the range if it is equal to the start or end of the range or if it is between the start and end of the range. @@ -104,6 +104,6 @@ and end of the range. [Products valid now](/documentation/user/en/query/filtering/examples/range/attribute-in-range-now.evitaql) -Returns a list of products with a *valid* date/time range that includes the current date and time. The result of -the example query cannot be listed here because it depends on the current date and time and may change from time to +Returns a list of products with a *valid* date/time range that includes the current date and time. The result of +the example query cannot be listed here because it depends on the current date and time and may change from time to time. \ No newline at end of file diff --git a/documentation/user/en/query/filtering/references.md b/documentation/user/en/query/filtering/references.md index de9f9bc74..aec306138 100644 --- a/documentation/user/en/query/filtering/references.md +++ b/documentation/user/en/query/filtering/references.md @@ -21,17 +21,17 @@ referenceHaving(
argument:string!
- the name of the [entity reference](../../use/schema.md#reference) that will be subjected to the filtering + the name of the [entity reference](../../use/schema.md#reference) that will be subjected to the filtering constraints in the second and subsequent arguments
filterConstraint:any+
- one or more filter constraints that must be satisfied by one of the entity references with name specified in + one or more filter constraints that must be satisfied by one of the entity references with name specified in the first argument
-The evita_query/src/main/java/io/evitadb/api/query/filter/ReferenceHaving.javaEvitaDB.Client/Queries/Filter/ReferenceHaving.cs constraint +The evita_query/src/main/java/io/evitadb/api/query/filter/ReferenceHaving.javaEvitaDB.Client/Queries/Filter/ReferenceHaving.cs constraint eliminates entities which has no reference of particular name satisfying set of filtering constraints. You can examine either the attributes specified on the relation itself or wrap the filtering constraint in [`entityHaving`](#entity-having) @@ -59,23 +59,23 @@ Returns the following result: - + [Products with at least one `relatedProducts` reference of `alternativeProduct` category](/documentation/user/en/query/filtering/examples/references/reference-having.evitaql.md) - + - + [Products with at least one `relatedProducts` reference of `alternativeProduct` category](/documentation/user/en/query/filtering/examples/references/reference-having.graphql.json.md) - + - + [Products with at least one `relatedProducts` reference of `alternativeProduct` category](/documentation/user/en/query/filtering/examples/references/reference-having.rest.json.md) - + @@ -97,23 +97,23 @@ Which returns the following result: - + [Products with at least one `relatedProducts` reference of any category](/documentation/user/en/query/filtering/examples/references/reference-having-any.evitaql.md) - + - + [Products with at least one `relatedProducts` reference of any category](/documentation/user/en/query/filtering/examples/references/reference-having-any.graphql.json.md) - + - + [Products with at least one `relatedProducts` reference of any category](/documentation/user/en/query/filtering/examples/references/reference-having-any.rest.json.md) - + @@ -136,30 +136,30 @@ Which returns the following result: - + [Products referencing `brand` of particular primary key](/documentation/user/en/query/filtering/examples/references/reference-having-exact-id.evitaql.md) - + - + [Products referencing `brand` of particular primary key](/documentation/user/en/query/filtering/examples/references/reference-having-exact-id.graphql.json.md) - + - + [Products referencing `brand` of particular primary key](/documentation/user/en/query/filtering/examples/references/reference-having-exact-id.rest.json.md) - + ## Entity having ```evitaql-syntax -entityHaving( +entityHaving( filterConstraint:any+ ) ``` @@ -167,7 +167,7 @@ entityHaving(
filterConstraint:any+
- one or more filter constraints that must be satisfied by the target referenced entity of any of the source + one or more filter constraints that must be satisfied by the target referenced entity of any of the source entity references identified by the parent `referenceHaving` constraint
@@ -196,23 +196,23 @@ Which returns the following result: - + [Products referencing `brand` of with code `apple`](/documentation/user/en/query/filtering/examples/references/entity-having.evitaql.md) - + - + [Products referencing `brand` of with code `apple`](/documentation/user/en/query/filtering/examples/references/entity-having.graphql.json.md) - + - + [Products referencing `brand` of with code `apple`](/documentation/user/en/query/filtering/examples/references/entity-having.rest.json.md) - + @@ -228,17 +228,17 @@ facetHaving(
argument:string!
- the name of the [entity reference](../../use/schema.md#reference) that will be subject to the filtering + the name of the [entity reference](../../use/schema.md#reference) that will be subject to the filtering constraints in the second and subsequent arguments
filterConstraint:any*
- zero or more filter constraints that identify the facet (reference) that must be present on the entities in + zero or more filter constraints that identify the facet (reference) that must be present on the entities in the result set
-The evita_query/src/main/java/io/evitadb/api/query/filter/FacetHaving.javaEvitaDB.Client/Queries/Filter/FacetHaving.cs filtering +The evita_query/src/main/java/io/evitadb/api/query/filter/FacetHaving.javaEvitaDB.Client/Queries/Filter/FacetHaving.cs filtering constraint is typically placed inside the [`userFilter`](behavioral.md#user-filter) constraint container and represents the user's request to drill down the result set by a particular facet. The `facetHaving` constraint works exactly like the [`referenceHaving`](#reference-having) constraint, but works in conjunction with @@ -277,22 +277,22 @@ Because the facet summary JSON is quite long and not very readable, we will only summary result in this documentation. As you can see, the selected facet is checked and the predicted numbers have changed accordingly: - + [The result of facet having filtering constraint](/documentation/user/en/query/filtering/examples/references/facet-having.evitaql.string.md) - + - + [The result of facet having filtering constraint](/documentation/user/en/query/filtering/examples/references/facet-having.graphql.json.md) - + - + [The result of facet having filtering constraint](/documentation/user/en/query/filtering/examples/references/facet-having.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/filtering/string.md b/documentation/user/en/query/filtering/string.md index 25181ecea..7e77a2462 100644 --- a/documentation/user/en/query/filtering/string.md +++ b/documentation/user/en/query/filtering/string.md @@ -2,7 +2,7 @@ title: String filtering date: '17.1.2023' perex: | - There are several filtering constraints designed to work especially with string attributes. They are useful for + There are several filtering constraints designed to work especially with string attributes. They are useful for looking for entities with attributes that contain a specific string. author: 'Ing. Jan Novotný' proofreading: 'done' @@ -10,7 +10,7 @@ preferredLang: 'evitaql' --- -In the context of the limitations described in this chapter, you might be interested in the general rules for handling +In the context of the limitations described in this chapter, you might be interested in the general rules for handling data types and arrays described in [the query language basics](../basics.md#generic-query-rules). @@ -26,7 +26,7 @@ attributeContains(
argument:string!
- the name of the [entity attribute](../../use/schema.md#attributes) whose value will be scanned for + the name of the [entity attribute](../../use/schema.md#attributes) whose value will be scanned for the occurrence of the string in the second argument
argument:string!
@@ -35,9 +35,9 @@ attributeContains(
-The `attributeContains` searches the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) -for the occurrence of the string. The constraint behaves exactly like the [Java `contains` method](https://www.javatpoint.com/java-string-contains)[C# `Contains` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.contains). -It's case-sensitive, works with national characters (since we're working with UTF-8 strings), and requires an exact +The `attributeContains` searches the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) +for the occurrence of the string. The constraint behaves exactly like the [Java `contains` method](https://www.javatpoint.com/java-string-contains)[C# `Contains` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.contains). +It's case-sensitive, works with national characters (since we're working with UTF-8 strings), and requires an exact match of the searched string anywhere in the attribute value. @@ -54,23 +54,23 @@ Returns a few products having a string *epix* in the attribute *code*. ##### Products having a `epix` string in the `code` attribute - + [Products having a `epix` string in the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-contains.evitaql.md) - + - + [Products having a `epix` string in the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-contains.graphql.json.md) - + - + [Products having a `epix` string in the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-contains.rest.json.md) - + @@ -86,7 +86,7 @@ attributeStartsWith(
argument:string!
- the name of the [entity attribute](../../use/schema.md#attributes) whose value will be tested to see if it + the name of the [entity attribute](../../use/schema.md#attributes) whose value will be tested to see if it starts with the string in the second argument
argument:string!
@@ -95,9 +95,9 @@ attributeStartsWith(
-The `attributeStartsWith` searches the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) -and checks if it starts with the specified string. The constraint behaves exactly like the [Java `startsWith` method](https://www.javatpoint.com/java-string-startswith)[C# `StartsWith` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.startswith). -It's case-sensitive, works with national characters (since we're working with UTF-8 strings), and requires an exact +The `attributeStartsWith` searches the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) +and checks if it starts with the specified string. The constraint behaves exactly like the [Java `startsWith` method](https://www.javatpoint.com/java-string-startswith)[C# `StartsWith` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.startswith). +It's case-sensitive, works with national characters (since we're working with UTF-8 strings), and requires an exact match of the search string at the beginning of the attribute value. @@ -114,23 +114,23 @@ Returns a few pages of products that start with a *garmin* string in the *code* ##### Products having a `garmin` string at the beginning of the `code` attribute - + [Products having a `garmin` string at the beginning of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-starts-with.evitaql.md) - + - + [Products having a `garmin` string at the beginning of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-starts-with.graphql.json.md) - + - + [Products having a `garmin` string at the beginning of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-starts-with.rest.json.md) - + @@ -146,7 +146,7 @@ attributeEndsWith(
argument:string!
- the name of the [entity attribute](../../use/schema.md#attributes) whose value will be tested to see if it ends + the name of the [entity attribute](../../use/schema.md#attributes) whose value will be tested to see if it ends with the string in the second argument
argument:string!
@@ -157,7 +157,7 @@ attributeEndsWith( The `attributeEndssWith` searches the filterable or unique entity [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) and checks if it ends with the specified string. The constraint behaves exactly like the -[Java `endsWith` method](https://www.javatpoint.com/java-string-endswith)[C# `EndsWith` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.endswith). +[Java `endsWith` method](https://www.javatpoint.com/java-string-endswith)[C# `EndsWith` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.endswith). It's case-sensitive, works with national characters (since we're working with UTF-8 strings), and requires an exact match of the search string at the end of the attribute value. @@ -175,22 +175,22 @@ Returns a few products that end with a *solar* string in the *code* attribute. ##### Products having a `solar` string at the end of the `code` attribute - + [Products having a `solar` string at the end of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-ends-with.evitaql.md) - + - + [Products having a `solar` string at the end of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-ends-with.graphql.json.md) - + - + [Products having a `solar` string at the end of the `code` attribute](/documentation/user/en/query/filtering/examples/string/attribute-ends-with.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/ordering/comparable.md b/documentation/user/en/query/ordering/comparable.md index 9fa14284b..270c50b19 100644 --- a/documentation/user/en/query/ordering/comparable.md +++ b/documentation/user/en/query/ordering/comparable.md @@ -27,7 +27,7 @@ attributeNatural(
the ordering direction (ascending or descending), **default value** is `ASC`
-
+ The constraint allows output entities to be sorted by their attributes in their natural order (numeric, alphabetical, temporal). It requires specification of a single [attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) @@ -47,23 +47,23 @@ To sort products by the number of their sales (the best-selling products first), ##### List of products sorted by number attribute - + [List of products sorted by number attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-non-localized.evitaql.md) - + - + [List of products sorted by number attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-non-localized.graphql.json.md) - + - + [List of products sorted by number attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-non-localized.rest.json.md) - + @@ -75,7 +75,7 @@ constraint in the `filterBy` part of the query: [List of products sorted by localized attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-localized.evitaql)
-The correct [collator](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/Collator.html)collator on the database side is used to +The correct [collator](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/Collator.html)collator on the database side is used to order the localized attribute string, so that the order is consistent with the national customs of the language. @@ -85,23 +85,23 @@ order the localized attribute string, so that the order is consistent with the n ##### List of products sorted by localized attribute - + [List of products sorted by localized attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-localized.evitaql.md) - + - + [List of products sorted by localized attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-localized.graphql.json.md) - + - + [List of products sorted by localized attribute](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-localized.rest.json.md) - + @@ -122,27 +122,27 @@ attribute, they are not sorted by the second attribute, but by the primary key ( ##### List of products sorted by multiple attributes - + [List of products sorted by multiple attributes](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-multiple.evitaql.md) - + - + [List of products sorted by multiple attributes](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-multiple.graphql.json.md) - + - + [List of products sorted by multiple attributes](/documentation/user/en/query/ordering/examples/comparable/attribute-natural-multiple.rest.json.md) - + -If we want to use fast "pre-sorted" indexes, there is no other way to do it, because the secondary order would not be +If we want to use fast "pre-sorted" indexes, there is no other way to do it, because the secondary order would not be known until a query time. If you want to sort by multiple attributes in the conventional way, you need to define the [sortable attribute compound](../../use/schema.md#sortable-attribute-compounds) in advance and use its name instead of the default attribute name. The sortable attribute compound will cover multiple attributes and prepares a special @@ -152,7 +152,7 @@ In the query, you can then use the compound name instead of the default attribut ## Primary key natural ```evitaql-syntax -primaryKeyNatural( +primaryKeyNatural( argument:enum(ASC|DESC) ) ``` @@ -164,7 +164,7 @@ primaryKeyNatural( -If no ordering constraint is specified in the query, the entities are sorted by their primary key in ascending order. +If no ordering constraint is specified in the query, the entities are sorted by their primary key in ascending order. If you want to sort them in descending order, you can use the `primaryKeyNatural` constraint with the `DESC` argument. Although the constraint also accepts the `ASC` argument, it doesn't make sense to use it because this is the default ordering behavior. @@ -183,22 +183,22 @@ To sort products by their primary key in descending order, we can use the follow ##### List of products sorted by primary key in descending order - + [List of products sorted by primary key in descending order](/documentation/user/en/query/ordering/examples/comparable/primary-key-natural.evitaql.md) - + - + [List of products sorted by primary key in descending order](/documentation/user/en/query/ordering/examples/comparable/primary-key-natural.graphql.json.md) - + - + [List of products sorted by primary key in descending order](/documentation/user/en/query/ordering/examples/comparable/primary-key-natural.rest.json.md) - + diff --git a/documentation/user/en/query/ordering/constant.md b/documentation/user/en/query/ordering/constant.md index 27d0c25f5..ad669338e 100644 --- a/documentation/user/en/query/ordering/constant.md +++ b/documentation/user/en/query/ordering/constant.md @@ -1,8 +1,8 @@ --- title: Constant ordering perex: | - There are situations when the order of entities is specified outside evitaDB. The constant order constraints allow to - control the order of the selected entities by a caller logic. + There are situations when the order of entities is specified outside evitaDB. The constant order constraints allow to + control the order of the selected entities by a caller logic. date: '17.1.2023' author: 'Ing. Jan Novotný' proofreading: 'needed' @@ -19,9 +19,9 @@ it represents a relevance of those entities from the full-text engine). entityPrimaryKeyInFilter() ``` -The constraint allows output entities to be sorted by primary key values in the exact order used to filter them. +The constraint allows output entities to be sorted by primary key values in the exact order used to filter them. The constraint requires the presence of exactly one [`entityPrimaryKeyInSet`](../filtering/constant.md#entity-primary-key-in-set) -constraint in the filter part of the query. It uses the specified array of entity primary keys to sort the result +constraint in the filter part of the query. It uses the specified array of entity primary keys to sort the result returned by the query. @@ -29,8 +29,8 @@ returned by the query. [Entities sorted by order of the filtered primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-in-filter.evitaql) -The sample query returns exactly 4 products, which maintain the order of the filtered primary keys in the query that -was issued. +The sample query returns exactly 4 products, which maintain the order of the filtered primary keys in the query that +was issued. @@ -39,23 +39,23 @@ was issued. ##### List of products sorted by order of entity primary keys in filter - + [Entities sorted by order of the filtered primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-in-filter.evitaql.md) - + - + [Entities sorted by order of the filtered primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-in-filter.graphql.json.md) - + - + [Entities sorted by order of the filtered primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-in-filter.rest.json.md) - + @@ -74,7 +74,7 @@ entityPrimaryKeyExact( -The constraint allows output entities to be sorted by entity primary keys in the exact order specified in the 2nd through +The constraint allows output entities to be sorted by entity primary keys in the exact order specified in the 2nd through Nth arguments of this constraint. @@ -84,8 +84,8 @@ Nth arguments of this constraint. The sample query returns all products whose code starts with the string *lenovo*, but uses the order of the first three entities in the output as specified by the order constraint `entityPrimaryKeyExact`. Because the query returns more -results than the order constraint has information for, the rest of the result set is sorted *traditionally* by -the entity primary key in ascending order. If there is another order constraint in the chain, it would be used to sort +results than the order constraint has information for, the rest of the result set is sorted *traditionally* by +the entity primary key in ascending order. If there is another order constraint in the chain, it would be used to sort the rest of the query result. @@ -95,23 +95,23 @@ the rest of the query result. ##### List of products sorted by the exact order of entity primary keys - + [Entities sorted by the specified order of the primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-exact.evitaql.md) - + - + [Entities sorted by the specified order of the primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-exact.graphql.json.md) - + - + [Entities sorted by the specified order of the primary keys](/documentation/user/en/query/ordering/examples/constant/entity-primary-key-exact.rest.json.md) - + @@ -126,14 +126,14 @@ attributeSetInFilter(
argument:string!
- a mandatory name of the [attribute name](../../use/schema.md#attributes) that control the order of + a mandatory name of the [attribute name](../../use/schema.md#attributes) that control the order of the query result
-This constraint allows output entities to be sorted by values of the specified attribute in the exact order in which -they were filtered. The constraint requires the presence of exactly one [`attribute-in-set`](../filtering/comparable.md#attribute-in-set) -in the filter part of the query, referring to the attribute with the same name as used in the first argument of this +This constraint allows output entities to be sorted by values of the specified attribute in the exact order in which +they were filtered. The constraint requires the presence of exactly one [`attribute-in-set`](../filtering/comparable.md#attribute-in-set) +in the filter part of the query, referring to the attribute with the same name as used in the first argument of this constraint. It uses the specified array of attribute values to sort the result returned by the query. @@ -141,7 +141,7 @@ constraint. It uses the specified array of attribute values to sort the result r [Entities sorted by order `code` attribute of the filtered entities](/documentation/user/en/query/ordering/examples/constant/attribute-set-in-filter.evitaql) -The sample query returns exactly 3 products, preserving the order of the entity's `code` attribute used in the filter +The sample query returns exactly 3 products, preserving the order of the entity's `code` attribute used in the filter constraint of the query that was issued. @@ -151,23 +151,23 @@ constraint of the query that was issued. ##### List of products sorted by order of attribute `code` in filter - + [Entities sorted by order `code` attribute of the filtered entities](/documentation/user/en/query/ordering/examples/constant/attribute-set-in-filter.evitaql.md) - + - + [Entities sorted by order `code` attribute of the filtered entities](/documentation/user/en/query/ordering/examples/constant/attribute-set-in-filter.graphql.json.md) - + - + [Entities sorted by order `code` attribute of the filtered entities](/documentation/user/en/query/ordering/examples/constant/attribute-set-in-filter.rest.json.md) - + @@ -183,12 +183,12 @@ attributeSetExact(
argument:string!
- a mandatory name of the [attribute name](../../use/schema.md#attributes) that control the order of + a mandatory name of the [attribute name](../../use/schema.md#attributes) that control the order of the query result
argument:comparable+
- a mandatory set of attribute values whose data type matches [attribute data type](../../use/schema.md#attributes), + a mandatory set of attribute values whose data type matches [attribute data type](../../use/schema.md#attributes), which define the order of the query result
@@ -214,22 +214,22 @@ the rest of the query result. ##### List of products sorted by the exact order of entity attribute `code` - + [Entities sorted by the specified order of the attribute `code` values](/documentation/user/en/query/ordering/examples/constant/attribute-set-exact.evitaql.md) - + - + [Entities sorted by the specified order of the attribute `code` values](/documentation/user/en/query/ordering/examples/constant/attribute-set-exact.graphql.json.md) - + - + [Entities sorted by the specified order of the attribute `code` values](/documentation/user/en/query/ordering/examples/constant/attribute-set-exact.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/ordering/price.md b/documentation/user/en/query/ordering/price.md index 367f0ba55..e27b75491 100644 --- a/documentation/user/en/query/ordering/price.md +++ b/documentation/user/en/query/ordering/price.md @@ -25,13 +25,13 @@ priceNatural( -The evita_query/src/main/java/io/evitadb/api/query/order/PriceNatural.javaEvitaDB.Client/Queries/Order/PriceNatural.cs constraint -allows output entities to be sorted by their [selling price](../filtering/price.md#price-for-sale-computation-algorithm) +The evita_query/src/main/java/io/evitadb/api/query/order/PriceNatural.javaEvitaDB.Client/Queries/Order/PriceNatural.cs constraint +allows output entities to be sorted by their [selling price](../filtering/price.md#price-for-sale-computation-algorithm) in their natural numeric order. It requires only the order direction and the price constraints in the `filterBy` section -of the query. The price variant (with or without tax) is determined by the [`priceType`](../requirements/price.md#price-type) +of the query. The price variant (with or without tax) is determined by the [`priceType`](../requirements/price.md#price-type) requirement of the query (price with tax is used by default). -To sort products by their selling price (currently considering only `basic` price list and `CZK`), we can use +To sort products by their selling price (currently considering only `basic` price list and `CZK`), we can use the following query: @@ -46,22 +46,22 @@ the following query: ##### List of products sorted by selling price - + [List of products sorted by selling price](/documentation/user/en/query/ordering/examples/price/price-natural.evitaql.md) - + - + [List of products sorted by selling price](/documentation/user/en/query/ordering/examples/price/price-natural.graphql.json.md) - + - + [List of products sorted by selling price](/documentation/user/en/query/ordering/examples/price/price-natural.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/ordering/random.md b/documentation/user/en/query/ordering/random.md index 980a5ba85..57ae4b637 100644 --- a/documentation/user/en/query/ordering/random.md +++ b/documentation/user/en/query/ordering/random.md @@ -2,7 +2,7 @@ title: Random ordering date: '25.6.2023' perex: | - Random ordering is useful in situations where you want to present the end user with the unique entity listing every + Random ordering is useful in situations where you want to present the end user with the unique entity listing every time he/she accesses it. author: 'Ing. Jan Novotný' proofreading: 'needed' @@ -31,22 +31,22 @@ The sample query always returns a different page of products. ##### List of randomized products - + [List of randomized products](/documentation/user/en/query/ordering/examples/random/randomized.evitaql.md) - + - + [List of randomized products](/documentation/user/en/query/ordering/examples/random/randomized.graphql.json.md) - + - + [List of randomized products](/documentation/user/en/query/ordering/examples/random/randomized.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/ordering/reference.md b/documentation/user/en/query/ordering/reference.md index 58707d3d4..c836a1f52 100644 --- a/documentation/user/en/query/ordering/reference.md +++ b/documentation/user/en/query/ordering/reference.md @@ -1,8 +1,8 @@ --- title: Ordering references / by reference attribute perex: | - You can sort entities by attributes on references, and you can also sort fetched referenced entities by their - attributes or by attributes of references that point to them. Although these are fundamentally different scenarios, + You can sort entities by attributes on references, and you can also sort fetched referenced entities by their + attributes or by attributes of references that point to them. Although these are fundamentally different scenarios, both are described in this section. date: '25.6.2023' author: 'Ing. Jan Novotný' @@ -37,9 +37,9 @@ referenceProperty( ##### The `referenceProperty` is implicit in requirement `referenceContent` -In the `orderBy` clause within the [`referenceContent`](../requirements/fetching.md#reference-content) requirement, -the `referenceProperty` constraint is implicit and must not be repeated. All attribute order constraints -in `referenceContent` automatically refer to the reference attributes, unless the [`entityProperty`](#entity-property) +In the `orderBy` clause within the [`referenceContent`](../requirements/fetching.md#reference-content) requirement, +the `referenceProperty` constraint is implicit and must not be repeated. All attribute order constraints +in `referenceContent` automatically refer to the reference attributes, unless the [`entityProperty`](#entity-property) container is used there. @@ -63,29 +63,29 @@ following query: ##### List of products in "sale" ordered by predecessor chain - + [List of products in "sale" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural.evitaql.md) - + - + [List of products in "sale" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural.graphql.json.md) - + - + [List of products in "sale" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural.rest.json.md) - + -The example is based on a simple one-to-zero-or-one reference (a product can have at most one reference to a group -entity). The response will only return the products that have a reference to the "sale" group, all of which contain the -`orderInGroup` attribute (since it's marked as a non-nullable attribute). Because the example is so simple, the returned +The example is based on a simple one-to-zero-or-one reference (a product can have at most one reference to a group +entity). The response will only return the products that have a reference to the "sale" group, all of which contain the +`orderInGroup` attribute (since it's marked as a non-nullable attribute). Because the example is so simple, the returned result can be anticipated. ### Behaviour of zero or one to many references ordering @@ -97,11 +97,11 @@ We decided to allow it and bind it with the following rules: #### Non-hierarchical entity -If the referenced entity is **non-hierarchical**, and the returned entity references multiple entities, only +If the referenced entity is **non-hierarchical**, and the returned entity references multiple entities, only the reference with the lowest primary key of the referenced entity, while also having the order property set, will be used for ordering. -Let's extend our previous example so that it returns products that refer not only to the group "sale", but also to the +Let's extend our previous example so that it returns products that refer not only to the group "sale", but also to the group "new": @@ -116,23 +116,23 @@ group "new": ##### List of products in groups "sale" or "new" ordered by predecessor chain - + [List of products in groups "sale" or "new" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-multiple.evitaql.md) - + - + [List of products in groups "sale" or "new" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-multiple.graphql.json.md) - + - + [List of products in groups "sale" or "new" ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-multiple.rest.json.md) - + The result will contain first products referring to a "new" group which has the lowest primary key, and then products referring to a "sale" group. The order of products within each group will be determined by the `orderInGroup` attribute. @@ -141,16 +141,16 @@ referring to a "sale" group. The order of products within each group will be det #### Hierarchical entity -If the referenced entity is **hierarchical** and the returned entity references multiple entities, the reference used -for ordering is the one that contains the order property and is the closest hierarchy node to the root of the filtered +If the referenced entity is **hierarchical** and the returned entity references multiple entities, the reference used +for ordering is the one that contains the order property and is the closest hierarchy node to the root of the filtered hierarchy node. -It sounds complicated, but it's really quite simple. If you list products of a certain category and at the same time -order them by a property `orderInCategory` set on the reference to the category, the first products will be those -directly related to the category, ordered by `orderInCategory`, followed by the products of the first child category, +It sounds complicated, but it's really quite simple. If you list products of a certain category and at the same time +order them by a property `orderInCategory` set on the reference to the category, the first products will be those +directly related to the category, ordered by `orderInCategory`, followed by the products of the first child category, and so on, maintaining the depth-first order of the category tree. -This behaviour is best illustrated by a following example. Let's list products in the *Accessories* category ordered +This behaviour is best illustrated by a following example. Let's list products in the *Accessories* category ordered by the `orderInCategory` attribute on the reference to the category: @@ -165,28 +165,28 @@ by the `orderInCategory` attribute on the reference to the category: ##### List products in "Accessories" category ordered by predecessor chain - + [List products in "Accessories" category ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-hierarchy.evitaql.md) - + - + [List products in "Accessories" category ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-hierarchy.graphql.json.md) - + - + [List products in "Accessories" category ordered by predecessor chain](/documentation/user/en/query/ordering/examples/reference/reference-attribute-natural-hierarchy.rest.json.md) - + -The result will first contain products directly related to the *Accessories* category, ordered by `orderInCategory` in -ascending order, then products *Christmas electronics* (which is the first child of the *Accessories* category with -the least primary key), then *Smart wearable* (which has no directly related products), then *Bands* (which is the first -child of the *Smart wearable* category), and so on. The order follows the order of the categories in the following +The result will first contain products directly related to the *Accessories* category, ordered by `orderInCategory` in +ascending order, then products *Christmas electronics* (which is the first child of the *Accessories* category with +the least primary key), then *Smart wearable* (which has no directly related products), then *Bands* (which is the first +child of the *Smart wearable* category), and so on. The order follows the order of the categories in the following image: ![dynamic-tree.png](../requirements/assets/dynamic-tree.png) @@ -220,11 +220,11 @@ entityProperty( -The `entityProperty` ordering constraint can only be used within the [`referenceContent`](../requirements/fetching.md#reference-content) -requirement. It allows to change the context of the reference ordering from attributes of the reference itself to +The `entityProperty` ordering constraint can only be used within the [`referenceContent`](../requirements/fetching.md#reference-content) +requirement. It allows to change the context of the reference ordering from attributes of the reference itself to attributes of the entity the reference points to. -In other words, if the `Product` entity has multiple references to `ParameterValue` entities, you can sort those +In other words, if the `Product` entity has multiple references to `ParameterValue` entities, you can sort those references by, for example, the `order` or `name` attribute of the `ParameterValue` entity. Let's see an example: @@ -239,23 +239,23 @@ references by, for example, the `order` or `name` attribute of the `ParameterVal ##### Get product with parameter values ordered by their name - + [Get product with parameters ordered by their name](/documentation/user/en/query/ordering/examples/reference/entity-property.evitaql.json.md) - + - + [Get product with parameters ordered by their name](/documentation/user/en/query/ordering/examples/reference/entity-property.graphql.json.md) - + - + [Get product with parameters ordered by their name](/documentation/user/en/query/ordering/examples/reference/entity-property.rest.json.md) - + @@ -275,12 +275,12 @@ entityGroupProperty( -The `entityGroupProperty` ordering constraint can only be used within the [`referenceContent`](../requirements/fetching.md#reference-content) requirement. It -allows the context of the reference ordering to be changed from attributes of the reference itself to attributes of +The `entityGroupProperty` ordering constraint can only be used within the [`referenceContent`](../requirements/fetching.md#reference-content) requirement. It +allows the context of the reference ordering to be changed from attributes of the reference itself to attributes of the group entity within which the reference is aggregated. -In other words, if the `Product` entity has multiple references to `ParameterValue` entities that are grouped by their -assignment to the `Parameter` entity, you can sort those references primarily by the `name` attribute of the grouping +In other words, if the `Product` entity has multiple references to `ParameterValue` entities that are grouped by their +assignment to the `Parameter` entity, you can sort those references primarily by the `name` attribute of the grouping entity, and secondarily by the `name` attribute of the referenced entity. Let's look at an example: @@ -296,22 +296,22 @@ entity, and secondarily by the `name` attribute of the referenced entity. Let's ##### Get product with parameters ordered by their priority - + [Get product with parameters ordered by their group name and name](/documentation/user/en/query/ordering/examples/reference/entity-group-property.evitaql.json.md) - + - + [Get product with parameters ordered by their group name and name](/documentation/user/en/query/ordering/examples/reference/entity-group-property.graphql.json.md) - + - + [Get product with parameters ordered by their group name and name](/documentation/user/en/query/ordering/examples/reference/entity-group-property.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/requirements/facet.md b/documentation/user/en/query/requirements/facet.md index e8ca37cb3..2e23c7956 100644 --- a/documentation/user/en/query/requirements/facet.md +++ b/documentation/user/en/query/requirements/facet.md @@ -58,7 +58,7 @@ The visualization is organized in the same way as the facet summary itself: ## Facet summary - + ```evitaql-syntax facetSummary( @@ -77,7 +77,7 @@ facetSummary(

**Default:** `COUNTS`

-

optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/FacetStatisticsDepth.javaEvitaDB.Client/Queries/Requires/FacetStatisticsDepth.cs +

optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/FacetStatisticsDepth.javaEvitaDB.Client/Queries/Requires/FacetStatisticsDepth.cs that allows you to specify the computation depth of the facet summary:

@@ -121,7 +121,7 @@ facetSummary(

-
+ ```evitaql-syntax @@ -167,7 +167,7 @@ facetSummary( -The request triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs +The request triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs containing the facet summary calculation. The calculated facet summary will contain all entity references marked as `faceted` in the [entity schema](../../use/schema.md). The facet summary can be further modified by the [facet summary of reference](#facet-summary-of-reference) constraint, which allows you to override the general facet @@ -219,21 +219,21 @@ facets". Facet group lists all [facet options](#3rd-tier-facet) available for the given group and reference combination. It also contains a `count` of all entities in the current query result that match at least one facet in the group / reference. - + Optionally, it can contain the body of the group entity if the [`entityGroupFetch`](#entity-group-fetch) requirement is specified. - - + + Optionally, it can contain the body of the group entity if the `groupEntity` field is specified. - + There may also be a special "group" for facets that are not related to a group. - + This group will be placed in the facet summary as a `nonGroupedStatistics` property. - - + + This group will be returned as a single group for the reference. - + #### 3rd tier: facet @@ -253,16 +253,16 @@ Facet contains the statistics for that facet option: - + And optionally the body of the facet (referenced) entity if the [`entityFetch`](#entity-fetch) requirement is specified. If the `IMPACT` statistics depth is requested in the facet summary, the statistics will also include the impact analysis calculation, which contains the following data: - - + + And optionally the body of the facet (referenced) entity if the `facetEntity` field is specified. If the `impact` object is requested in the facet summary, the statistics will also include the impact analysis calculation, which can contains the following data: - +
matchCount
@@ -288,8 +288,8 @@ calculation, which can contains the following data: -The evita_query/src/main/java/io/evitadb/api/query/require/FacetSummary.javaEvitaDB.Client/Queries/Requires/FacetSummary.cs requirement -triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs +The evita_query/src/main/java/io/evitadb/api/query/require/FacetSummary.javaEvitaDB.Client/Queries/Requires/FacetSummary.cs requirement +triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs extra result. The facet summary is always computed as a side result of the main entity query and respects any filtering constraints placed on the queried entities. To demonstrate the facet summary calculation, we will use the following example: @@ -302,7 +302,7 @@ example: - + When the `facetSummary` field is specified with specific references within the `extraResults` field is specified, it triggers the calculation of the facet summary extra result. @@ -316,7 +316,7 @@ example: - + @@ -329,23 +329,23 @@ example: The query returns a list of "active" products in the "e-readers" category, and in the extra results index it also includes the facet summary calculation: - + [The result of the facet summarization in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary.evitaql.string.md) - - + + [The result of the facet summarization in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-simple.graphql.json.md) - - + + [The result of the facet summarization in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary.rest.json.md) - + - + The format has been simplified because the raw JSON result would be too long and hard to read. This is the output format of the `prettyPrint` method of evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.java @@ -354,36 +354,36 @@ entities for each of the facets and facet groups. No facet is currently selected not checked anywhere. The listing doesn't contain any human-readable information except the primary keys of the references, facet groups, and facets - to get them we would have to add [their bodies](#fetching-facet-group-bodies). - - + + You can see the summary organized in a three-tier structure, along with the information about the number of result entities for each of the facets and facet groups. No facet is currently selected and therefore the `requested` property is `false` everywhere. The listing doesn't contain any human-readable information except the primary keys of the references, facet groups, and facets - to get them we would have to add [their bodies](#fetching-facet-group-bodies). - + ### Fetching facet (group) bodies - + The facet summary makes little sense without the bodies of the facet groups and facets. To get those bodies, you need to add [`entityFetch`](#entity-fetch) or [`entityGroupFetch`](#entity-group-fetch) requirement to the query. Let's modify the example to fetch the facet summary along with the codes of the facets and their groups: - - + + The facet summary makes little sense without the bodies of the facet groups and facets. To get those bodies, you need to request [`facetEntity`](#entity-fetch) or [`groupEntity`](#entity-group-fetch) fields. Let's modify the example to fetch the facet summary along with the codes of the facets and their groups: - + - + @@ -391,8 +391,8 @@ the example to fetch the facet summary along with the codes of the facets and th - - + + @@ -400,7 +400,7 @@ the example to fetch the facet summary along with the codes of the facets and th - + @@ -413,26 +413,26 @@ the example to fetch the facet summary along with the codes of the facets and th Now you can see that the facet summary contains not only the primary keys, but also the somewhat comprehensible codes of the facets and their respective groups: - + [The result of the facet summarization in the "e-readers" category including the referenced entity bodies](/documentation/user/en/query/requirements/examples/facet/facet-summary-bodies.evitaql.string.md) - - + + [The result of the facet summarization in the "e-readers" category including the referenced entity bodies](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-bodies.graphql.json.md) - - + + [The result of the facet summarization in the "e-readers" category including the referenced entity bodies](/documentation/user/en/query/requirements/examples/facet/facet-summary-bodies.rest.json.md) - + If you add the desired locale to the query and also list localized names, you'll get a result that's very close to the version you want to see in the user interface: - + @@ -440,8 +440,8 @@ the version you want to see in the user interface: - - + + @@ -449,23 +449,23 @@ the version you want to see in the user interface: - + - + [The result of facet summary with localized names for products in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary-localized-bodies.evitaql.string.md) - - + + [The result of facet summary with localized names for products in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-localized-bodies.graphql.json.md) - - + + [The result of facet summary with localized names for products in the "e-readers" category](/documentation/user/en/query/requirements/examples/facet/facet-summary-localized-bodies.rest.json.md) - + @@ -479,24 +479,24 @@ To limit the facet summary, you can use the [`filterBy`](../basics.md#filter-by) and `filterGroupBy` (which is the same as `filterBy`, but it filters the entire facet group instead of individual facets) constraints. - + The `filterGroupBy` can be specified on each reference field returning facet groups. The `filterBy` can be specified deeper in the facet summary structure, specifically within the group definition on the `facetStatistics` field, which returns the actual facet options. - + - + If you add the filtering constraints to the `facetSummary` requirement, you can only refer to filterable properties that are shared by all referenced entities. This may not be feasible in some cases, and you will need to split the generic `facetSummary` requirement into multiple individual [`facetSummaryOfReference`](#facet-summary-of-reference) requirements with specific filters for each reference type. - + [Behaviour of filtering on referenced entities in facet summary constraint](/documentation/user/en/query/requirements/assets/referenced-filter-note.md) @@ -506,7 +506,7 @@ It's hard to find a good example for filtering a generic facet summary even for a bit artificial. Let's say we want to display only the facet options whose *code* attribute contains the substring *ar*, and only those that are within groups with *code* starting with the letter *o*: - + @@ -514,8 +514,8 @@ a bit artificial. Let's say we want to display only the facet options whose *cod - - + + @@ -523,7 +523,7 @@ a bit artificial. Let's say we want to display only the facet options whose *cod - + @@ -535,16 +535,16 @@ a bit artificial. Let's say we want to display only the facet options whose *cod We don't limit the search to a specific hierarchy because the filter is quite selective, as you can see in the result: - + [The result of facet summary filtering](/documentation/user/en/query/requirements/examples/facet/facet-summary-filtering.evitaql.string.md) - - + + [The result of facet summary filtering](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-filtering.graphql.json.md) - + @@ -556,22 +556,22 @@ We don't limit the search to a specific hierarchy because the filter is quite se [Ordering facet summary](/documentation/user/en/query/requirements/assets/ordering-facet-summary.md) - + The `orderGroupBy` can be specified on each reference field returning facet groups. The `orderBy` can be specified deeper in the facet summary structure, specifically inside the group definition on `facetStatistics` field returning actual facet options. - + - + If you add the ordering constraints to the `facetSummary` requirement, you can only refer to sortable properties that are shared by all referenced entities. This may not be feasible in some cases, and you will need to split the generic `facetSummary` requirement into multiple individual [`facetSummaryOfReference`](#facet-summary-of-reference) requirements with specific ordering constraints for each reference type. - + [Behaviour of ordering on referenced entities in facet summary constraint](/documentation/user/en/query/requirements/assets/referenced-order-note.md) @@ -579,7 +579,7 @@ requirements with specific ordering constraints for each reference type. Let's sort both facet groups and facets alphabetically by their English names: - + @@ -587,8 +587,8 @@ Let's sort both facet groups and facets alphabetically by their English names: - - + + @@ -596,7 +596,7 @@ Let's sort both facet groups and facets alphabetically by their English names: - + @@ -608,27 +608,27 @@ Let's sort both facet groups and facets alphabetically by their English names: You can see that the facet summary is now sorted where appropriate: - + [The result of facet summary sorting](/documentation/user/en/query/requirements/examples/facet/facet-summary-ordering.evitaql.string.md) - - + + [The result of facet summary sorting](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-ordering.graphql.json.md) - - + + [The result of facet summary sorting](/documentation/user/en/query/requirements/examples/facet/facet-summary-of-reference-ordering.rest.json.md) - + - + ## Facet summary of reference @@ -697,8 +697,8 @@ facetSummaryOfReference(
-The evita_query/src/main/java/io/evitadb/api/query/require/FacetSummaryOfReference.javaEvitaDB.Client/Queries/Requires/FacetSummaryOfReference.cs -requirement triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs +The evita_query/src/main/java/io/evitadb/api/query/require/FacetSummaryOfReference.javaEvitaDB.Client/Queries/Requires/FacetSummaryOfReference.cs +requirement triggers the calculation of the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.javaEvitaDB.Client/Models/ExtraResults/FacetSummary.cs for a specific reference. When a generic [`facetSummary`](#facet-summary) requirement is specified, this require constraint overrides the default constraints from the generic requirement to constraints specific to this particular reference. By combining the generic [`facetSummary`](#facet-summary) and `facetSummaryOfReference`, you define common requirements @@ -823,11 +823,11 @@ You can see that the facet summary is now sorted where appropriate: - + ## Entity group fetch - + The `entityGroupFetch` constraint used within the [`facetSummary`](#facet-summary) or [`facetSummaryOfReference`](#facet-summary-of-reference) requirement is identical to @@ -836,34 +836,34 @@ that the `entityGroupFetch` refers to the related group entity schema specified [reference schema](../../use/schema.md#reference), and is named `entityGroupFetch` instead of `entityFetch` to distinguish the requirements for referenced (facet) entity and referenced (facet) entity group. - - + + The `groupEntity` field used within the facet group object in the [`facetSummary`](#facet-summary) has same meaning as [standard entity fetching](fetching.md#entity-fetch). The only difference is that the `groupEntity` refers to the related group entity schema specified by the faceted [reference schema](../../use/schema.md#reference). - + ## Entity fetch - + The `entityFetch` constraint used within the [`facetSummary`](#facet-summary) or [`facetSummaryOfReference`](#facet-summary-of-reference) requirement is identical to the [`entityFetch`](fetching.md#entity-fetch) requirement described in the referenced chapter. The only difference is that the `entityFetch` refers to the related entity schema specified by the faceted [reference schema](../../use/schema.md#reference). - + - + The `facetEntity` field used within the facet object in the [`facetSummary`](#facet-summary) has same meaning as [standard entity fetching](fetching.md#entity-fetch). The only difference is that the `facetEntity` refers to the related entity schema specified by the faceted [reference schema](../../use/schema.md#reference). - + ## Facet groups conjunction @@ -889,7 +889,7 @@ facetGroupsConjunction( -The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsConjunction.javaEvitaDB.Client/Queries/Requires/FacetGroupsConjunction.cs +The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsConjunction.javaEvitaDB.Client/Queries/Requires/FacetGroupsConjunction.cs changes the default behavior of the facet summary calculation for the facet groups specified in the `filterBy` constraint. Instead of logical disjunction (logical OR), the facet options in the facet groups are combined with logical conjunction (logical AND). @@ -935,21 +935,21 @@ part of any group. You can see that instead of increasing the number of results in the final set, the impact analysis predicts their reduction: - + [The result of facet summarization with inverted facet relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-conjunction.evitaql.string.md) - - + + [The result of facet summarization with inverted facet relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-conjunction.graphql.json.md) - - + + [The result of facet summarization with inverted facet relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-conjunction.rest.json.md) - + @@ -978,7 +978,7 @@ facetGroupsDisjunction( -The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsDisjunction.javaEvitaDB.Client/Queries/Requires/FacetGroupsDisjunction.cs +The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsDisjunction.javaEvitaDB.Client/Queries/Requires/FacetGroupsDisjunction.cs changes the default behavior of the facet summary calculation for the facet groups specified in the `filterBy` constraint. Instead of logical AND, the facet options in the facet groups are combined with logical OR with facets from different facet groups. @@ -1016,21 +1016,21 @@ reducing the numbers, the impact analysis predicts their expansion: You can see that instead of reducing the number of results in the final set, the impact analysis predicts their expansion: - + [The result of facet summarization with inverted facet group relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-disjunction.evitaql.string.md) - - + + [The result of facet summarization with inverted facet group relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-disjunction.graphql.json.md) - - + + [The result of facet summarization with inverted facet group relation behavior](/documentation/user/en/query/requirements/examples/facet/facet-groups-disjunction.rest.json.md) - + @@ -1059,7 +1059,7 @@ facetGroupsNegation( -The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsNegation.javaEvitaDB.Client/Queries/Requires/FacetGroupsNegation.cs +The evita_query/src/main/java/io/evitadb/api/query/require/FacetGroupsNegation.javaEvitaDB.Client/Queries/Requires/FacetGroupsNegation.cs changes the behavior of the facet option in all facet groups specified in the `filterBy` constraint. Instead of returning only those items that have a reference to that particular faceted entity, the query result will return only those items that don't have a reference to it. @@ -1095,20 +1095,20 @@ The predicted results in the negated groups are far greater than the numbers pro can see, selecting any option in the RAM facet group predicts returning thousands of results, while the ROM facet group with default behavior predicts only a dozen of them: - + [The result of facet summarization with negated facet relation behavior in the group](/documentation/user/en/query/requirements/examples/facet/facet-groups-negation.evitaql.string.md) - - + + [The result of facet summarization with negated facet relation behavior in the group](/documentation/user/en/query/requirements/examples/facet/facet-groups-negation.graphql.json.md) - - + + [The result of facet summarization with negated facet relation behavior in the group](/documentation/user/en/query/requirements/examples/facet/facet-groups-negation.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/requirements/fetching.md b/documentation/user/en/query/requirements/fetching.md index c9114aaf9..b45d25f99 100644 --- a/documentation/user/en/query/requirements/fetching.md +++ b/documentation/user/en/query/requirements/fetching.md @@ -11,7 +11,7 @@ proofreading: 'done' preferredLang: 'evitaql' --- - + If no content requirement is used in the query, the result will contain only the primary key of the entity. While this may be sufficient for some queries, it is usually necessary to fetch some data from the entity or even other entities @@ -65,22 +65,22 @@ entityFetch( - + -The `entityFetch` (evita_query/src/main/java/io/evitadb/api/query/require/EntityFetch.javaEvitaDB.Client/Queries/Requires/EntityFetch.cs) +The `entityFetch` (evita_query/src/main/java/io/evitadb/api/query/require/EntityFetch.javaEvitaDB.Client/Queries/Requires/EntityFetch.cs) requirement is used to trigger loading one or more entity data containers from the disk by its primary key. This operation requires a disk access unless the entity is already loaded in the database cache (frequently fetched entities have higher chance to stay in the cache). - -In the Java APIIn the C# client, + +In the Java APIIn the C# client, including the `entityFetch` requirement in the query changes the output type in the response container. -Instead of returning an evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityReference.javaEvitaDB.Client/Models/Data/Structure/EntityReference.cs -for each entity, the evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.javaEvitaDB.Client/Models/Data/ISealedEntity.cs +Instead of returning an evita_api/src/main/java/io/evitadb/api/requestResponse/data/structure/EntityReference.javaEvitaDB.Client/Models/Data/Structure/EntityReference.cs +for each entity, the evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.javaEvitaDB.Client/Models/Data/ISealedEntity.cs type is returned. - + - + ## Entity group fetch @@ -131,9 +131,9 @@ entityGroupFetch( Same as the [`entityFetch`](#entity-fetch) but used for fetching entities that represents reference group. - + - + ## Entity content @@ -178,11 +178,11 @@ The query returns the following entity body of the `Brand` entity: - + ## Attribute content - + ```evitaql-syntax attributeContent( @@ -197,7 +197,7 @@ attributeContent( -The `attributeContent` (evita_query/src/main/java/io/evitadb/api/query/require/AttributeContent.javaEvitaDB.Client/Queries/Requires/AttributeContent.cs) +The `attributeContent` (evita_query/src/main/java/io/evitadb/api/query/require/AttributeContent.javaEvitaDB.Client/Queries/Requires/AttributeContent.cs) requirement is used to retrieve one or more entity or reference [attributes](../../use/data-model.md#attributes-unique-filterable-sortable-localized). [Localized attributes](../../use/data-model.md#localized-attributes) are only fetched if there is a *locale context* in the query, either by using the [`entityLocaleEquals`](../filtering/locale.md#entity-locale-equals) filter constraint or the [`dataInLocales`](#data-in-locale) require constraint. @@ -226,25 +226,25 @@ To select a `code` and localized `name` attribute for the `Brand` entity, use th The query returns the following attributes of the `Brand` entity: - + [The result of an entity fetch with named attributes](/documentation/user/en/query/requirements/examples/fetching/attributeContent.evitaql.md) - - + + [The result of an entity fetch with named attributes](/documentation/user/en/query/requirements/examples/fetching/attributeContent.rest.json.md) - + As you can see, the name is in the English localization thanks to the `entityLocaleEquals` filter constraint in the query. - + - + To fetch entity or reference [attributes](../../use/data-model.md#attributes-unique-filterable-sortable-localized), use the `attributes` field within an entity or reference object and specify the required attribute names as sub-fields. @@ -334,9 +334,9 @@ satisfied by the entity. - + - + ### Attribute content all @@ -364,26 +364,26 @@ To select all non-localized attributes for the `Brand` entity, use the following The query returns the following attributes of the `Brand` entity: - + [The result of an entity fetch with all attributes](/documentation/user/en/query/requirements/examples/fetching/attributeContentAll.evitaql.md) - - + + [The result of an entity fetch with all attributes](/documentation/user/en/query/requirements/examples/fetching/attributeContentAll.rest.json.md) - + All the localized attributes are missing, because there is no localization context present in the query. - + ## Associated data content - + ```evitaql-syntax associatedDataContent( @@ -398,7 +398,7 @@ associatedDataContent( -The `associatedDataContent` (evita_query/src/main/java/io/evitadb/api/query/require/AssociatedDataContent.javaEvitaDB.Client/Queries/Requires/AssociatedDataContent.cs) +The `associatedDataContent` (evita_query/src/main/java/io/evitadb/api/query/require/AssociatedDataContent.javaEvitaDB.Client/Queries/Requires/AssociatedDataContent.cs) requirement is used to retrieve one or more entity [associated data](../../use/data-model.md#associated-data). [Localized associated data](../../use/data-model.md#localized-associated-data) are only fetched if there is a *locale context* in the query, either by using the [`entityLocaleEquals`](../filtering/locale.md#entity-locale-equals) @@ -420,16 +420,16 @@ To select an *allActiveUrls* and localized *localization* associated data for th The query returns the following associated data of the `Brand` entity: - + [The result of an entity fetch with named associated data](/documentation/user/en/query/requirements/examples/fetching/associatedDataContent.evitaql.json.md) - - + + [The result of an entity fetch with named associated data](/documentation/user/en/query/requirements/examples/fetching/associatedDataContent.rest.json.md) - + As you can see, the *localization* related data item contains the texts in the English localization thanks to the `entityLocaleEquals` filter constraint in the query. The *allActiveUrls* is a non-localized related @@ -438,9 +438,9 @@ be used to generate a language selection menu for this brand record. - + - + To fetch entity [associated data](../../use/data-model.md#associated-data), use the `associatedData` field within an entity object and specify required associated data names as sub-fields. @@ -519,9 +519,9 @@ satisfied by the entity. - + - + ### Associated data content all @@ -557,29 +557,29 @@ To select all non-localized associated data for the `Brand` entity, use the foll The query returns the following associated data of the `Brand` entity: - + [The result of an entity fetch with all the associated data](/documentation/user/en/query/requirements/examples/fetching/associatedDataContentAll.evitaql.json.md) - - + + [The result of an entity fetch with all the associated data](/documentation/user/en/query/requirements/examples/fetching/associatedDataContentAll.graphql.json.md) - - + + [The result of an entity fetch with all the associated data](/documentation/user/en/query/requirements/examples/fetching/associatedDataContentAll.rest.json.md) - + All the localized associated data are missing, because there is no localization context present in the query. - + - + ## Data in locales @@ -598,7 +598,7 @@ dataInLocales( -The `dataInLocales` (evita_query/src/main/java/io/evitadb/api/query/require/DataInLocales.javaEvitaDB.Client/Queries/Requires/DataInLocales.cs) +The `dataInLocales` (evita_query/src/main/java/io/evitadb/api/query/require/DataInLocales.javaEvitaDB.Client/Queries/Requires/DataInLocales.cs) requirement is used in two scenarios: 1. there is no *locale context* in the filter part of the query, because you don't want to exclude entities without @@ -624,16 +624,16 @@ query: The query returns the following localized attributes of the `Brand` entity: - + [The result of an entity fetch with localized attributes](/documentation/user/en/query/requirements/examples/fetching/dataInLocales.evitaql.md) - - + + [The result of an entity fetch with localized attributes](/documentation/user/en/query/requirements/examples/fetching/dataInLocales.rest.json.md) - + If the `dataInLocales` requirement was not used in the query, accessing the *name* attribute would throw an exception. In the example above, the *name* attribute is accessible in the Czech locale even though the `entityLocaleEquals` filter @@ -658,16 +658,16 @@ get Czech and English *name* attribute values. The following query will do the j The query returns the following localized attributes of the `Brand` entity: - + [The result of an entity fetch with localized attributes in multiple locales](/documentation/user/en/query/requirements/examples/fetching/dataInLocalesWithFilter.evitaql.md) - - + + [The result of an entity fetch with localized attributes in multiple locales](/documentation/user/en/query/requirements/examples/fetching/dataInLocalesWithFilter.rest.json.md) - + As you can see, the localized attributes are available both for the Czech and English locales. The entity is still present in the result, because the filter constraint enforces the Czech locale context, which is @@ -675,9 +675,9 @@ satisfied by the entity. - + - + ### Data in locales all @@ -707,32 +707,32 @@ To fetch entity in all locales available, use the following query: The query returns the following localized attributes of the `Brand` entity: - + [The result of an entity fetch in all available locales](/documentation/user/en/query/requirements/examples/fetching/dataInLocalesAll.evitaql.md) - - + + [The result of an entity fetch in all available locales](/documentation/user/en/query/requirements/examples/fetching/dataInLocalesAll.graphql.json.md) - - + + [The result of an entity fetch in all available locales](/documentation/user/en/query/requirements/examples/fetching/dataInLocalesAll.rest.json.md) - + As you can see, the entity is returned with the Czech and English locales for which the localized attributes or associated data are available. - + ## Hierarchy content - + ```evitaql-syntax hierarchyContent( @@ -753,7 +753,7 @@ hierarchyContent( -The `hierarchyContent` (evita_query/src/main/java/io/evitadb/api/query/require/HierarchyContent.javaEvitaDB.Client/Queries/Requires/HierarchyContent.cs) +The `hierarchyContent` (evita_query/src/main/java/io/evitadb/api/query/require/HierarchyContent.javaEvitaDB.Client/Queries/Requires/HierarchyContent.cs) requirement allows you to access the information about the hierarchical placement of the entity. If no additional constraints are specified, entity will contain a full chain of parent primary keys up to the root of @@ -783,16 +783,16 @@ To fetch an entity with basic hierarchy information, use the following query: The query returns the following hierarchy of the `Category` entity: - + [The result of an entity fetch with hierarchy placement](/documentation/user/en/query/requirements/examples/fetching/hierarchyContent.evitaql.json.md) - - + + [The result of an entity fetch with hierarchy placement](/documentation/user/en/query/requirements/examples/fetching/hierarchyContent.rest.json.md) - + The `Category` entity is returned with the hierarchy information up to the root of the hierarchy tree. @@ -816,25 +816,25 @@ categories. The query looks like this: The query returns the following product with the reference to the full `Category` entity hierarchy chain: - + [The result of an entity fetch with hierarchy placement](/documentation/user/en/query/requirements/examples/fetching/hierarchyContentViaReference.evitaql.json.md) - - + + [The result of an entity fetch with hierarchy placement](/documentation/user/en/query/requirements/examples/fetching/hierarchyContentViaReference.rest.json.md) - + This quite complex example uses the [`referenceContent`](#reference-content) requirement that is described in a following chapter. - + - + To access the information about the hierarchical placement of an entity, use either the `parentPrimaryKey` or the `parents` field (or both). @@ -898,11 +898,11 @@ chapter. - + ## Price content - + ```evitaql-syntax priceContent( @@ -914,7 +914,7 @@ priceContent(
argument:enum(NONE|RESPECTING_FILTER|ALL)
- optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/PriceContentMode.javaEvitaDB.Client/Queries/Requires/PriceContentMode.cs + optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/PriceContentMode.javaEvitaDB.Client/Queries/Requires/PriceContentMode.cs enum allowing you to specify whether to fetch all, selected or no price records for the entity: - **NONE**: no prices will be fetched for the entity (even if the filter contains a price constraint) @@ -929,7 +929,7 @@ priceContent(
-The `priceContent` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) +The `priceContent` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) requirement allows you to access the information about the prices of the entity. If the `RESPECTING_FILTER` mode is used, the `priceContent` requirement will only retrieve the prices selected by @@ -958,16 +958,16 @@ To get an entity with prices that you filter by, use the following query: The query returns the following list of prices of the `Product` entity: - + [The result of an entity fetched with its selected prices](/documentation/user/en/query/requirements/examples/fetching/priceContent.evitaql.json.md) - - +
+ [The result of an entity fetched with its selected prices](/documentation/user/en/query/requirements/examples/fetching/priceContent.rest.json.md) -
+ As you can see, the prices for the filtered price lists *employee-basic-price* and *basic* are returned. This query is equivalent to using the [`priceContentRespectingFilter`](#price-content-respecting-filter) alias. @@ -990,7 +990,7 @@ priceContent( -The `priceContentRespectingFilter` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) +The `priceContentRespectingFilter` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) requirement allows you to access the information about the prices of the entity. It fetches only the prices selected by the [`priceInPriceLists`](../filtering/price.md#price-in-price-lists) constraint. @@ -1017,16 +1017,16 @@ To get an entity with prices that you filter by and a *reference* price on top o The query returns the following list of prices of the `Product` entity: - + [The result of an entity fetched with its selected prices and reference price](/documentation/user/en/query/requirements/examples/fetching/priceContentRespectingFilter.evitaql.json.md) - - + + [The result of an entity fetched with its selected prices and reference price](/documentation/user/en/query/requirements/examples/fetching/priceContentRespectingFilter.rest.json.md) - + As you can see, the prices for the filtered price lists *employee-basic-price* and *basic* are returned, as well as the price in the *reference* price lists requested by the `priceContent` requirement. @@ -1039,7 +1039,7 @@ the price in the *reference* price lists requested by the `priceContent` require priceContentAll() ``` -The `priceContentAll` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) +The `priceContentAll` (evita_query/src/main/java/io/evitadb/api/query/require/PriceContent.javaEvitaDB.Client/Queries/Requires/PriceContent.cs) requirement allows you to access all of the entity's price information regardless of the filtering constraints specified in the query. @@ -1061,24 +1061,24 @@ To get an entity with all of the entity's prices, use the following query: The query returns the following list of prices of the `Product` entity: - + [The result of an entity fetched with all its prices](/documentation/user/en/query/requirements/examples/fetching/priceContentAll.evitaql.json.md) - - + + [The result of an entity fetched with all its prices](/documentation/user/en/query/requirements/examples/fetching/priceContentAll.rest.json.md) - + As you can see, all prices of the entity are returned in all available currencies - not only the filtered price lists *employee-basic-price* and *basic*. Thanks to `priceContentAll` you have an overview of all prices of the entity. - - + + To fetch price information for an entity, there are several different fields available within an entity: `priceForSale`, `price` and `prices`. Each has a different purpose and returns different prices. @@ -1223,11 +1223,11 @@ As you can see, the filtered price list is returned. - + ## Reference content - + ```evitaql-syntax referenceContent( @@ -1272,14 +1272,14 @@ referenceContent( -The `referenceContent` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) +The `referenceContent` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) requirement allows you to access the information about the references the entity has towards other entities (either managed by evitaDB itself or by any other external system). This variant of `referenceContent` doesn't return the attributes set on the reference itself - if you need those attributes, use the [`referenceContentWithAttributes`](#reference-content-with-attributes) variant of it. - - + + Reference fields allow you to access the information about the references the entity has towards other entities (either managed by evitaDB itself or by any other external system). However, reference fields are a bit different from the other @@ -1287,7 +1287,7 @@ entity fields. They are dynamically generated based on the reference schemas, so the entity object by a schema-defined name, and also, each reference object has a slightly different structure based on the specific reference schema. - + To get an entity with reference to categories and brand, use the following query: @@ -1305,21 +1305,21 @@ To get an entity with reference to categories and brand, use the following query The returned `Product` entity will contain primary keys of all categories and brand it references: - + [The result of an entity fetched with category and brand references](/documentation/user/en/query/requirements/examples/fetching/referenceContent.evitaql.json.md) - - + + [The result of an entity fetched with category and brand references](/documentation/user/en/query/requirements/examples/fetching/referenceContent.graphql.json.md) - - + + [The result of an entity fetched with category and brand references](/documentation/user/en/query/requirements/examples/fetching/referenceContent.rest.json.md) - + @@ -1343,21 +1343,21 @@ the bodies of the groups the references refer to. One such common scenario is fe The returned `Product` entity will contain a list of all parameter codes it references and the code of the group to which each parameter belongs: - + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentBodies.evitaql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentBodies.graphql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentBodies.rest.json.md) - + The example lists only a *code* attribute for each referenced entity and group for brevity, but you can retrieve any of their content - associated data, prices, hierarchies, or nested references as well. @@ -1383,27 +1383,27 @@ related entities: product → group → tag → tag category. The query looks li The returned `Product` entity will contain a list of all groups it references, for each group a list of all its tags and for each tag its category assignment: - + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentNested.evitaql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentNested.graphql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies and group bodies](/documentation/user/en/query/requirements/examples/fetching/referenceContentNested.rest.json.md) - + The tag category is not an entity managed by evitaDB and that's why we retrieve only its primary key. - + #### Reference attributes fetching @@ -1429,18 +1429,18 @@ combination and which parameter values are merely informative, use the following The returned `Product` entity will contain references to parameter values and for each of it, it specifies the type of the relation between the product and the parameter value: - + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentWithAttributes.graphql.json.md) - + As you can see, the *cellular-true*, *display-size-10-2*, *ram-memory-4*, *rom-memory-256* and *color-yellow* parameter values define the product variant, while the other parameters only describe the additional properties of the product. - + #### Filtering references @@ -1449,8 +1449,8 @@ can use the filter constraint to filter out the references you don't need. -The `referenceContent` filter -on reference fields +The `referenceContent` filter +on reference fields implicitly targets the attributes on the same reference it points to, so you don't need to specify a [`referenceHaving`](../filtering/references.md#reference-having) constraint. However, if you need to declare constraints on referenced entity attributes, you must wrap them in the [`entityHaving`](../filtering/references.md#entity-having) @@ -1477,21 +1477,21 @@ following query: The returned `Product` entity will contain a list of all parameter codes it references and the code of the group to which each parameter belongs: - + [The result of an entity fetched with referenced parameter bodies that belong to group visible on detail page](/documentation/user/en/query/requirements/examples/fetching/referenceContentFilter.evitaql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies that belong to group visible on detail page](/documentation/user/en/query/requirements/examples/fetching/referenceContentFilter.graphql.json.md) - - + + [The result of an entity fetched with referenced parameter bodies that belong to group visible on detail page](/documentation/user/en/query/requirements/examples/fetching/referenceContentFilter.rest.json.md) - + As you can see only the parameters of the groups having *isVisibleInDetail* set to *TRUE* are returned. @@ -1505,8 +1505,8 @@ you can use the order constraint inside the `referenceContent` requirement. -The `referenceContent` ordering -on reference fields implicitly targets the attributes on the same reference +The `referenceContent` ordering +on reference fields implicitly targets the attributes on the same reference it points to, so you don't need to specify a [`referenceProperty`](../ordering/reference.md#reference-property) constraint. However, if you need to declare constraints on referenced entity attributes, you must wrap them in the [`entityProperty`](../ordering/reference.md#entity-property) @@ -1531,25 +1531,25 @@ query: The returned `Product` entity will contain a list of all parameters in the expected order: - + [The result of an entity fetched with referenced parameter ordered by name](/documentation/user/en/query/requirements/examples/fetching/referenceContentOrder.evitaql.json.md) - - + + [The result of an entity fetched with referenced parameter ordered by name](/documentation/user/en/query/requirements/examples/fetching/referenceContentOrder.graphql.json.md) - - + + [The result of an entity fetched with referenced parameter ordered by name](/documentation/user/en/query/requirements/examples/fetching/referenceContentOrder.rest.json.md) - + - + ### Reference content all @@ -1589,7 +1589,7 @@ referenceContentAll( -The `referenceContentAll` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) +The `referenceContentAll` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) is a variation of the [`referenceContent`](#reference-content) requirement that allows you to access the information about the references the entity has towards other entities (either managed by evitaDB itself or by any other external system). The `referenceContentAll` is a shortcut that simply targets all references defined for the entity. It can be @@ -1613,17 +1613,17 @@ To get an entity with all the references available, use the following query: The returned `Product` entity will contain primary keys and codes of all its references: - + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentAll.evitaql.json.md) - + - + - + ### Reference content with attributes @@ -1674,7 +1674,7 @@ referenceContentWithAttributes( -The `referenceContentWithAttributes` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) +The `referenceContentWithAttributes` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) is a variation of the [`referenceContent`](#reference-content) requirement that allows you to access the information about the references the entity has towards other entities (either managed by evitaDB itself or by any other external system) and the attributes set on those references. The `referenceContentWithAttributes` allows you to specify the list @@ -1700,25 +1700,25 @@ combination and which parameter values are merely informative, use the following The returned `Product` entity will contain references to parameter values and for each of it, it specifies the type of the relation between the product and the parameter value: - + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentWithAttributes.evitaql.json.md) - - + + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentWithAttributes.rest.json.md) - + As you can see, the *cellular-true*, *display-size-10-2*, *ram-memory-4*, *rom-memory-256* and *color-yellow* parameter values define the product variant, while the other parameters only describe the additional properties of the product. - + - + ### Reference content all with attributes @@ -1764,14 +1764,14 @@ referenceContentAllWithAttributes( -The `referenceContentAllWithAttributes` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) +The `referenceContentAllWithAttributes` (evita_query/src/main/java/io/evitadb/api/query/require/ReferenceContent.javaEvitaDB.Client/Queries/Requires/ReferenceContent.cs) is a variation of the [`referenceContent`](#reference-content) requirement that allows you to access the information about the references the entity has towards other entities (either managed by evitaDB itself or by any other external system) and the attributes set on those references. The `referenceContentAllWithAttributes` allows you to specify the list of attributes to fetch, but by default it fetches all attributes on the reference. It doesn't allow you to specify the reference names - because it targets all of them, and so you can specify the constraints and the attributes that are shared by all of the references. This constraint is only useful in exploration scenarios. - + For detail information, see the [`referenceContent`](#reference-content) requirement chapter. @@ -1791,15 +1791,15 @@ To obtain an entity with all the references and their attributes, use the follow The returned `Product` entity will contain all the references and the attributes set on this relation: - + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentAllWithAttributes.evitaql.json.md) - - + + [The result of an entity fetched with all references](/documentation/user/en/query/requirements/examples/fetching/referenceContentAllWithAttributes.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/requirements/hierarchy.md b/documentation/user/en/query/requirements/hierarchy.md index f737c9f2c..79d67f2a2 100644 --- a/documentation/user/en/query/requirements/hierarchy.md +++ b/documentation/user/en/query/requirements/hierarchy.md @@ -32,35 +32,35 @@ There are a huge number of possible variations, and it is difficult to support a That's why there is an extensible mechanism by which you can request the computation of multiple different parts of the hierarchy tree, as you actually need it for your particular user interface use case. - + There are two type of top hierarchy requirements: - +
[`hierarchyOfSelf`](#hierarchy-of-self)
- realized by evita_query/src/main/java/io/evitadb/api/query/require/HierarchyOfSelf.javaEvitaDB.Client/Queries/Requires/HierarchyOfSelf.cs + realized by evita_query/src/main/java/io/evitadb/api/query/require/HierarchyOfSelf.javaEvitaDB.Client/Queries/Requires/HierarchyOfSelf.cs and is used to compute data structures from the data of the directly queried hierarchical entity
[`hierarchyOfReference`](#hierarchy-of-reference)
- realized by evita_query/src/main/java/io/evitadb/api/query/require/HierarchyOfReference.javaEvitaDB.Client/Queries/Requires/HierarchyOfReference.cs + realized by evita_query/src/main/java/io/evitadb/api/query/require/HierarchyOfReference.javaEvitaDB.Client/Queries/Requires/HierarchyOfReference.cs and is used to compute data structures from the data of the entities referencing hierarchical entity
-
+
These top hierarchy requirements must have at least one of the following hierarchy sub-constraints: -
- + + Hierarchy data structures can be requested by specifying the `hierarchy` field in extra results of query. Specific data structures can be requested either from the data of the directly queried hierarchical entity, or from the data of the entities referencing hierarchical entity. Either way, you can then request one or more of the following hierarchy data structures: - + - [`fromRoot`](#from-root) - [`fromNode`](#from-node) @@ -70,15 +70,15 @@ Either way, you can then request one or more of the following hierarchy data str #### Constraint to result association - + There can be multiple sub-constraints, and each constraint can be duplicated (usually with different settings). -Each hierarchy sub-constraint defines a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) +Each hierarchy sub-constraint defines a [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument with a named value that allows to associate the request constraint with the computed result data structure -in evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.javaEvitaDB.Client/Models/ExtraResults/Hierarchy.cs +in evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.javaEvitaDB.Client/Models/ExtraResults/Hierarchy.cs extra result. - - + + There can be requested multiple data structures, and each data structure can be duplicated (usually with different settings), but in such case, each data structure must be aliased with unique name (see examples below). Each such data structure then returns a list of hierarchy tree nodes. @@ -93,7 +93,7 @@ Note that the list of nodes is sorted in [depth-first](https://en.wikipedia.org/ can be used to simplify the reconstruction of the tree on the client side. - + @@ -106,43 +106,43 @@ The following code snippet contains a query that lists all (transitive) categori returns menu items that contain direct children of the *Audio* category and its direct parent category (which is *Accessories*): - + [Hierarchy request association](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-data-structure-association.java) - + -Both menu components are stored in the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.javaEvitaDB.Client/Models/ExtraResults/Hierarchy.cs +Both menu components are stored in the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.javaEvitaDB.Client/Models/ExtraResults/Hierarchy.cs extra result data structure and are available under the labels that correspond to those used in request constraints. - - + + Using the custom aliases for hierarchies, you can easily create custom menu data structures. - + - + [Output with multiple menu parts](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-data-structure-association.evitaql.json.md) - + - + [Output with multiple menu parts](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-data-structure-association.graphql.json.md) - + - + [Output with multiple menu parts](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-data-structure-association.rest.json.md) - + ## Hierarchy of self - + ```evitaql-syntax hierarchyOfSelf( @@ -154,9 +154,9 @@ hierarchyOfSelf(
orderConstraint:any
- optional ordering constraint that allows you to specify an order of - evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java - EvitaDB.Client/Models/ExtraResults/Hierarchy.cs + optional ordering constraint that allows you to specify an order of + evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java + EvitaDB.Client/Models/ExtraResults/Hierarchy.cs `LevelInfo` elements in the result hierarchy data structure
requireConstraint:(fromRoot|fromNode|siblings|children|parents)+
@@ -173,17 +173,17 @@ hierarchyOfSelf(
-The requirement triggers the calculation of the -evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java -EvitaDB.Client/Models/ExtraResults/Hierarchy.cs data +The requirement triggers the calculation of the +evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java +EvitaDB.Client/Models/ExtraResults/Hierarchy.cs data structure for the hierarchy of which it is a part. The hierarchy of self can still be combined with [`hierarchyOfReference`](#hierarchy-of-reference) if the queried entity is a hierarchical entity that is also connected to another hierarchical entity. Such situations are rather sporadic in reality. -
- + + "Self" hierarchy data structures can be requested inside the `extraResult` → `hierarchy` using the reserved `self` field, similarly to [referenced hierarchies](#hierarchy-of-reference). @@ -208,11 +208,11 @@ Within the `self` field you can then request one or more of the following hierar On the `self` field, you can specify an optional ordering constraint argument that allows you to specify an order of the returned nodes in the result hierarchy data structure. - + ## Hierarchy of reference - + ```evitaql-syntax hierarchyOfReference( @@ -234,7 +234,7 @@ hierarchyOfReference(
argument:enum(LEAVE_EMPTY|REMOVE_EMPTY)
- optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/EmptyHierarchicalEntityBehaviour.javaEvitaDB.Client/Queries/Requires/EmptyHierarchicalEntityBehaviour.cs + optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/EmptyHierarchicalEntityBehaviour.javaEvitaDB.Client/Queries/Requires/EmptyHierarchicalEntityBehaviour.cs enum allowing you to specify whether or not to return empty hierarchical entities (e.g., those that do not have any queried entities that satisfy the current query filter constraint assigned to them - either directly or transitively): @@ -244,11 +244,11 @@ hierarchyOfReference(
orderConstraint:any
- optional ordering constraint that allows you to specify an order of - evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java - EvitaDB.Client/Models/ExtraResults/Hierarchy.cs + optional ordering constraint that allows you to specify an order of + evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java + EvitaDB.Client/Models/ExtraResults/Hierarchy.cs `LevelInfo` elements in the result hierarchy data structure - +
requireConstraint:(fromRoot|fromNode|siblings|children|parents)+
@@ -265,8 +265,8 @@ hierarchyOfReference( The requirement triggers the calculation of the -evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java -EvitaDB.Client/Models/ExtraResults/Hierarchy.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/Hierarchy.java +EvitaDB.Client/Models/ExtraResults/Hierarchy.cs data structure for the hierarchies of the [referenced entity type](../../use/schema.md#reference). The hierarchy of reference can still be combined with [`hierarchyOfSelf`](#hierarchy-of-self) if the queried entity @@ -276,8 +276,8 @@ reality. The `hierarchyOfReference` can be repeated multiple times in a single query if you need different calculation settings for different reference types. - - + + Hierarchy data structures for the [referenced hierarchical entities](../../use/schema.md#reference) can be requested inside the `extraResult` → `hierarchy` → `{reference name}` fields. @@ -312,11 +312,11 @@ either directly or transitively): - **LEAVE_EMPTY**: empty hierarchical nodes will remain in computed data structures - **REMOVE_EMPTY**: empty hierarchical nodes are omitted from computed data structures (default behaviour) - + ## From root - + ```evitaql-syntax fromRoot( @@ -328,9 +328,9 @@ fromRoot(
argument:string!
- mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument - specifying the output name for the calculated data structure + mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument + specifying the output name for the calculated data structure (see [constraint to result association](#constraint-to-result-association))
requireConstraint:(entityFetch|stopAt|statistics)*
@@ -346,15 +346,15 @@ fromRoot(
-
+ -The `fromRoot` requirementdata structure +The `fromRoot` requirementdata structure computes the hierarchy tree starting from the "virtual" invisible top root of the hierarchy, regardless of the potential use of the `hierarchyWithin` constraint in the filtering part of the query. The scope of -the calculated information can be controlled by the [`stopAt`](#stop-at) constraintargument. +the calculated information can be controlled by the [`stopAt`](#stop-at) constraintargument. By default, the traversal goes all the way to the bottom of the hierarchy tree unless you tell it to stop anywhere. If you need to access statistical data, -use [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. +use [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. Calculated data is not affected by the `hierarchyWithin` filter constraint - the query can filter entities using `hierarchyWithin` from category *Accessories*, while still allowing you to correctly compute menu at root level. @@ -375,7 +375,7 @@ requires a computed *megaMenu* data structure that lists the top 2 levels of the a computed count of child categories for each menu item and an aggregated count of all filtered products that would fall into the given category. - + [Example of using `hierarchyWithin` and `fromRoot` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-root.java) @@ -386,23 +386,23 @@ The computed result of the *megaMenu* looks like this: ... and here is the data structure output in JSON format: - + [Example of using `hierarchyWithin` and `fromRoot` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-root.evitaql.json.md) - + - + [Example of using `hierarchyWithin` and `fromRoot` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-root.graphql.json.md) - + - + [Example of using `hierarchyWithin` and `fromRoot` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-root.rest.json.md) - + @@ -415,7 +415,7 @@ the calculated number remains consistent for the end user. ## From node - + ```evitaql-syntax fromNode( @@ -428,9 +428,9 @@ fromNode(
argument:string!
- mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument - specifying the output name for the calculated data structure + mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument + specifying the output name for the calculated data structure (see [constraint to result association](#constraint-to-result-association))
requireConstraint:node!
@@ -451,19 +451,19 @@ fromNode(
-
+ -The `fromNode` requirementdata structure +The `fromNode` requirementdata structure computes the hierarchy tree starting from the pivot node of the hierarchy, that is identified -by the [`node`](#node) inner constraintargument. +by the [`node`](#node) inner constraintargument. The `fromNode` calculates the result regardless of the potential use of the `hierarchyWithin` constraint in the filtering part of the query. The scope of the calculated -information can be controlled by the [`stopAt`](#stop-at) constraintargument. +information can be controlled by the [`stopAt`](#stop-at) constraintargument. By default, the traversal goes all the way to the bottom of the hierarchy tree unless you tell it to stop anywhere. Calculated data is not affected by the `hierarchyWithin` filter constraint - the query can filter entities using `hierarchyWithin` from category *Accessories*, while still allowing you to correctly compute menu at different node defined in a `fromNode` requirement. -If you need to access statistical data, use [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. +If you need to access statistical data, use [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. @@ -477,7 +477,7 @@ returns a computed *sideMenu1* and *sideMenu2* data structure that lists the fla *Portables* and *Laptops* with a computed count of child categories for each menu item and an aggregated count of all products that would fall into the given category. - + [Example of using `hierarchyWithin` and `fromNode` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-node.java) @@ -488,23 +488,23 @@ The computed result both of the *sideMenu1* and *sideMenu2* looks like this: ... and here is the data structure output in JSON format: - + [Example of using `hierarchyWithin` and `fromNode` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-node.evitaql.json.md) - + - + [Example of using `hierarchyWithin` and `fromNode` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-node.graphql.json.md) - + - + [Example of using `hierarchyWithin` and `fromNode` in a single query](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-from-node.rest.json.md) - + @@ -517,7 +517,7 @@ the calculated number remains consistent for the end user. ## Children - + ```evitaql-syntax children @@ -529,9 +529,9 @@ children
argument:string!
- mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument - specifying the output name for the calculated data structure + mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument + specifying the output name for the calculated data structure (see [constraint to result association](#constraint-to-result-association))
requireConstraint:(entityFetch|stopAt|statistics)*
@@ -547,16 +547,16 @@ children
-
+ -The `children` requirementdata structure +The `children` requirementdata structure computes the hierarchy tree starting at the same hierarchy node that is targeted by the filtering part of the same query using the [`hierarchyWithin`](../filtering/hierarchy.md#hierarchy-within) or [`hierarchyWithinRoot`](../filtering/hierarchy.md#hierarchy-within-root) constraints. The scope of the calculated -information can be controlled by the [`stopAt`](#stop-at) constraintargument. +information can be controlled by the [`stopAt`](#stop-at) constraintargument. By default, the traversal goes all the way to the bottom of the hierarchy tree unless you tell it to stop anywhere. If you need to access statistical data, use -the [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. +the [`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. @@ -570,7 +570,7 @@ returns a computed *subcategories* data structure that lists the flat category l *Audio* with a computed count of child categories for each menu item and an aggregated count of all products that would fall into the given category. - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-children.java) @@ -581,23 +581,23 @@ The computed result *subcategories* looks like this: ... and here is the data structure output in JSON format: - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-children.evitaql.json.md) - + - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-children.graphql.json.md) - + - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-children.rest.json.md) - + @@ -612,7 +612,7 @@ so that the calculated number remains consistent for the end user. ## Parents - + ```evitaql-syntax parents @@ -624,9 +624,9 @@ parents
argument:string!
- mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument - specifying the output name for the calculated data structure + mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument + specifying the output name for the calculated data structure (see [constraint to result association](#constraint-to-result-association))
requireConstraint:(siblings|entityFetch|stopAt|statistics)*
@@ -643,16 +643,16 @@ parents
-
+ -The `parents` requirementdata structure +The `parents` requirementdata structure computes the hierarchy tree starting at the same hierarchy node that is targeted by the filtering part of the same query using the [`hierarchyWithin`](../filtering/hierarchy.md#hierarchy-within) constraint towards the root of the hierarchy. The scope of the calculated information can be controlled by the [`stopAt`](#stop-at) -constraintargument. +constraintargument. By default, the traversal goes all the way to the top of the hierarchy tree unless you tell it to stop at anywhere. If you need to access statistical data, use the -[`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. +[`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. @@ -666,7 +666,7 @@ also returns a computed *parentAxis* data structure that lists all the parent no *True wireless* with a computed count of child categories for each menu item and an aggregated count of all products that would fall into the given category. - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents.java) @@ -677,27 +677,27 @@ The computed result *parentAxis* looks like this: ... and here is the data structure output in JSON format: - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents.evitaql.json.md) - + - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents.graphql.json.md) - + - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents.rest.json.md) - + You can also list all siblings of the parent node as you move up the tree: - + [Example of using `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents-siblings.java) @@ -708,27 +708,27 @@ The computed result *parentAxis* with siblings now looks like this: ... and here is the data structure output in JSON format: - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents-siblings.evitaql.json.md) - + - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents-siblings.graphql.json.md) - + - + [Example of using `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parents-siblings.rest.json.md) - + If you need each of these siblings to fetch their child nodes as well (no matter if they are only one level deep or -more), you can do this by adding a `stopAt` constraint -argument to the `siblings` constraint containerdata structure. +more), you can do this by adding a `stopAt` constraint +argument to the `siblings` constraint containerdata structure. However, this scenario is too complex to cover in this documentation. @@ -743,7 +743,7 @@ for the end user. ## Siblings - + ```evitaql-syntax siblings( @@ -752,7 +752,7 @@ siblings( ) ``` - + @@ -761,7 +761,7 @@ siblings( ##### Different `siblings` syntax when used within `parents` parent constraint - + ```evitaql-syntax siblings( @@ -769,32 +769,32 @@ siblings( ) ``` - + -The `siblings` constraintdata structure -can be used separately as a child of `hierarchyOfSelf` or `hierarchyOfReference``hierarchy` field, or it can be -used as a child constraintargument -of the [`parents`](#parents) constraintdata structure. - +The `siblings` constraintdata structure +can be used separately as a child of `hierarchyOfSelf` or `hierarchyOfReference``hierarchy` field, or it can be +used as a child constraintargument +of the [`parents`](#parents) constraintdata structure. + In such a case, the `siblings` constraint lacks the first string argument that defines the name for the output data structure. The reason is that this name is already defined on the enclosing `parents` constraint, and the `siblings` constraint simply extends the data available in its data structure. - - + + In such a case, the `siblings` argument simply just requests more data in the `parent` data structure if present. However, you can still define custom [`stopAt`](#stop-at) argument specific to siblings within the `siblings` argument. - + - +
argument:string!
- mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument - specifying the output name for the calculated data structure + mandatory [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) argument + specifying the output name for the calculated data structure (see [constraint to result association](#constraint-to-result-association))
requireConstraint:(entityFetch|stopAt|statistics)*
@@ -810,20 +810,20 @@ you can still define custom [`stopAt`](#stop-at) argument specific to siblings w
-
+ -The `siblings` requirementdata structure +The `siblings` requirementdata structure computes the hierarchy tree starting at the same hierarchy node that is targeted by the filtering part of the same query using the [`hierarchyWithin`](../filtering/hierarchy.md#hierarchy-within). It lists all sibling nodes to the node that is requested by `hierarchyWithin` constraint (that's why the `siblings` has no sense with `hierarchyWithinRoot` constraint - "virtual" top level node cannot have any siblings). Siblings will produce a flat list of siblings unless the [`stopAt`](#stop-at) -constraintargument -is used as an inner constrainton the `siblings` field. -The [`stopAt`](#stop-at) constraintargument +constraintargument +is used as an inner constrainton the `siblings` field. +The [`stopAt`](#stop-at) constraintargument triggers a top-down hierarchy traversal from each of the sibling nodes until the [`stopAt`](#stop-at) is satisfied. If you need to access statistical data, use the -[`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. +[`statistics`](#statistics) constraintthe [`childrenCount` and `queriedEntityCount` fields](#statistics) on the node object. @@ -837,7 +837,7 @@ returns a computed *audioSiblings* data structure that lists the flat category l *Audio* with a computed count of child categories for each menu item and an aggregated count of all products that would fall into the given category. - + [Example of using `siblings` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings.java) @@ -848,52 +848,52 @@ The computed result *audioSiblings* looks like this: ... and here is the data structure output in JSON format: - + [Example of using `siblings` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings.evitaql.json.md) - + - + [Example of using `siblings` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings.graphql.json.md) - + - + [Example of using `siblings` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings.rest.json.md) - + If you need to return all siblings and also the level below them (their children), just use the `stopAt` -constraintargument and -extend the default scope of the `siblings` constraintdata structure. +constraintargument and +extend the default scope of the `siblings` constraintdata structure. - + [Example of using `siblings` subtree requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings-with-subtree.java) The computed result *audioSiblings* with their direct children looks like this (visualized in JSON format): - + [Example of using `siblings` subtree requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings-with-subtree.evitaql.json.md) - + - + [Example of using `siblings` subtree requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings-with-subtree.graphql.json.md) - + - + [Example of using `siblings` subtree requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-siblings-with-subtree.rest.json.md) - + @@ -925,10 +925,10 @@ stopAt( -The `stopAt` container constraintargument +The `stopAt` container constraintargument is a service wrapping constraint container that only makes sense -in combination with one of the allowed nested constraintsas an argument of one of the data structures. -See the usage examples for specific nested constraintsdata structures. +in combination with one of the allowed nested constraintsas an argument of one of the data structures. +See the usage examples for specific nested constraintsdata structures. ## Distance @@ -948,7 +948,7 @@ distance( The `distance` constraint can only be used within the `stopAt` -containerargument +containerargument and limits the hierarchy traversal to stop when the number of levels traversed reaches the specified constant. The distance is always relative to the pivot node (the node where the hierarchy traversal starts) and is the same whether we are traversing the hierarchy top-down or @@ -966,59 +966,59 @@ The following query lists products in category *Audio* and its subcategories. Al returns a computed *subcategories* data structure that lists the flat category list the currently focused category *Audio*. - + [Example of using `distance` with `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-direct-children.java) Which returns following output: - + [Direct children](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-direct-children.evitaql.json.md) - + - + [Direct children](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-direct-children.graphql.json.md) - + - + [Direct children](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-direct-children.rest.json.md) - + The following query lists products in the category *Audio* and its subcategories. Along with the products returned, it also returns a computed *parent* data structure that lists single direct parent category of the currently focused *Audio* category. - + [Example of using `distance` with `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parent.java) That returns simply: - + [Direct parent](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parent.evitaql.json.md) - + - + [Direct parent](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parent.graphql.json.md) - + - + [Direct parent](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-parent.rest.json.md) - + @@ -1040,7 +1040,7 @@ level( The `level` constraint can only be used within the `stopAt` -containerargument +containerargument and limits the hierarchy traversal to stop when the actual level of the traversed node is equal to a specified constant. The "virtual" top invisible node has level zero, the top nodes (nodes with `NULL` parent) have level one, their children have level two, and so on. See the @@ -1056,59 +1056,59 @@ following figure: The following query lists products in *Audio* category and its subcategories. Along with the products returned, it also returns a computed *megaMenu* data structure that lists top two levels of the entire hierarchy. - + [Example of using `level` with `fromRoot` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level.java) Which returns: - + [Top 2 level of categories](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level.evitaql.json.md) - + - + [Top 2 level of categories](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level.graphql.json.md) - + - + [Top 2 level of categories](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level.rest.json.md) - + The following query lists products in the *Audio* category and its subcategories. Along with the products returned, it also returns a computed *parent* data structure that lists all the parents of the currently focused *True wireless* category up to level two. - + [Example of using `level` with `parents` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level-parent.java) ... returns output: - + [Parents up to level 2](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level-parent.evitaql.json.md) - + - + [Parents up to level 2](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level-parent.graphql.json.md) - + - + [Parents up to level 2](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-level-parent.rest.json.md) - + @@ -1144,36 +1144,36 @@ a meaningful example of this in the demo dataset, so our example query will be s demonstration, let's list the entire *Accessories* hierarchy, but stop traversing at the nodes whose code starts with the letter *w*. - + [Example of using `node` with `children` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-node.java) The computed result *subMenu* looks like this (visualized in JSON format): - + [Example of using `node` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-node.evitaql.json.md) - + - + [Example of using `node` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-node.graphql.json.md) - + - + [Example of using `node` requirement](/documentation/user/en/query/requirements/examples/hierarchy/hierarchy-node.rest.json.md) - + ## Statistics - + ```evitaql-syntax statistics( @@ -1185,7 +1185,7 @@ statistics(
argument:enum(COMPLETE_FILTER|WITHOUT_USER_FILTER)
- optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/StatisticsBase.javaEvitaDB.Client/Queries/Requires/StatisticsBase.cs + optional argument of type evita_query/src/main/java/io/evitadb/api/query/require/StatisticsBase.javaEvitaDB.Client/Queries/Requires/StatisticsBase.cs enum allowing you to specify the base queried entity set that is the source for statistics calculations: - **COMPLETE_FILTER**: complete filtering query constraint - **WITHOUT_USER_FILTER**: filtering query constraint where the contents of optional @@ -1198,7 +1198,7 @@ statistics(
argument:enum(CHILDREN_COUNT|QUERIED_ENTITY_COUNT)+
- mandatory argument of type evita_query/src/main/java/io/evitadb/api/query/require/StatisticsType.javaEvitaDB.Client/Queries/Requires/StatisticsType.cs + mandatory argument of type evita_query/src/main/java/io/evitadb/api/query/require/StatisticsType.javaEvitaDB.Client/Queries/Requires/StatisticsType.cs enum that specifies which statistics to compute for each node in the returned hierarchy: - **CHILDREN_COUNT**: triggers calculation of the count of child hierarchy nodes that exist in the hierarchy @@ -1215,9 +1215,9 @@ statistics(
-
+ - + ### Statistics base @@ -1243,10 +1243,10 @@ constraints are crucial for the calculation of `queriedEntityCount` (and therefo filter constraint (the possible refining constraint in the form of [`directRelation`](../filtering/hierarchy.md#direct-relation) and [`excluding-root`](../filtering/hierarchy.md#excluding-root) is not taken into account). - + -The `statistics` constraint with `CHILDREN_COUNT` -The `childrenCount` field on a hierarchy node allows you to easily +The `statistics` constraint with `CHILDREN_COUNT` +The `childrenCount` field on a hierarchy node allows you to easily render collapsed menu showing the nodes available for opening without actually requesting the child nodes from the database: ![Accessories dynamic tree example](assets/accessories-tree.png "Accessories dynamic tree example") @@ -1254,8 +1254,8 @@ render collapsed menu showing the nodes available for opening without actually r As you can see, the *Smart wearable*, *Audio*, and *Keyboards* nodes have a plus sign next to them, indicating that the user can expand this category. -The `statistics` constraint with `QUERIED_ENTITY_COUNT` -The `queriedEntityCount` field on a hierarchy allows you to display +The `statistics` constraint with `QUERIED_ENTITY_COUNT` +The `queriedEntityCount` field on a hierarchy allows you to display the number of items hidden behind the given hierarchy node (category): ![Queried entity counts example](assets/category-queried-entity-counts.png "Queried entity counts example") @@ -1271,12 +1271,12 @@ branched the series category may be. The performance price paid for calculating statistics is not negligible. The calculation of -`CHILDREN_COUNT``childrenCount` +`CHILDREN_COUNT``childrenCount` is cheaper because it allows to eliminate "dead branches" early and thus conserve the computation cycles. The calculation of -the `QUERIED_ENTITY_COUNT``queriedEntityCount` +the `QUERIED_ENTITY_COUNT``queriedEntityCount` is more expensive because it requires counting items up to the last one and must be precise. -**We strongly recommend that you avoid using `QUERIED_ENTITY_COUNT``queriedEntityCount` +**We strongly recommend that you avoid using `QUERIED_ENTITY_COUNT``queriedEntityCount` for root hierarchy nodes for large datasets.** This query actually has to filter and aggregate all the records in the database, which is obviously quite expensive, diff --git a/documentation/user/en/query/requirements/histogram.md b/documentation/user/en/query/requirements/histogram.md index fbcc693d3..ebf5c9fb3 100644 --- a/documentation/user/en/query/requirements/histogram.md +++ b/documentation/user/en/query/requirements/histogram.md @@ -38,7 +38,7 @@ The histogram data structure is optimized for frontend rendering. It contains th ## Attribute histogram - + ```evitaql-syntax attributeHistogram( @@ -68,10 +68,10 @@ attributeHistogram( - + -The evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/AttributeHistogram.javaEvitaDB.Client/Models/ExtraResults/AttributeHistogram.cs -attribute histogram +The evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/AttributeHistogram.javaEvitaDB.Client/Models/ExtraResults/AttributeHistogram.cs +attribute histogram can be computed from any [filterable attribute](../../use/data-model.md#attributes-unique-filterable-sortable-localized) whose type is numeric. The histogram is computed only from the attributes of elements that match the current mandatory part of the filter. The interval related constraints - i.e. [`attributeBetween`](../filtering/comparable.md#attribute-between) @@ -101,21 +101,21 @@ The simplified result looks like this: The histogram result in JSON format is a bit more verbose, but it's still quite readable: - + [The result of `width` and `height` attribute histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/attribute-histogram.evitaql.json.md) - - + + [The result of `width` and `height` attribute histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/attribute-histogram.graphql.json.md) - - + + [The result of `width` and `height` attribute histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/attribute-histogram.rest.json.md) - + @@ -172,7 +172,7 @@ As you can see, the number of buckets has been adjusted to fit the data, contrar ## Price histogram - + ```evitaql-syntax priceHistogram( @@ -196,10 +196,10 @@ priceHistogram( - + -The evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/PriceHistogram.javaEvitaDB.Client/Models/ExtraResults/PriceHistogram.cs -price histogram +The evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/PriceHistogram.javaEvitaDB.Client/Models/ExtraResults/PriceHistogram.cs +price histogram is computed from the [price for sale](../filtering/price.md). The interval related constraints - i.e. [`attributeBetween`](../filtering/comparable.md#attribute-between) and [`priceBetween`](../filtering/price.md#price-between) in the [`userFilter`](../filtering/behavioral.md#user-filter) part are excluded for the sake of histogram calculation. @@ -231,21 +231,21 @@ The simplified result looks like this: The histogram result in JSON format is a bit more verbose, but it's still quite readable: - + [The result of price histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/price-histogram.evitaql.json.md) - - + + [The result of price histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/price-histogram.graphql.json.md) - - + + [The result of price histogram in JSON format](/documentation/user/en/query/requirements/examples/histogram/price-histogram.rest.json.md) - + diff --git a/documentation/user/en/query/requirements/paging.md b/documentation/user/en/query/requirements/paging.md index 842b1bd98..4c8e6f67a 100644 --- a/documentation/user/en/query/requirements/paging.md +++ b/documentation/user/en/query/requirements/paging.md @@ -1,8 +1,8 @@ --- title: Paging perex: | - Paging request constraints help to traverse large lists of records by splitting them into several parts that are requested - separately. This technique is used to reduce the amount of data transferred over the network and to reduce the load + Paging request constraints help to traverse large lists of records by splitting them into several parts that are requested + separately. This technique is used to reduce the amount of data transferred over the network and to reduce the load on the server. evitaDB supports several ways to paginate query results, which are described in this section. date: '23.7.2023' author: 'Ing. Jan Novotný' @@ -10,7 +10,7 @@ proofreading: 'done' preferredLang: 'evitaql' --- - + In GraphQL, there are multiple different ways to paginate results. The main distinction is between the [`list` queries](../../use/api/query-data.md#list-queries) and [`query` queries](../../use/api/query-data.md#query-queries). @@ -19,7 +19,7 @@ The `query` queries are then further divided into `page` and `strip` pagination. ## Pagination of `list` queries As mentioned in [detailed description of `list` queries](../../use/api/query-data.md#list-queries), the `list` queries -are meant to be used for quick listing of entities, and so they offer only a limited set of pagination features. +are meant to be used for quick listing of entities, and so they offer only a limited set of pagination features. The pagination is controlled by the `limit` and `offset` arguments on a `listCollectionName` field, and it doesn't provide any pagination metadata (e.g., total number of records, page number, and so on): @@ -40,17 +40,17 @@ The result contains the result from the 11th through the 15th record of the list of the records because no content request was specified, and it is sorted by the primary key in ascending order because no order was specified in the query. - + [The data chunk with paginated data](/documentation/user/en/query/requirements/examples/paging/listEntities.graphql.json.md) - + - + - + ## Pagination of `query` queries @@ -59,8 +59,8 @@ The pagination in this case has two versions - `page` (`recordPage` field) and ` ### Page (`recordPage`) - - + + ## Page @@ -82,27 +82,27 @@ page( - - -The `page` -(evita_query/src/main/java/io/evitadb/api/query/require/Page.java)(EvitaDB.Client/Queries/Requires/Page.cs) requirement -approach -controls the number and slice of entities returned in the query response and is specified by usage of the `recordPage` field (in combination with `number` and `size` arguments). -If no -page requirement is -page arguments are used -in the query -on the field, + + +The `page` +(evita_query/src/main/java/io/evitadb/api/query/require/Page.java)(EvitaDB.Client/Queries/Requires/Page.cs) requirement +approach +controls the number and slice of entities returned in the query response and is specified by usage of the `recordPage` field (in combination with `number` and `size` arguments). +If no +page requirement is +page arguments are used +in the query +on the field, the default page `1` with the default page size `20` is used. If the requested page exceeds the number of available pages, a result with the first page is returned. An empty result is only returned if the query returns no result at all or the page size is set to zero. By automatically returning the first page result when the requested page is exceeded, we try to avoid the need to issue a secondary request to fetch the data. The information about the actual returned page and data statistics can be found in the query response, which is wrapped -in a so-called data chunk object. In case of the `page` constraint, -the evita_common/src/main/java/io/evitadb/dataType/PaginatedList.java -EvitaDB.Client/DataTypes/PaginatedList.cs is used as data chunk -object. The data chunk object contains the following information: +in a so-called data chunk object. In case of the `page` constraint, +the evita_common/src/main/java/io/evitadb/dataType/PaginatedList.java +EvitaDB.Client/DataTypes/PaginatedList.cs is used as data chunk +object. The data chunk object contains the following information:
pageNumber
@@ -159,7 +159,7 @@ object. The data chunk object contains the following informat
-The `page` requirement`recordPage` field +The `page` requirement`recordPage` field is the most natural and commonly used requirement for the pagination of the query results. To get the second page of the query result, use the following query: @@ -175,35 +175,35 @@ To get the second page of the query result, use the following query: ##### The result of second page example -The result contains the result from the 6th through the 10th record of the query result. It returns only a primary key -of the records because no content request was specified, and it is sorted by the primary key in ascending order because +The result contains the result from the 6th through the 10th record of the query result. It returns only a primary key +of the records because no content request was specified, and it is sorted by the primary key in ascending order because no order was specified in the query. - + [The data chunk with paginated data](/documentation/user/en/query/requirements/examples/paging/page.evitaql.json.md) - - + + [The data chunk with paginated data](/documentation/user/en/query/requirements/examples/paging/page.graphql.json.md) - - + + [The data chunk with paginated data](/documentation/user/en/query/requirements/examples/paging/page.rest.json.md) - + - + ### Strip (`recordStrip`) - + - + ## Strip @@ -225,22 +225,22 @@ strip( - + The `strip` -(evita_query/src/main/java/io/evitadb/api/query/require/Strip.java)(EvitaDB.Client/Queries/Requires/Strip.cs) requirement -approach -controls the number and slice of entities returned in the query response and is specified by usage of the `recordStrip` field (in combination with `limit` and `offset` arguments). +(evita_query/src/main/java/io/evitadb/api/query/require/Strip.java)(EvitaDB.Client/Queries/Requires/Strip.cs) requirement +approach +controls the number and slice of entities returned in the query response and is specified by usage of the `recordStrip` field (in combination with `limit` and `offset` arguments). If the requested strip exceeds the number of available records, a result from the zero offset with retained limit is returned. An empty result is only returned if the query returns no result at all or the limit is set to zero. By automatically returning the first strip result when the requested page is exceeded, we try to avoid the need to issue a secondary request to fetch the data. The information about the actual returned page and data statistics can be found in the query response, which is wrapped -in a so-called data chunk object. In case of the `strip` constraint, -the evita_common/src/main/java/io/evitadb/dataType/StripList.java -EvitaDB.Client/DataTypes/StripList.cs is used as data chunk -object.The data chunk object contains the following information: +in a so-called data chunk object. In case of the `strip` constraint, +the evita_common/src/main/java/io/evitadb/dataType/StripList.java +EvitaDB.Client/DataTypes/StripList.cs is used as data chunk +object.The data chunk object contains the following information:
offset
@@ -281,11 +281,11 @@ object.The data chunk object contains the following informati
-The `strip` requirement can be used to list query records in a non-uniform way - for example, when the entity listing is -interleaved with an advertisement that requires an entity rendering to be skipped at certain positions. In other words, -if you know that there is an "advertisement" block every 20 records, which means that the entity must be skipped for -that position, and you want to correctly fetch records for the 5th page, you need to request a strip with offset `76` -(4 pages * 20 positions per page - 4 records omitted on the previous 4 pages) and limit 19. To get such a strip, use +The `strip` requirement can be used to list query records in a non-uniform way - for example, when the entity listing is +interleaved with an advertisement that requires an entity rendering to be skipped at certain positions. In other words, +if you know that there is an "advertisement" block every 20 records, which means that the entity must be skipped for +that position, and you want to correctly fetch records for the 5th page, you need to request a strip with offset `76` +(4 pages * 20 positions per page - 4 records omitted on the previous 4 pages) and limit 19. To get such a strip, use the following query: @@ -304,20 +304,20 @@ The result contains the result from the 76th through the 95th record of the quer of the records because no content request was specified, and it is sorted by the primary key in ascending order because no order was specified in the query. - + [The data chunk with strip list](/documentation/user/en/query/requirements/examples/paging/strip.evitaql.json.md) - - + + [The data chunk with strip list](/documentation/user/en/query/requirements/examples/paging/strip.graphql.json.md) - - + + [The data chunk with strip list](/documentation/user/en/query/requirements/examples/paging/strip.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/query/requirements/price.md b/documentation/user/en/query/requirements/price.md index c22f94fef..ebd6e1aba 100644 --- a/documentation/user/en/query/requirements/price.md +++ b/documentation/user/en/query/requirements/price.md @@ -30,7 +30,7 @@ priceType( -The evita_query/src/main/java/io/evitadb/api/query/require/PriceType.javaEvitaDB.Client/Queries/Requires/PriceType.cs requirement +The evita_query/src/main/java/io/evitadb/api/query/require/PriceType.javaEvitaDB.Client/Queries/Requires/PriceType.cs requirement controls which price type is used when calculating the sales price and filtering or sorting by it. If no such requirement is specified, **the price with tax is used by default**. @@ -53,21 +53,21 @@ between `€100` and `€105`. The following query will do that: The result contains some products, which you can see in the following table: - + [Results filtered by price between €100 and €105](/documentation/user/en/query/requirements/examples/price/price-type.evitaql.md) - - + + [Results filtered by price between €100 and €105](/documentation/user/en/query/requirements/examples/price/price-type.graphql.json.md) - - + + [Results filtered by price between €100 and €105](/documentation/user/en/query/requirements/examples/price/price-type.rest.json.md) - + @@ -91,20 +91,20 @@ in this range with the price without tax. To do this, we need to modify the quer And now the result contains completely different products (in the output we show the price with tax to demonstrate the difference - in regular UI you'd choose to show the price without tax) with more appropriate price for particular user: - + [Different results filtered by price between €100 and €105 without tax](/documentation/user/en/query/requirements/examples/price/price-type-without-tax.evitaql.md) - - + + [Different results filtered by price between €100 and €105 without tax](/documentation/user/en/query/requirements/examples/price/price-type-without-tax.graphql.json.md) - - + + [Different results filtered by price between €100 and €105 without tax](/documentation/user/en/query/requirements/examples/price/price-type-without-tax.rest.json.md) - + diff --git a/documentation/user/en/query/requirements/telemetry.md b/documentation/user/en/query/requirements/telemetry.md index 91fd088e8..2738cb6d8 100644 --- a/documentation/user/en/query/requirements/telemetry.md +++ b/documentation/user/en/query/requirements/telemetry.md @@ -12,17 +12,17 @@ preferredLang: 'evitaql' ## Query telemetry - + ```evitaql-syntax queryTelemetry() ``` - + -The evita_query/src/main/java/io/evitadb/api/query/require/QueryTelemetry.java requirement -EvitaDB.Client/Queries/Requires/QueryTelemetry.cs requirement -`queryTelemetry` extra result field +The evita_query/src/main/java/io/evitadb/api/query/require/QueryTelemetry.java requirement +EvitaDB.Client/Queries/Requires/QueryTelemetry.cs requirement +`queryTelemetry` extra result field requests the computed query telemetry for the current query. The telemetry contains detailed information about the query processing time and its decomposition to single operations. @@ -33,7 +33,7 @@ the following data:
operation
Phase of the query execution. - Possible values can be found in the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/QueryTelemetry.java classEvitaDB.Client/Models/ExtraResults/QueryTelemetry.cs class. + Possible values can be found in the evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/QueryTelemetry.java classEvitaDB.Client/Models/ExtraResults/QueryTelemetry.cs class.
start
@@ -53,10 +53,10 @@ the following data:
- + By default the number values of the telemetry object are returned in raw form. You can change that in the GraphQL by using argument `format` on the `queryTelemetry` field. This way human-readable values are returned. - + To demonstrate the information the query telemetry is providing, we will use the following query that filters and sorts @@ -77,20 +77,20 @@ entities: The result contains query telemetry and some products (which we omitted here for brevity): - + [Result query telemetry for filtered and ordered entities](/documentation/user/en/query/requirements/examples/telemetry/queryTelemetryResult.evitaql.json.md) - - + + [Result query telemetry for filtered and ordered entities](/documentation/user/en/query/requirements/examples/telemetry/queryTelemetryResult.graphql.json.md) - - + + [Result query telemetry for filtered and ordered entities](/documentation/user/en/query/requirements/examples/telemetry/queryTelemetryResult.rest.json.md) - + \ No newline at end of file diff --git a/documentation/user/en/use/api/example/delete-entities-by-query.cs b/documentation/user/en/use/api/example/delete-entities-by-query.cs index 6cdd4ae9e..431be8289 100644 --- a/documentation/user/en/use/api/example/delete-entities-by-query.cs +++ b/documentation/user/en/use/api/example/delete-entities-by-query.cs @@ -5,8 +5,7 @@ Collection("Brand"), FilterBy( And( - AttributeStartsWith("name", "A"), - EntityLocaleEquals(new CultureInfo("en")) + AttributeStartsWith("name", "A") ) ), Require( diff --git a/documentation/user/en/use/api/example/delete-entities-by-query.graphql b/documentation/user/en/use/api/example/delete-entities-by-query.graphql index 2f5961370..0b09cb28d 100644 --- a/documentation/user/en/use/api/example/delete-entities-by-query.graphql +++ b/documentation/user/en/use/api/example/delete-entities-by-query.graphql @@ -2,7 +2,6 @@ mutation { deleteBrand( filterBy: { attributeNameStartsWith: "A" - entityLocaleEquals: en } limit: 20 ) { diff --git a/documentation/user/en/use/api/example/delete-entities-by-query.java b/documentation/user/en/use/api/example/delete-entities-by-query.java index 0885d50dd..5e1edc63e 100644 --- a/documentation/user/en/use/api/example/delete-entities-by-query.java +++ b/documentation/user/en/use/api/example/delete-entities-by-query.java @@ -1,3 +1,26 @@ +/* + * + * _ _ ____ ____ + * _____ _(_) |_ __ _| _ \| __ ) + * / _ \ \ / / | __/ _` | | | | _ \ + * | __/\ V /| | || (_| | |_| | |_) | + * \___| \_/ |_|\__\__,_|____/|____/ + * + * Copyright (c) 2024 + * + * Licensed under the Business Source License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/FgForrest/evitaDB/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + evita.updateCatalog( "evita", session -> { return session.deleteEntities( @@ -5,8 +28,7 @@ collection("Brand"), filterBy( and( - attributeStartsWith("name", "A"), - entityLocaleEquals(Locale.ENGLISH) + attributeStartsWith("name", "A") ) ), require( diff --git a/documentation/user/en/use/api/example/delete-entities-by-query.rest b/documentation/user/en/use/api/example/delete-entities-by-query.rest index a808d241b..d7bc768c6 100644 --- a/documentation/user/en/use/api/example/delete-entities-by-query.rest +++ b/documentation/user/en/use/api/example/delete-entities-by-query.rest @@ -1,9 +1,8 @@ -DELETE /rest/evita/brand +DELETE /rest/evita/Brand { "filterBy": { - "attributeNameStartsWith": "A", - "entityLocaleEquals": "en" + "attributeNameStartsWith": "A" }, "require": { "page": { diff --git a/documentation/user/en/use/api/example/evita-query-example.graphql b/documentation/user/en/use/api/example/evita-query-example.graphql index abdbf9d13..83cfbfbdd 100644 --- a/documentation/user/en/use/api/example/evita-query-example.graphql +++ b/documentation/user/en/use/api/example/evita-query-example.graphql @@ -52,7 +52,6 @@ max overallCount buckets(requestedCount: 30) { - index threshold occurrences } diff --git a/documentation/user/en/use/api/example/evita-query-example.rest b/documentation/user/en/use/api/example/evita-query-example.rest index 3534bc0a1..f60f449a1 100644 --- a/documentation/user/en/use/api/example/evita-query-example.rest +++ b/documentation/user/en/use/api/example/evita-query-example.rest @@ -29,6 +29,9 @@ POST /rest/evita/Product/query "statisticsDepth": "IMPACT" }, "priceType": "WITH_TAX", - "priceHistogram": 30 + "priceHistogram": { + "requestedBucketCount" : 30, + "behavior" : "STANDARD" + } } } \ No newline at end of file diff --git a/documentation/user/en/use/api/example/graphql-full-query-example.graphql b/documentation/user/en/use/api/example/graphql-full-query-example.graphql index 2095aa195..de6d308d6 100644 --- a/documentation/user/en/use/api/example/graphql-full-query-example.graphql +++ b/documentation/user/en/use/api/example/graphql-full-query-example.graphql @@ -61,7 +61,6 @@ max overallCount buckets(requestedCount: 30) { - index threshold occurrences } diff --git a/documentation/user/en/use/api/example/rest-full-query-example.rest b/documentation/user/en/use/api/example/rest-full-query-example.rest index 6cd0ded36..a8abd53ec 100644 --- a/documentation/user/en/use/api/example/rest-full-query-example.rest +++ b/documentation/user/en/use/api/example/rest-full-query-example.rest @@ -31,6 +31,9 @@ POST /rest/evita/Product/query "facetSummary": { "statisticsDepth": "COUNTS" }, - "priceHistogram": 30 + "priceHistogram": { + "requestedBucketCount" : 30, + "behavior" : "STANDARD" + } } } \ No newline at end of file diff --git a/documentation/user/en/use/api/query-data.md b/documentation/user/en/use/api/query-data.md index 8783c4d94..89b79b7aa 100644 --- a/documentation/user/en/use/api/query-data.md +++ b/documentation/user/en/use/api/query-data.md @@ -9,7 +9,7 @@ proofreading: 'done' preferredLang: 'java' --- -The [query in evitaDB](../query/basics.md) is represented by a tree of nested "constraints" divided into four _logical_ parts: +The [query in evitaDB](../query/basics.md) is represented by a tree of nested "constraints" divided into four _logical_ parts:
`collection`
@@ -24,24 +24,24 @@ The [query in evitaDB](../query/basics.md) is represented by a tree of nested "c performed on them
- + The *evitaQL* (evitaDB Query Language) entry point is represented by -evita_query/src/main/java/io/evitadb/api/query/Query.javaEvitaDB.Client/Queries/Query.cs class, and looks like this +evita_query/src/main/java/io/evitadb/api/query/Query.javaEvitaDB.Client/Queries/Query.cs class, and looks like this a [Lisp flavored language](https://en.wikipedia.org/wiki/Lisp_(programming_language)). It always starts with the name of the constraint, followed by a set of arguments in parentheses. You can even use other functions in those arguments. An example of such a query might look like this: - - + + The *evitaQL* (evitaDB Query Language) is represented by JSON object of nested constraints. Each nested property always starts with name of the constraint followed by a set of arguments as property value. You can even use other constraints in those arguments. An example of such a query might look like this: - + - + [EvitaQL example](/documentation/user/en/use/api/example/evita-query-example.java) @@ -56,14 +56,14 @@ constraints in those arguments. An example of such a query might look like this: > *calculated with an impact analysis of how the result would look if the user selected some other parameters in* > *addition to the two selected ones.* - + evitaQL is represented by a simple [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) which is parsed to an abstract syntax tree consisting of constraints (evita_query/src/main/java/io/evitadb/api/query/Constraint.java) encapsulated in evita_query/src/main/java/io/evitadb/api/query/Query.java object. - + We have designed the *evitaQL* string representation to look similar to a query defined directly in the *Java* language. We also try to preserve the "look & feel" of the original evitaQL in different languages / APIs like REST, GraphQL or C# @@ -73,7 +73,7 @@ evitaQL is used in the gRPC protocol and can optionally be used for the embedded in [evitaDB console](/documentation/blog/en/09-our-new-web-client-evitalab). The GraphQL and REST Web API use a similar format, but adapted to the protocol conventions (so that we can take advantage of the Open API / GQL schema). - + ## Defining queries in Java code @@ -90,7 +90,7 @@ This is an example of how the query is composed and how evitaDB is called. The e evita_query/src/main/java/io/evitadb/api/query/Query.java and evita_query/src/main/java/io/evitadb/api/query/QueryConstraints.java. - + [Java query example](/documentation/user/en/use/api/example/java-query-example.java) @@ -99,7 +99,7 @@ This is an example of how the query is composed and how evitaDB is called. The e The query may also contain "dirty" parts - that is, null constraints and unnecessary parts: - + [Java dirty query example](/documentation/user/en/use/api/example/java-dirty-query-example.java) @@ -145,7 +145,7 @@ represented by the evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityReferenceContract.java interface. - + [Default query example](/documentation/user/en/use/api/example/default-query-example.java) @@ -163,7 +163,7 @@ When such a require constraint is used, data will be fetched *greedily* during t will then contain entities in the form of evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.java. - + [Fetching example](/documentation/user/en/use/api/example/fetching-example.java) @@ -179,7 +179,7 @@ Although there are simpler variants for querying entities, the typical method is The next example documents fetching the second page of products in a category with calculated facet statistics: - + [Fetching example](/documentation/user/en/use/api/example/query-example.java) @@ -200,7 +200,7 @@ To enrich, a.k.a. lazy fetch missing data to an existing entity, you must pass t method and specify a set of additional require constraints that should be satisfied. Due to immutability properties enforced by database design, enriching an entity object returns a new instance of the entity. - + [Lazy loading example](/documentation/user/en/use/api/example/lazy-fetch-example.java) @@ -488,9 +488,9 @@ invalidation. You'd have to query only the entity references that contain versio that are not in the cache with a separate request. So instead of one network request, you have to make two. The benefit of the local cache is therefore somewhat questionable. - + - + ## Defining queries in C# code @@ -505,7 +505,7 @@ This is an example of how the query is composed and how evitaDB is called. The example imports previously mentioned interface EvitaDB.Client/Queries/IQueryConstraints.cs statically. - + [C# query example](/documentation/user/en/use/api/example/csharp-query-example.cs) @@ -514,7 +514,7 @@ The example imports previously mentioned interface The query may also contain "dirty" parts - that is, null constraints and unnecessary parts: - + [C# dirty query example](/documentation/user/en/use/api/example/csharp-dirty-query-example.cs) @@ -537,7 +537,7 @@ represented by the EvitaDB.Client/Models/Data/IEntityReference.cs interface. - + [Default query example](/documentation/user/en/use/api/example/default-query-example.cs) @@ -555,7 +555,7 @@ When such a `require` constraint is used, data will be fetched *greedily* during will then contain entities in the form of EvitaDB.Client/Models/Data/ISealedEntity.cs. - + [Fetching example](/documentation/user/en/use/api/example/fetching-example.cs) @@ -571,7 +571,7 @@ Although there are simpler variants for querying entities, the typical method is The next example documents fetching the second page of products in a category with calculated facet statistics: - + [Fetching example](/documentation/user/en/use/api/example/query-example.cs) @@ -592,7 +592,7 @@ To enrich, a.k.a. lazy fetch missing data to an existing entity, you must pass t method and specify a set of additional require constraints that should be satisfied. Due to immutability properties enforced by database design, enriching an entity object returns a new instance of the entity. - + [Lazy loading example](/documentation/user/en/use/api/example/lazy-fetch-example.cs) @@ -622,8 +622,8 @@ give you better latency. The problem is related to cache invalidation. You'd hav that contain version information and fetch the entities that are not in the cache with a separate request. So instead of one network request, you have to make two. The benefit of the local cache is therefore somewhat questionable. - - + + ## Defining queries in GraphQL API @@ -726,8 +726,8 @@ one query. [GraphQL full query example](/documentation/user/en/use/api/example/graphql-full-query-example.graphql) - - + + ## Defining queries in REST API @@ -806,4 +806,4 @@ one query. [REST full query example](/documentation/user/en/use/api/example/rest-full-query-example.rest)
- \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/api/schema-api.md b/documentation/user/en/use/api/schema-api.md index 920e788fb..1a5176b65 100644 --- a/documentation/user/en/use/api/schema-api.md +++ b/documentation/user/en/use/api/schema-api.md @@ -9,7 +9,7 @@ proofreading: 'done' preferredLang: 'java' --- - + ## Imperative schema definition @@ -122,9 +122,9 @@ the [Java Connector chapter](../connectors/java.md#custom-contracts). - + - + Unlike the Java approach, the GraphQL API supports only an imperative schema definition. The schema is defined using atomic mutations where each mutation adds, changes or removes a small part of the entire schema. To define an entire schema, @@ -161,9 +161,9 @@ or update the schema of a specific entity collection at the same URL using a Gra [Imperative collection schema definition via GraphQL API](/documentation/user/en/use/api/example/imperative-collection-schema-definition.graphql)
- + - + Unlike the Java approach, the REST API supports only an imperative schema definition. The schema is defined using atomic mutations where each mutation adds, changes or removes a small part of the entire schema. To define an entire schema, @@ -201,9 +201,9 @@ for the collection `Product` using a REST mutation of the selected collection li [Imperative collection schema definition via REST API](/documentation/user/en/use/api/example/imperative-collection-schema-definition.rest)
- + - + Unlike the Java approach, the C# client supports only an imperative schema definition. The schema is defined using builder pattern, that is provided by EvitaDB.Client/Models/Schemas/IEntitySchemaBuilder.cs interface. @@ -218,10 +218,10 @@ A schema can be programmatically defined this way: [Imperative schema definition via AP evitaDB API](/documentation/user/en/use/api/example/imperative-schema-definition.cs)
- + - + Unfortunately, it is currently not possible to define a schema using EvitaQL. This extension is also not planned to be implemented in the near future, because we believe that sufficient options (Java, GraphQL, REST API) are available for schema definition. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/api/write-data.md b/documentation/user/en/use/api/write-data.md index 522b0df36..86132acab 100644 --- a/documentation/user/en/use/api/write-data.md +++ b/documentation/user/en/use/api/write-data.md @@ -9,14 +9,14 @@ proofreading: 'done' preferredLang: 'java' --- - + Unfortunately, it is currently not possible to write data using EvitaQL. This extension is also not planned to be implemented in the near future, because we believe that sufficient options (Java, GraphQL, REST API, gRPC and C#) are available. - + - + ## Indexing modes @@ -29,15 +29,15 @@ day, but let's be honest - we're not there yet. This reasoning led us to design two different types of [entity data](../data-model.md) ingestion and corresponding catalog states: -- [bulk indexing](#bulk-indexing), state: `WARMUP``Warmup` -- [incremental indexing](#incremental-indexing), state: `ALIVE``Alive` +- [bulk indexing](#bulk-indexing), state: `WARMUP``Warmup` +- [incremental indexing](#incremental-indexing), state: `ALIVE``Alive` ### Bulk indexing Bulk indexing is used to quickly index large amounts of source data. It's used for initial catalog creation from external (primary) data stores. It doesn't need to support transactions and allows only a single session (single thread) -to be opened from the client side. The catalog is in a so-called `WARMUP``Warmup` state -(evita_api/src/main/java/io/evitadb/api/CatalogState.javaEvitaDB.Client/Session/CatalogState.cs). +to be opened from the client side. The catalog is in a so-called `WARMUP``Warmup` state +(evita_api/src/main/java/io/evitadb/api/CatalogState.javaEvitaDB.Client/Session/CatalogState.cs). The client can both write and query the written data, but no other client can open another session because the consistency of the data could not be guaranteed for them. The goal here is to index hundreds or thousands of entities per second. @@ -46,11 +46,11 @@ If the database crashes during this initial bulk indexing, the state and consist corrupted, and the entire catalog should be dumped and rebuilt from scratch. Since there is no client other than the one writing the data, we can afford to do this. - + - + -Any newly created catalog starts in `WARMUP``Warmup` +Any newly created catalog starts in `WARMUP``Warmup` state and must be manually switched to *transactional* mode by executing: @@ -58,17 +58,17 @@ state and must be manually switched to *transactional* mode by executing: [Termination of warm-up mode](/documentation/user/en/use/api/example/finalization-of-warmup-mode.java) -The `goLiveAndClose``GoLiveAndClose` -method sets the catalog to `ALIVE``Alive` +The `goLiveAndClose``GoLiveAndClose` +method sets the catalog to `ALIVE``Alive` (transactional) state and closes the current session. From this moment on, multiple clients can open read-only or read-write sessions in parallel to this particular catalog. - - + + Any newly created catalog starts in `WARMUP` state and must be manually switched to *transactional* mode using the -[system API](/documentation/user/en/use/connectors/graphql.md#graphql-api-instances) -[system API](/documentation/user/en/use/connectors/rest.md#rest-api-instances) +[system API](/documentation/user/en/use/connectors/graphql.md#graphql-api-instances) +[system API](/documentation/user/en/use/connectors/rest.md#rest-api-instances) by executing: @@ -76,13 +76,13 @@ by executing: [Termination of warm-up mode](/documentation/user/en/use/api/example/finalization-of-warmup-mode.graphql) -The `switchCatalogToAliveState` mutation`/catalogs/{catalog-name}` endpoint with `PATCH` method +The `switchCatalogToAliveState` mutation`/catalogs/{catalog-name}` endpoint with `PATCH` method sets the catalog to `ALIVE` (transactional) state. From this moment on, multiple clients can send queries or mutations requests in parallel to this particular catalog. - + - + ### Incremental indexing @@ -92,8 +92,8 @@ the primary data store. One of the more interesting recent developments in this [the Debezium project](https://debezium.io/), which allows changes from primary data stores to be streamed to secondary indexes fairly easily. -There might be multiple clients reading & writing data to the same catalog when it is in `ALIVE` -`Alive` state. Each catalog +There might be multiple clients reading & writing data to the same catalog when it is in `ALIVE` +`Alive` state. Each catalog update is wrapped into a *transaction* that meets [the snapshot isolation level](https://en.wikipedia.org/wiki/Snapshot_isolation). More details about transaction handling is in [separate chapter](../../deep-dive/transactions.md). @@ -108,9 +108,9 @@ All model classes are **designed to be immutable**. The reason for this is simpl concurrent access (in other words, entities can be cached without fear of race conditions), and easy identity checking (where only the primary key and version are needed to claim that two data objects of the same type are identical). - + - + All model classes are described by interfaces, and there should be no reason to use or instantiate direct classes. Interfaces follow this structure: @@ -133,60 +133,60 @@ to the entity and then store the entity to the database:
When you read existing entity from the catalog, you obtain read-only -evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.javaEvitaDB.Client/Models/Data/ISealedEntity.cs, which is +evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.javaEvitaDB.Client/Models/Data/ISealedEntity.cs, which is basically a contract interface with a few methods allowing you to convert it to the builder instance that can be used for updating the data: - + [Retrieving existing entity returns a sealed entity](/documentation/user/en/use/api/example/update-existing-entity-shortened.java) - + - + - + -In the GraphQLREST API, +In the GraphQLREST API, the immutability is implicit by design. You may be able to modify the returned entity objects in your client application, but these changes cannot be propagated to the evitaDB server, so it is recommended to make your client model immutable as well (see the Java API for inspiration). The only way to modify the data is to use the -[catalog data API](/documentation/user/en/use/connectors/graphql.md#graphql-api-instances) -[catalog API](/documentation/user/en/use/connectors/rest.md#rest-api-instances) +[catalog data API](/documentation/user/en/use/connectors/graphql.md#graphql-api-instances) +[catalog API](/documentation/user/en/use/connectors/rest.md#rest-api-instances) and manually send evitaDB mutations with individual changes using one of the -`updateCollectionName` GraphQL mutations specific to -REST endpoints for modifying data of your selected [entity collection](/documentation/user/en/use/data-model.md#collection). +`updateCollectionName` GraphQL mutations specific to +REST endpoints for modifying data of your selected [entity collection](/documentation/user/en/use/data-model.md#collection). - + - + ### Versioning All model classes are versioned - in other words, when a model instance is modified, the version number of the new instance created from that modified state is incremented by one. - + - + -Version information is available not only at the evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.javaEvitaDB.Client/Models/Data/IEntity.cs level, +Version information is available not only at the evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.javaEvitaDB.Client/Models/Data/IEntity.cs level, but also at more granular levels (such as -evita_api/src/main/java/io/evitadb/api/requestResponse/data/AttributesContract.javaEvitaDB.Client/Models/Data/IAttributes.cs, -evita_api/src/main/java/io/evitadb/api/requestResponse/data/ReferenceContract.javaEvitaDB.Client/Models/Data/IReference.cs, or -evita_api/src/main/java/io/evitadb/api/requestResponse/data/AssociatedDataContract.javaEvitaDB.Client/Models/Data/IAssociatedData.cs). -All model classes that support versioning implement the evita_api/src/main/java/io/evitadb/api/requestResponse/data/Versioned.javaEvitaDB.Client/Models/Data/IVersioned.cs interface. +evita_api/src/main/java/io/evitadb/api/requestResponse/data/AttributesContract.javaEvitaDB.Client/Models/Data/IAttributes.cs, +evita_api/src/main/java/io/evitadb/api/requestResponse/data/ReferenceContract.javaEvitaDB.Client/Models/Data/IReference.cs, or +evita_api/src/main/java/io/evitadb/api/requestResponse/data/AssociatedDataContract.javaEvitaDB.Client/Models/Data/IAssociatedData.cs). +All model classes that support versioning implement the evita_api/src/main/java/io/evitadb/api/requestResponse/data/Versioned.javaEvitaDB.Client/Models/Data/IVersioned.cs interface. - + - + Version information is available at the entity level. - + - + The version information serves two purposes: @@ -196,9 +196,9 @@ The version information serves two purposes: 2. **optimistic locking:** if there is a concurrent update of the same entity, we could automatically resolve the conflict, provided that the changes themselves do not overlap. - + - + Since the entity is *immutable* and *versioned* the default implementation of the `hashCode` and `equals` takes these @@ -208,25 +208,25 @@ three components into account: 2. primary key 3. version -If you need a thorough comparison that compares all model data, you must use the `differsFrom``DiffersFrom` method defined in the -evita_api/src/main/java/io/evitadb/api/requestResponse/data/ContentComparator.javaEvitaDB.Client/Models/Data/IContentComparator.cs +If you need a thorough comparison that compares all model data, you must use the `differsFrom``DiffersFrom` method defined in the +evita_api/src/main/java/io/evitadb/api/requestResponse/data/ContentComparator.javaEvitaDB.Client/Models/Data/IContentComparator.cs interface and implemented by the -evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.javaEvitaDB.Client/Models/Data/IEntity.cs. +evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.javaEvitaDB.Client/Models/Data/IEntity.cs. - + - + ## Session & transaction - + - + The communication with the evitaDB instance always takes place via the -evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs interface. +evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs interface. Session is a single-threaded communication channel identified by a unique [random UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier). @@ -238,7 +238,7 @@ To conserve resources, the server automatically closes sessions after a period o The interval is set by default to `60 seconds` but [it can be changed](https://evitadb.io/documentation/operate/configure#server-configuration) to different value. The inactivity means that there is no activity recorded on the -evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs interface. If you need +evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs interface. If you need to artificially keep session alive you need to periodically call some method without side-effects on the session interface, such as: @@ -249,13 +249,13 @@ interface, such as:
In case of remote use of evitaDB. In this case we really need to call some method that triggers the network communication. Many methods in - evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs + evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.javaEvitaDB.Client/EvitaClientSession.cs return only locally cached results to avoid expensive and unnecessary network calls.
-evita_api/src/main/java/io/evitadb/api/TransactionContract.javaEvitaDB.Client/EvitaClientTransaction.cs is an envelope for a "unit +evita_api/src/main/java/io/evitadb/api/TransactionContract.javaEvitaDB.Client/EvitaClientTransaction.cs is an envelope for a "unit of work" with evitaDB. A transaction exists within a session and is guaranteed to have [the snapshot isolation level](https://en.wikipedia.org/wiki/Snapshot_isolation) for reads. The changes in a transaction are always isolated from other transactions and become visible only after the transaction has been @@ -263,27 +263,27 @@ committed. If the transaction is marked as *rollback only*, all changes will be will never reach the shared database state. There can be at most one active transaction in a session, but there can be multiple successor transactions during the session's lifetime. -
+ - + -The communication with the evitaDB instance using the GraphQLREST -API always uses some kind of session. In the case of the GraphQLREST API, +The communication with the evitaDB instance using the GraphQLREST +API always uses some kind of session. In the case of the GraphQLREST API, a session is a per-request communication channel that is used in the background. A transaction is an envelope for a "unit of work" with evitaDB. -In the GraphQLREST API, -a transaction exists for the duration of a session, or more precisely a GraphQLREST +In the GraphQLREST API, +a transaction exists for the duration of a session, or more precisely a GraphQLREST API request, and it is guaranteed to have [the snapshot isolation level](https://en.wikipedia.org/wiki/Snapshot_isolation) for reads. The changes in a transaction are always isolated from other transactions and become visible only after the transaction has been -committed, i.e. the request to the GraphQLREST -API has been processed and was successful. If a GraphQLREST +committed, i.e. the request to the GraphQLREST +API has been processed and was successful. If a GraphQLREST API request results in any kind of error, the transaction is automatically rolled back. - + - + Parallel transaction handling hasn't been finalized yet, and is scheduled to be finalized in @@ -296,20 +296,20 @@ sessions, but the writer must be only one. evitaDB recognizes two types of sessions: - + - +
read-only (default)
-
Read-only sessions are opened by calling the `queryCatalog``QueryCatalog` method. No write operations are allowed in a +
Read-only sessions are opened by calling the `queryCatalog``QueryCatalog` method. No write operations are allowed in a read-only session. This also allows evitaDB to optimize its behavior when working with the database.
read-write
-
Read-write sessions are opened by calling the `updateCatalog``UpdateCatalog` method
+
Read-write sessions are opened by calling the `updateCatalog``UpdateCatalog` method
-
- + +
read-only
@@ -321,8 +321,8 @@ evitaDB recognizes two types of sessions: and so on.
-
- + +
read-only
@@ -333,21 +333,21 @@ evitaDB recognizes two types of sessions:
Read-write sessions are opened by calling endpoints modify any data.
-
+ - + In the future, the read-only sessions can be distributed to multiple read nodes, while the read-write sessions must talk to the master node. - + - + #### Unsafe session lifecycle -We recommend to open sessions using `queryCatalog` / `updateCatalog` -`QueryCatalog` / `UpdateCatalog` methods that accept a lambda function to execute +We recommend to open sessions using `queryCatalog` / `updateCatalog` +`QueryCatalog` / `UpdateCatalog` methods that accept a lambda function to execute your business logic. This way evitaDB can safely handle the lifecycle management of *sessions* & *transactions*. This approach is not always acceptable - for example, if your application needs to be integrated into an existing framework that only provides a lifecycle callback methods, there is no way to "wrap" the entire business logic in @@ -365,10 +365,10 @@ If you use manual *session / transaction* handling, you must ensure that for eve a corresponding closing (even if an exception occurs during your business logic call). -Both evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java -EvitaDB.Client/EvitaClientSession.cs and -evita_api/src/main/java/io/evitadb/api/TransactionContract.java implement Java -`Autocloseable`EvitaDB.Client/EvitaClientTransaction.cs implement C# `IDisposable` +Both evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java +EvitaDB.Client/EvitaClientSession.cs and +evita_api/src/main/java/io/evitadb/api/TransactionContract.java implement Java +`Autocloseable`EvitaDB.Client/EvitaClientTransaction.cs implement C# `IDisposable` interface, so you can use them this way: @@ -376,8 +376,8 @@ interface, so you can use them this way: [Get advantage of Autocloseable behaviour](/documentation/user/en/use/api/example/autocloseable-transaction-management.java) -This approach is safe, but has the same disadvantage as using `queryCatalog` / `updateCatalog` -`QueryCatalog` / `UpdateCatalog` methods - you need to +This approach is safe, but has the same disadvantage as using `queryCatalog` / `updateCatalog` +`QueryCatalog` / `UpdateCatalog` methods - you need to have all the business logic executable within the same block. #### Dry-run session @@ -395,19 +395,19 @@ to set the rollback flag manually. This fact greatly simplifies implementing your tests, or can be useful if you want to ensure that the changes are not committed in a particular session, and you don't have easy access to the places where the transaction is opened. - + - + ### Upsert - + - + It's expected that most of the entity instances will be created by the evitaDB service classes - such as -evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java -EvitaDB.Client/EvitaClientSession.cs +evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java +EvitaDB.Client/EvitaClientSession.cs Anyway, there is also the [possibility of creating them directly](#creating-entities-in-detached-mode). Usually the entity creation will look like this: @@ -430,14 +430,14 @@ the builder wrapper), modify it, and finally collect the changes and send them t -The `upsertVia``UpsertVia` -method is a shortcut for calling `session.upsertEntity(builder.buildChangeSet())` -`session.UpsertEntity(builder.BuildChangeSet())`. If you look at the -evita_api/src/main/java/io/evitadb/api/requestResponse/data/BuilderContract.java -EvitaDB.Client/Models/Data/IBuilder.cs you'll +The `upsertVia``UpsertVia` +method is a shortcut for calling `session.upsertEntity(builder.buildChangeSet())` +`session.UpsertEntity(builder.BuildChangeSet())`. If you look at the +evita_api/src/main/java/io/evitadb/api/requestResponse/data/BuilderContract.java +EvitaDB.Client/Models/Data/IBuilder.cs you'll see, that you can call on it either: - +
`buildChangeSet`
@@ -448,8 +448,8 @@ see, that you can call on it either: from the server again, you'll see that none of the changes have been applied to the database entity.
-
- +
+
`BuildChangeSet`
@@ -460,11 +460,11 @@ see, that you can call on it either: from the server again, you'll see that none of the changes have been applied to the database entity.
-
+ - + evita_api/src/main/java/io/evitadb/api/requestResponse/data/mutation/EntityMutation.java or evita_api/src/main/java/io/evitadb/api/requestResponse/data/BuilderContract.java can be @@ -475,8 +475,8 @@ containing only entity type and (possibly assigned) primary key information. You method, which inserts or creates the entity and returns its body in the form and size you specify in your `require` argument. - - + + EvitaDB.Client/Models/Data/Mutations/IEntityMutation.cs or EvitaDB.Client/Models/Data/IBuilder.cs can be passed to EvitaDB.Client/EvitaClientSession.cs `Upsert` method, @@ -484,11 +484,11 @@ which returns EvitaDB.Client/Models/Data/Structure/EntityReference. containing only entity type and (possibly assigned) primary key information. You can also use the `UpsertAndFetchEntity` method, which inserts or creates the entity and returns its body in the form and size you specify in your `Require` argument. - + - + - + #### Creating entities in detached mode @@ -508,14 +508,14 @@ There is an analogous builder that takes an existing entity and tracks changes m [Detached existing entity example](/documentation/user/en/use/api/example/detached-existing-entity-instantiation.java)
- + - + -In the GraphQLREST API, +In the GraphQLREST API, there is no way to send full entity object to the server to be stored. Instead, you send a collection of mutations that add, change, or remove individual data from an entity (new or existing one). Similarly to how the schema -is defined in the GraphQLREST API. +is defined in the GraphQLREST API. @@ -527,13 +527,13 @@ is defined in the GraphQLGraphQLREST API +using the GraphQLREST API will create a library with e.g. entity builders that will generate the collection of mutations for the entity definition (see Java API for inspiration). - + You can create a new entity or update an existing one using the [catalog data API](/documentation/user/en/use/connectors/graphql.md#graphql-api-instances) at the `https://your-server:5555/gql/evita` URL. This API contains `upsertCollectionName` GraphQL mutations for each @@ -542,8 +542,8 @@ at the `https://your-server:5555/gql/evita` URL. This API contains `upsertCollec the changes to be applied to an entity. In one go, you can then retrieve the entity with the changes applied by defining return data. - - + + You can create a new entity or update an existing one using the [catalog API](/documentation/user/en/use/connectors/rest.md#rest-api-instances) at a collection endpoint, for example `https://your-server:5555/test/evita/product` with `PUT` HTTP method. @@ -551,14 +551,14 @@ There endpoints are customized to collections' [schemas](/documentation/user/en/ collection of evitaDB mutations which define the changes to be applied to an entity. In one go, you can then retrieve the entity with the changes applied by defining requirements. - + [Creating new entity example](/documentation/user/en/use/api/example/create-new-entity.graphql) -Because these GraphQL mutationsendpoints +Because these GraphQL mutationsendpoints are also for updating existing entities, evitaDB will automatically either create a new entity with specified mutations (and possibly a primary key) or update an existing one if a primary key of an existing entity is specified. You can further customize the behavior of the mutation by specifying the `entityExistence` @@ -569,84 +569,84 @@ argument. [Updating existing entity example](/documentation/user/en/use/api/example/update-existing-entity.graphql)
- + - + ### Removal - + - + The easiest way how to remove an entity is by its *primary key*. However, if you need to remove multiple entities at once you need to define a query that will match all the entities to remove: - - + + To remove one or multiple entities, you need to define a query that will match all the entities to remove: - + - + - + [Removing all entities which name starts with `A`](/documentation/user/en/use/api/example/delete-entities-by-query.java) - + - + -The `deleteEntities``DeleteEntities` method returns the count of removed entities. -If you want to return bodies of deleted entities, you can use alternative method `deleteEntitiesAndReturnBodies``DeleteEntitiesAndReturnBodies`. +The `deleteEntities``DeleteEntities` method returns the count of removed entities. +If you want to return bodies of deleted entities, you can use alternative method `deleteEntitiesAndReturnBodies``DeleteEntitiesAndReturnBodies`. - + - + -The delete mutationBoth deletion endpoints +The delete mutationBoth deletion endpoints can return entity bodies, so you can define the return structure of data as you need as if you were fetching entities in usual way. - + - + evitaDB may not remove all entities matched by the filter part of the query. The removal of entities is subject to the -logic of the `require` conditions [`page` or `strip`](../../query/requirements/paging.md) -`Require` conditions [`Page` or `Strip`](../../query/requirements/paging.md) -pagination arguments [`offset` and `limit`](../../query/requirements/paging.md). -Even if you omit the these completely, implicit pagination (`page(1, 20)`) -(`Page(1, 20)`)(`offset: 1, limit: 20`) +logic of the `require` conditions [`page` or `strip`](../../query/requirements/paging.md) +`Require` conditions [`Page` or `Strip`](../../query/requirements/paging.md) +pagination arguments [`offset` and `limit`](../../query/requirements/paging.md). +Even if you omit the these completely, implicit pagination (`page(1, 20)`) +(`Page(1, 20)`)(`offset: 1, limit: 20`) will be used. If the number of entities removed is equal to the size of the defined paging, you should repeat the removal command. -Massive entity removal is better to execute in multiple transactional rounds rather than in one big transaction, i.e. multiple requests. +Massive entity removal is better to execute in multiple transactional rounds rather than in one big transaction, i.e. multiple requests. This is at least a good practice, because large and long-running transactions increase probability of conflicts that lead to rollbacks of other transactions. - + - + If you are removing a hierarchical entity, and you need to remove not only the entity itself, but its entire subtree, -you can take advantage of `deleteEntityAndItsHierarchy` -`DeleteEntityAndItsHierarchy` method. +you can take advantage of `deleteEntityAndItsHierarchy` +`DeleteEntityAndItsHierarchy` method. By default, the method returns the number of entities removed, but alternatively it can return the body of the removed root entity with the size and form you specify in -its `require``Require` argument. +its `require``Require` argument. If you remove only the root node without removing its children, the children will become [orphans](../schema.md#orphan-hierarchy-nodes), and you will need to reattach them to another existing parent. - + - + @@ -657,8 +657,8 @@ If you remove only the root node without removing its children, the children wil No data is actually removed once it is created and stored. If you remove the reference/attribute/whatever, it remains in the entity and is just marked as `dropped`. See the -evita_api/src/main/java/io/evitadb/api/requestResponse/data/Droppable.java -EvitaDB.Client/Models/Data/IDroppable.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/data/Droppable.java +EvitaDB.Client/Models/Data/IDroppable.cs interface implementations. There are a few reasons for this decision: @@ -670,9 +670,9 @@ There are a few reasons for this decision: - + - + ## Custom contracts @@ -857,4 +857,4 @@ the reference is automatically removed. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/api/write-tests.md b/documentation/user/en/use/api/write-tests.md index 0dbe22194..7831141ba 100644 --- a/documentation/user/en/use/api/write-tests.md +++ b/documentation/user/en/use/api/write-tests.md @@ -10,16 +10,16 @@ proofreading: 'done' preferredLang: 'java' --- - + The evitaQL language selection for this article makes no sense. - + - + Unfortunately, we don't have a support written for a C# client, yet. Want to [contribute](https://github.com/FgForrest/evitaDB)? - + - +

Terms used in this document

@@ -101,9 +101,9 @@ the test method implementation to query and assert the results of the data in th ### Test web APIs -
+ - + A similar approach is possible with the evitaDB Java Client through gRPC API. When setting up your dataset, simply declare that you also want to initialize the gRPC web server and open required set of web APIs: @@ -126,9 +126,9 @@ instance that is properly configured to communicate with this gRPC API, the clie certificate to pass [mTLS verification](../../operate/tls.md#default-mtls-behaviour-not-secure), and communicates with the *embedded evitaDB* over the wire. - + - + A similar approach is possible with the evitaDB GraphQL API. When setting up your dataset, simply declare that you also want to initialize the GraphQL web server and open required web API: @@ -153,9 +153,9 @@ just a wrapper around the [REST-assured](https://rest-assured.io/) library to pr builder specific to our GraphQL API. However, after the `.executeAndThen()` method is called, the request is sent, and you can use assertion methods provided directly by the [REST-assured](https://github.com/rest-assured/rest-assured/wiki/Usage#verifying-response-data) library. - + - + A similar approach is possible with the evitaDB REST API. When setting up your dataset, simply declare that you also want to initialize the REST web server and open required web API: @@ -180,9 +180,9 @@ just a wrapper around the [REST-assured](https://rest-assured.io/) library to pr builder specific to our REST API. However, after the `.executeAndThen()` method is called, the request is sent, and you can use assertion methods provided directly by the [REST-assured](https://github.com/rest-assured/rest-assured/wiki/Usage#verifying-response-data) library. - + - + ### Init shared data objects @@ -331,9 +331,9 @@ The annotation is expected to be placed on the `@Test` method or an argument of - + - + Besides the standard [autowired arguments](#annotations-reference) you can also inject evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java @@ -341,9 +341,9 @@ to any of the defined arguments. The client will open a gRPC connection to the w evita_server/src/main/java/io/evitadb/server/EvitaServer.java and you can start communicating with the server over the network even if the server is running locally as an embedded database. - + - + Besides the standard [autowired arguments](#annotations-reference) you can also inject evita_test_support/src/main/java/io/evitadb/test/tester/GraphQLTester.java @@ -351,9 +351,9 @@ to any of the defined arguments. The tester will open a GraphQL connection to th evita_server/src/main/java/io/evitadb/server/EvitaServer.java and you can start communicating with the server over the network even if the server is running locally as an embedded database. - + - + Besides the standard [autowired arguments](#annotations-reference) you can also inject evita_test_support/src/main/java/io/evitadb/test/tester/RestTester.java @@ -361,9 +361,9 @@ to any of the defined arguments. The tester will open a REST connection to the w evita_server/src/main/java/io/evitadb/server/EvitaServer.java and you can start communicating with the server over the network even if the server is running locally as an embedded database. - + - + ### @OnDataSetTearDown @@ -378,4 +378,4 @@ you'd need a special cleanup procedure for your shared objects, and you might ap
Defines name of the associated dataset.
-
\ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/connectors/c-sharp.md b/documentation/user/en/use/connectors/c-sharp.md index 0755eb05a..495efc6bc 100644 --- a/documentation/user/en/use/connectors/c-sharp.md +++ b/documentation/user/en/use/connectors/c-sharp.md @@ -10,13 +10,13 @@ author: 'Ing. Tomáš Pozler' preferredLang: 'cs' --- - -This chapter describes the C# driver for evitaDB and doesn't make sense for other languages. If you're interested in + +This chapter describes the C# driver for evitaDB and doesn't make sense for other languages. If you're interested in the details of the C# implementation, please change your preferred language in the upper right corner. - - + + This API unification was possible thanks to the common [gRPC](grpc.md) protocol and protobuf data format used by both clients. -It is built on top of the same interfaces (especially evita_api/src/main/java/io/evitadb/api/EvitaContract.java +It is built on top of the same interfaces (especially evita_api/src/main/java/io/evitadb/api/EvitaContract.java and evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java) for the client and the database itself, where on the C# side, there has been only an adaptation without the need of these specific interfaces - classes were used instead. @@ -44,12 +44,12 @@ Install-Package EvitaDB.Client -As you may notice, install commands lack the version specification. This is because the client is currently meant to be -always compatible with the latest version of the server in [master branch](https://github.com/FgForrest/evitaDB/tree/master) +As you may notice, install commands lack the version specification. This is because the client is currently meant to be +always compatible with the latest version of the server in [master branch](https://github.com/FgForrest/evitaDB/tree/master) which corresponds with latest evitaDB [docker image](https://hub.docker.com/r/evitadb/evitadb). This may change in the future. *Suggestions to use* -- in the most cases, you should be specifying `using` keyword when initializing EvitaDB.Client/EvitaClient.cs and EvitaDB.Client/EvitaClientSession.cs to take advantage of their `IDisposable` implementation for automatic resource release +- in the most cases, you should be specifying `using` keyword when initializing EvitaDB.Client/EvitaClient.cs and EvitaDB.Client/EvitaClientSession.cs to take advantage of their `IDisposable` implementation for automatic resource release - when working with queries, you should statically use `IQueryConstrains` interface for more compact and readable queries ## Notes @@ -64,7 +64,7 @@ to existing catalog. The EvitaDB.Client/EvitaClient.cs -keeps a pool of opened resources and should be terminated by a `Close()` method when you stop using it. +keeps a pool of opened resources and should be terminated by a `Close()` method when you stop using it. ### TLS configuration @@ -92,7 +92,7 @@ configuration on the client side: If `mTLS` is enabled on the server side and `UseGeneratedCertificate` is set to `false`, you must provide your -manually generated certificate in settings `CertificatePath` and `CertificateKeyPath`, otherwise the verification +manually generated certificate in settings `CertificatePath` and `CertificateKeyPath`, otherwise the verification process will fail and the connection will not be established. @@ -125,4 +125,4 @@ The above intervals are not currently configurable because we believe they are o to change them, please contact us with your specific use case and we will consider adding the configuration option. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/connectors/graphql.md b/documentation/user/en/use/connectors/graphql.md index 6942953f8..ba4774504 100644 --- a/documentation/user/en/use/connectors/graphql.md +++ b/documentation/user/en/use/connectors/graphql.md @@ -10,11 +10,11 @@ author: 'Lukáš Hornych' preferredLang: 'graphql' --- - -This chapter describes the GraphQL protocol for evitaDB and doesn't make sense for other languages. If you're interested + +This chapter describes the GraphQL protocol for evitaDB and doesn't make sense for other languages. If you're interested in the details of the GraphQL implementation, please change your preferred language in the upper right corner. - - + + The [GraphQL](https://graphql.org/) API has been developed to allow users to easily query domain-specific data from evitaDB with a high degree of customisation of the queries and the self-documentation that GraphQL APIs provide. @@ -195,4 +195,4 @@ Altair has, like many others, has a code-completion in its editor based on the r You can find all the available libraries on the [official GraphQL website](https://graphql.org/code/#language-support) for you to choose from for your own client language. Some can even generate classes/types based on the API schema for you to use in your codebase. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/connectors/grpc.md b/documentation/user/en/use/connectors/grpc.md index 85e5d3ce4..7d5715af1 100644 --- a/documentation/user/en/use/connectors/grpc.md +++ b/documentation/user/en/use/connectors/grpc.md @@ -1,67 +1,67 @@ --- title: gRPC perex: | - The gRPC API was designed to provide a very powerful and unified way to control the evitaDB database from different + The gRPC API was designed to provide a very powerful and unified way to control the evitaDB database from different programming languages, using the existing evitaDB Java API. date: '26.7.2023' author: 'Ing. Tomáš Pozler' preferredLang: 'java' --- - -This chapter describes the gRPC protocol for evitaDB and relates only to Java or C# drivers. If you're interested + +This chapter describes the gRPC protocol for evitaDB and relates only to Java or C# drivers. If you're interested in the details of the gRPC implementation, please change your preferred language in the upper right corner. - - + + The main idea behind the design was to define a universal communication protocol that follows design of [Java API](https://github.com/FgForrest/evitaDB/tree/dev/evita_api/src/main/java/io/evitadb/api). Unlike [REST](rest.md) and [GraphQL](graphql.md), this API is not intended for direct use by end users / developers, but primarily as a building block for evitaDB drivers or similar tools created for the database consumers. ## API structure -evitaDB is manipulated using the contracts exposed in [evita_api](https://github.com/FgForrest/evitaDB/tree/dev/evita_api/src/main/java/io/evitadb/api), -specifically the evita_api/src/main/java/io/evitadb/api/EvitaContract.java and +evitaDB is manipulated using the contracts exposed in [evita_api](https://github.com/FgForrest/evitaDB/tree/dev/evita_api/src/main/java/io/evitadb/api), +specifically the evita_api/src/main/java/io/evitadb/api/EvitaContract.java and evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java interfaces. -The proposed gRPC API aims to define its corresponding services with as little variation as possible, but in some cases -it was necessary to adapt the model to the capabilities of gRPC. In the design, it was not possible to model generics, -inheritance, or lambda functions directly, but these problems could have been avoided by adapting the defined models at -the cost of redundant information. +The proposed gRPC API aims to define its corresponding services with as little variation as possible, but in some cases +it was necessary to adapt the model to the capabilities of gRPC. In the design, it was not possible to model generics, +inheritance, or lambda functions directly, but these problems could have been avoided by adapting the defined models at +the cost of redundant information. It is also not possible to call methods on instances of objects located on the server, such as sessions, which are used -to perform most data manipulation and retrieval operations. However, these problems can be solved by implementing -a driver library with a rich API. The use of these methods on the session object has been replaced by the need -to specify the identifier of the user-created session, which must then be passed in the query metadata for all methods +to perform most data manipulation and retrieval operations. However, these problems can be solved by implementing +a driver library with a rich API. The use of these methods on the session object has been replaced by the need +to specify the identifier of the user-created session, which must then be passed in the query metadata for all methods based on the EvitaSessionContract interface. One way to simplify this process is to store the session ID in a shared memory scope (example class -evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/interceptor/ClientSessionInterceptor.java) +evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/interceptor/ClientSessionInterceptor.java) and set it to the metadata with every method call using a evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/interceptor/ClientSessionInterceptor.java. -In addition to `sessionId`, additional identifiers can be set in the metadata for [monitoring](../../operate/monitor.md) purposes. -Specifically, these are the `clientId` and `requestId` parameters, whose settings are used to add information about the -client that uses the database in a given instance (for example, it can be the name of the application using evitaDB) and -possibly an additional identifier for each query or method executed. Setting and using both of these parameters is +In addition to `sessionId`, additional identifiers can be set in the metadata for [monitoring](../../operate/monitor.md) purposes. +Specifically, these are the `clientId` and `requestId` parameters, whose settings are used to add information about the +client that uses the database in a given instance (for example, it can be the name of the application using evitaDB) and +possibly an additional identifier for each query or method executed. Setting and using both of these parameters is completely optional. gRPC works on the principle of Remote Method Calling (RPC), i.e. the client uses methods defined in protobuf services in -its code and their implementation is called on the server, where the request is processed and the response is sent back +its code and their implementation is called on the server, where the request is processed and the response is sent back to the client. For the above-mentioned contracts evita_api/src/main/java/io/evitadb/api/EvitaContract.java and evita_api/src/main/java/io/evitadb/api/EvitaSessionContract.java there are corresponding -services in the form of evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaService.java +services in the form of evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaService.java and evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaSessionService.java with the included methods supporting the same functionality as the base [Java API](https://github.com/FgForrest/evitaDB/tree/dev/evita_api/src/main/java/io/evitadb/api), but in a less convenient way due to the limitations of the gRPC protocol. ### Protocol buffers -Protocol buffers are a way to define the structure of data through messages using supported data types and structures. -They are not a replacement for JSON or XML formats used for data serialization, but rather a language-neutral and +Protocol buffers are a way to define the structure of data through messages using supported data types and structures. +They are not a replacement for JSON or XML formats used for data serialization, but rather a language-neutral and platform-neutral alternative. The main benefit of using protocol buffers is that they allow you to represent data in a structured way. Objects that match the defined message types can be serialized into a stream of bytes using the appropriate library. -When combined with the gRPC library, protocol buffers make the serialization process even more straightforward. You -don't need to directly manipulate protobuf files, and the gRPC library takes care of compiling protobuf files into +When combined with the gRPC library, protocol buffers make the serialization process even more straightforward. You +don't need to directly manipulate protobuf files, and the gRPC library takes care of compiling protobuf files into native classes and handling the serialization of objects automatically. All the *protobuf* files that define the gRPC protocol can be found [in a META-INF folder](https://github.com/FgForrest/evitaDB/tree/dev/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc). @@ -75,7 +75,7 @@ service EvitaSessionService { } ``` -together with the definition of the used input/output messages +together with the definition of the used input/output messages (except for the [Empty](https://protobuf.dev/reference/protobuf/google.protobuf/#empty) type, which comes from [the collection of standard message types](https://protobuf.dev/reference/protobuf/google.protobuf/) that are part of the protocol and are therefore included in the library): @@ -100,24 +100,24 @@ message GrpcQueryResponse { All protobuf files that define the gRPC API protocol should always be synchronised between client and server. -Although gRPC provides some mechanisms for backward compatibility, there is no guarantee that the client will be able to -communicate with the server if the protocol is not the same. Unchanged RPCs should work even if the protocol is not +Although gRPC provides some mechanisms for backward compatibility, there is no guarantee that the client will be able to +communicate with the server if the protocol is not the same. Unchanged RPCs should work even if the protocol is not the same, any changes or additions will not work. ## Querying the database -One of the design challenges was to find a way to represent database queries using protobuf capabilities. While it is -possible to define a message type that represents a query and pass the serialized query in a binary representation, we -decided to use the parameterized string form, where the parameters can be replaced by the `?` symbol, and a list of -parameters can be passed with such a query. An alternative is to use named parameters with the `@` prefix, which are -used with a unique name in the query and are also embedded in the map as keys, where each named parameter has -a corresponding value. This form is well known in the developer community and is used by many database drivers - namely +One of the design challenges was to find a way to represent database queries using protobuf capabilities. While it is +possible to define a message type that represents a query and pass the serialized query in a binary representation, we +decided to use the parameterized string form, where the parameters can be replaced by the `?` symbol, and a list of +parameters can be passed with such a query. An alternative is to use named parameters with the `@` prefix, which are +used with a unique name in the query and are also embedded in the map as keys, where each named parameter has +a corresponding value. This form is well known in the developer community and is used by many database drivers - namely in the form of JDBC statements, or [named queries](https://www.baeldung.com/spring-jdbc-jdbctemplate#2-queries-with-named-parameters) introduced by Spring framework. -In this form, the user submits the query to the server, which parses the string form and creates an object representing +In this form, the user submits the query to the server, which parses the string form and creates an object representing the requested query, ready for execution by the database. @@ -128,7 +128,7 @@ the requested query, ready for execution by the database. The example uses the `convertQueryParam` method from the evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/query/QueryConverter.java class. A similar method must be implemented in the gRPC client language to register input parameters of a specific gRPC data type for the query. -The primary purpose of evitaDB is to execute queries. However, as shown in the example above, working with the database +The primary purpose of evitaDB is to execute queries. However, as shown in the example above, working with the database in this way is not the most user-friendly experience. Unfortunately, there is currently no support for intellisense or query validation, and we haven't developed any IDE tools to address this limitation. @@ -147,50 +147,50 @@ original type-safe form: [Example of alternative gRPC query invocation](/documentation/user/en/use/connectors/examples/grpc-optimized-client-query-call.java) -However, this approach requires that the query language model be implemented in the target gRPC language, and this -requires a significant amount of effort. We always recommend using appropriate client drivers, if they are available for +However, this approach requires that the query language model be implemented in the target gRPC language, and this +requires a significant amount of effort. We always recommend using appropriate client drivers, if they are available for the target language, as this shifts the developer experience to a higher level. ## Recommended usage -To make the most of the gRPC API, we highly recommend using one of our implemented drivers or building your own tool to -facilitate querying. This will significantly improve your experience with evitaDB. Direct use of the gRPC API by +To make the most of the gRPC API, we highly recommend using one of our implemented drivers or building your own tool to +facilitate querying. This will significantly improve your experience with evitaDB. Direct use of the gRPC API by developers was not intended, and was designed to be more of a "machine-to-machine" interface. -When you start developing a driver for your preferred language, we recommend that you study the +When you start developing a driver for your preferred language, we recommend that you study the evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java driver, which has many things to inspire you for better performance, such as how to handle channel pooling or how to create and use schema caches. It is also important not to forget about TLS certificates, which need to be set up correctly on both the server and -the client side. gRPC communicates over HTTP/2 and data is sent over a TCP connection, and it is generally recommended +the client side. gRPC communicates over HTTP/2 and data is sent over a TCP connection, and it is generally recommended to use TLS to encrypt bidirectional communication. Our API enforces this, so it is recommended that you read the [instructions](../../operate/tls.md) regarding TLS and set it up on the server if necessary. -If you are considering developing a custom driver, we invite you to reach out to us for support and guidance throughout -the process. We are more than willing to provide the necessary feedback, recommendations, and assistance to ensure -the seamless functioning of your driver. Your success is important to us, and we are committed to working closely with +If you are considering developing a custom driver, we invite you to reach out to us for support and guidance throughout +the process. We are more than willing to provide the necessary feedback, recommendations, and assistance to ensure +the seamless functioning of your driver. Your success is important to us, and we are committed to working closely with you to make your driver integration with our API a successful and rewarding experience. Don't hesitate to contact us. We're here to help! ### Recommended tools -It's important to note that gRPC is designed to be used from any of the supported programming languages using +It's important to note that gRPC is designed to be used from any of the supported programming languages using protobuf-based generated classes, optionally with a friendly IDE that provides benefits such as intellisense, so using -it is pretty straightforward and there are a lot of resources and guides available on the web. +it is pretty straightforward and there are a lot of resources and guides available on the web. For testing purposes without writing code, i.e. trying out the available services and calling the procedures they provide, -it is possible to use classic API testing tools such as [Postman](https://www.postman.com/) or +it is possible to use classic API testing tools such as [Postman](https://www.postman.com/) or [Insomnia](https://insomnia.rest/), which already support communication with the gRPC API. -However, if you're new to gRPC, we recommend the [BloomRPC](https://github.com/bloomrpc/bloomrpc) tool, even though it's +However, if you're new to gRPC, we recommend the [BloomRPC](https://github.com/bloomrpc/bloomrpc) tool, even though it's deprecated, because it's more intuitive and dedicated to this technology. Alternatively, there are many great alternatives for testing gRPC APIs, which can be found [here](https://github.com/grpc-ecosystem/awesome-grpc). ### Recommended libraries You can find all the officially maintained libraries on the [gRPC](https://grpc.io) website, from which you can choose a library for -your own programming language. Along with a library, you also need to download a suitable protocol [compiler](https://grpc.io/docs/protoc-installation/), +your own programming language. Along with a library, you also need to download a suitable protocol [compiler](https://grpc.io/docs/protoc-installation/), which is not directly included in any of the libraries. It comes in the form of plugins, tools or completely separate libraries - it just depends on the language you are using. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/connectors/java.md b/documentation/user/en/use/connectors/java.md index 637720dff..861ba7c77 100644 --- a/documentation/user/en/use/connectors/java.md +++ b/documentation/user/en/use/connectors/java.md @@ -1,20 +1,20 @@ --- title: Java perex: | - The Java API is the native interface for communicating with evitaDB. It allows you to run evitaDB as an embedded - database or to connect to a remote database server. It is designed to share common interfaces for both scenarios, - allowing you to switch between embedded and remote without changing your code. This is particularly useful during - development or unit testing, when you can use the embedded database and switch to the remote database in production. + The Java API is the native interface for communicating with evitaDB. It allows you to run evitaDB as an embedded + database or to connect to a remote database server. It is designed to share common interfaces for both scenarios, + allowing you to switch between embedded and remote without changing your code. This is particularly useful during + development or unit testing, when you can use the embedded database and switch to the remote database in production. date: '26.10.2023' author: 'Ing. Jan Novotný' preferredLang: 'java' --- - -This chapter describes the Java driver for evitaDB and doesn't make sense for other languages. If you're interested + +This chapter describes the Java driver for evitaDB and doesn't make sense for other languages. If you're interested in the details of the Java driver implementation, please change your preferred language in the upper right corner. - - + + Starting evitaDB in embedded mode is described in detail in chapter [Run evitaDB](../../get-started/run-evitadb?lang=java). Connecting to a remote database instance is described in chapter [Connect to a remote database](../../get-started/query-our-dataset?lang=java). The same applies to [query API](../../use/api/query-data?lang=java) and [write API](../../use/api/write-data?lang=java). @@ -33,7 +33,7 @@ reached you need to call some method on it. The usual scenario would be [opening The evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java -keeps a pool of opened resources and should be terminated by a `close()` method when you stop using it. +keeps a pool of opened resources and should be terminated by a `close()` method when you stop using it. ### Configuration @@ -59,8 +59,8 @@ on the client side:

**Default: `gRPC client at hostname`**

- This property allows you to distinguish requests from this particular client from requests from other clients. - This information can be used in logs or in the [troubleshooting](../../use/api/troubleshoot.md) process. + This property allows you to distinguish requests from this particular client from requests from other clients. + This information can be used in logs or in the [troubleshooting](../../use/api/troubleshoot.md) process.

host
@@ -76,25 +76,25 @@ on the client side:
systemApiPort

**Default: `5557`**

-

Identification of the server port on which the evitaDB system API is running. The system API is used to - automatically set up the client certificate for mTLS or to download the server's self-signed certificate. - See [TLS Configuration and Principles](../../operate/tls.md). The system API is not required if the server uses - a trusted certificate and mTLS is disabled, or the server / client's private/public key pair is distributed +

Identification of the server port on which the evitaDB system API is running. The system API is used to + automatically set up the client certificate for mTLS or to download the server's self-signed certificate. + See [TLS Configuration and Principles](../../operate/tls.md). The system API is not required if the server uses + a trusted certificate and mTLS is disabled, or the server / client's private/public key pair is distributed "manually" with the client.

useGeneratedCertificate

**Default: `true`**

-

When set to `true`, the client automatically downloads the root certificate of the server CA from - the `system` endpoint. When set to `false`, the client expects the root certificate to be provided manually +

When set to `true`, the client automatically downloads the root certificate of the server CA from + the `system` endpoint. When set to `false`, the client expects the root certificate to be provided manually via the `rootCaCertificatePath` property.

trustCertificate

**Default: `false`**

When set to `true`, the certificate obtained from the `system` endpoint or manually through `certificatePath` - is automatically added to the local trust store. If set to `false` and an untrusted (self-signed) certificate is - provided, it will not be trusted by the client and the connection to the server will fail. Using `true` for this + is automatically added to the local trust store. If set to `false` and an untrusted (self-signed) certificate is + provided, it will not be trusted by the client and the connection to the server will fail. Using `true` for this setting in production is generally not recommended.

mtlsEnabled
@@ -112,41 +112,41 @@ on the client side:
rootCaCertificatePath

Relative path from `certificateFolderPath` to the root certificate of the server. If the `useGeneratedCertificate` - flag is off, it is necessary to set a path to the manually provided certificate, otherwise the verification + flag is off, it is necessary to set a path to the manually provided certificate, otherwise the verification process will fail and the connection will not be established.

certificateFileName
-

The relative path from `certificateFolderPath` to the client certificate. Must be configured if mTLS is +

The relative path from `certificateFolderPath` to the client certificate. Must be configured if mTLS is enabled and `useGeneratedCertificate` is set to `false`.

certificateKeyFileName
-

The relative path from `certificateFolderPath` to the client private key. Must be configured if mTLS is +

The relative path from `certificateFolderPath` to the client private key. Must be configured if mTLS is enabled and `useGeneratedCertificate` is set to `false`.

certificateKeyPassword
-

The password for the client's private key (if one is set). Must be configured if mTLS is enabled and +

The password for the client's private key (if one is set). Must be configured if mTLS is enabled and `useGeneratedCertificate` is set to `false`.

trustStorePassword

**Default: `trustStorePassword`**

-

The password for a trust store used to store server certificates. It is used when `trustCertificate` is set +

The password for a trust store used to store server certificates. It is used when `trustCertificate` is set to `true`.

reflectionLookupBehaviour

**Default: `CACHE`**

The behaviour of evita_common/src/main/java/io/evitadb/utils/ReflectionLookup.java - class analyzing classes for reflective information. Controls whether the once analyzed reflection information + class analyzing classes for reflective information. Controls whether the once analyzed reflection information should be cached or freshly (and costly) retrieved each time asked.

waitForClose

**Default: `5`**

-

Number of `waitForCloseUnit` client should wait for opened connection to terminate gracefully before killing +

Number of `waitForCloseUnit` client should wait for opened connection to terminate gracefully before killing them by force.

waitForCloseUnit
@@ -158,7 +158,7 @@ on the client side: If `mTLS` is enabled on the server side and `useGeneratedCertificate` is set to `false`, you must provide your -manually generated certificate in settings `certificatePath` and `certificateKeyPath`, otherwise the verification +manually generated certificate in settings `certificatePath` and `certificateKeyPath`, otherwise the verification process will fail and the connection will not be established. @@ -168,26 +168,26 @@ Both catalog and entity schemas are used quite often - every retrieved entity ha time, the schema is quite complex and doesn't change often. It is therefore beneficial to cache the schema on the client and avoid fetching it from the server every time it is needed. -The cache is handled by the evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaEntitySchemaCache.java +The cache is handled by the evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaEntitySchemaCache.java class which handles two schema access scenarios: #### Accessing last schema versions -The client maintains the last known schema versions for each catalog. This cache is invalidated each time a schema is -changed by that particular client, the collection is renamed or deleted, or the client fetches an entity that uses +The client maintains the last known schema versions for each catalog. This cache is invalidated each time a schema is +changed by that particular client, the collection is renamed or deleted, or the client fetches an entity that uses a schema version that is newer than the one cached as the last entity schema version. #### Accessing specific schema versions -The client also maintains a cache of specific schema versions. Each time a client fetches an entity, the entity returned -from the server side carries information about the schema version it refers to. The client tries to find the schema of +The client also maintains a cache of specific schema versions. Each time a client fetches an entity, the entity returned +from the server side carries information about the schema version it refers to. The client tries to find the schema of that particular version in its cache, and if it is not found, it fetches it from the server and caches it. The cache is invalidated once in a while (every minute) and the old schemas that have not been used for a long time (4 hours) are removed. -The above intervals are not currently configurable because we believe they are optimal for most use cases. If you need +The above intervals are not currently configurable because we believe they are optimal for most use cases. If you need to change them, please contact us with your specific use case and we will consider adding the configuration option. @@ -201,22 +201,22 @@ The Java API contains only two forms of the data model interfaces: 2. evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedEntity.java which represents a partial or complete form of the entity with its data -Both are valid and easy-to-use data structures, but neither speaks the language of your business domain. Developers +Both are valid and easy-to-use data structures, but neither speaks the language of your business domain. Developers generally prefer to work with their own domain objects, and we understand that. Their application would usually wrap the evitaDB model classes into their domain objects, which would require tedious manual work. -To make this process easier, we have created a custom contract API that allows you to define your own domain objects -and map them to evitaDB entities. Model objects can be used to define entity schemas as well as to read and write -entities from and to the database. Custom contracts use [ByteBuddy](https://bytebuddy.net/#/) and [Proxycian](https://github.com/FgForrest/Proxycian) -library to create dynamic proxies of your domain objects. There is a small performance overhead associated with this, -but it is negligible compared to the time spent on communication with the database. The API is optional and can be used +To make this process easier, we have created a custom contract API that allows you to define your own domain objects +and map them to evitaDB entities. Model objects can be used to define entity schemas as well as to read and write +entities from and to the database. Custom contracts use [ByteBuddy](https://bytebuddy.net/#/) and [Proxycian](https://github.com/FgForrest/Proxycian) +library to create dynamic proxies of your domain objects. There is a small performance overhead associated with this, +but it is negligible compared to the time spent on communication with the database. The API is optional and can be used in parallel to the standard API. ### Runtime requirements -The custom contracts API uses Java proxies under the hood which requires the [Proxycian](https://github.com/FgForrest/Proxycian) +The custom contracts API uses Java proxies under the hood which requires the [Proxycian](https://github.com/FgForrest/Proxycian) library to be present on classpath at runtime. Because the API is optional, we didn't want to bloat the evitaDB -JAR with the Proxycian library. However, when developer wants to use the custom contracts API, the Proxycian library +JAR with the Proxycian library. However, when developer wants to use the custom contracts API, the Proxycian library needs to be added as dependency: ```xml @@ -227,7 +227,7 @@ needs to be added as dependency: ``` -and also, if the application uses [Java Modules](https://www.oracle.com/corporate/features/understanding-java-9-modules.html), +and also, if the application uses [Java Modules](https://www.oracle.com/corporate/features/understanding-java-9-modules.html), the `--add-modules` parameter needs to be used ```shell @@ -274,9 +274,9 @@ Writing data using custom contracts is described in detail in the [write API cha ### Data modeling recommendations -You can define a single interface for both reading and writing data in evitaDB. However, it is recommended to separate -the read and write interfaces and to use different instances of the data objects for these purposes. In other words, -to follow similar principles that evitaDB is based on and uses itself. Although this may seem more complex in +You can define a single interface for both reading and writing data in evitaDB. However, it is recommended to separate +the read and write interfaces and to use different instances of the data objects for these purposes. In other words, +to follow similar principles that evitaDB is based on and uses itself. Although this may seem more complex in the beginning, it will pay off in the long run. The reasons behind this idea are: 1. the read instances remain immutable and can be safely shared between threads and cached in shared memory @@ -294,14 +294,14 @@ You define an interface or class with final fields that are initialized in the c
-As you can see, the interface looks exactly like the [example in the Schema API chapter](../../use/api/schema-api.md#declarative-schema-definition) -with the only difference that this version extends the evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedInstance.java -interface. The declaration signals that `` is the `Product` interface and `` is +As you can see, the interface looks exactly like the [example in the Schema API chapter](../../use/api/schema-api.md#declarative-schema-definition) +with the only difference that this version extends the evita_api/src/main/java/io/evitadb/api/requestResponse/data/SealedInstance.java +interface. The declaration signals that `` is the `Product` interface and `` is the `ProductEditor` interface. -We expect that the read interface will be used both to read your data and to define the schema structure. It's good +We expect that the read interface will be used both to read your data and to define the schema structure. It's good practice to keep the schema definition and the data access interface in the same place. @@ -316,7 +316,7 @@ Then you define a separate interface to modify the data:
-Note that this interface extends the `Product` interface and adds methods for modifying the data. It also extends +Note that this interface extends the `Product` interface and adds methods for modifying the data. It also extends the evita_api/src/main/java/io/evitadb/api/requestResponse/data/InstanceEditor.java interface and specifies that the `` is the `Product` interface. @@ -330,7 +330,7 @@ Now we can use the interfaces described above in the following way:
-The sealed/open principle is a bit more complex than the naive approach of using a single interface for both reading and -writing data, but it clearly separates the read and write scenarios, allowing you to maintain control over mutations and +The sealed/open principle is a bit more complex than the naive approach of using a single interface for both reading and +writing data, but it clearly separates the read and write scenarios, allowing you to maintain control over mutations and their visibility in a multi-threaded environment. - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/connectors/rest.md b/documentation/user/en/use/connectors/rest.md index acc7d69ff..85bf8d71d 100644 --- a/documentation/user/en/use/connectors/rest.md +++ b/documentation/user/en/use/connectors/rest.md @@ -10,11 +10,11 @@ author: 'Lukáš Hornych' preferredLang: 'rest' --- - -This chapter describes the REST protocol for evitaDB and doesn't make sense for other languages. If you're interested + +This chapter describes the REST protocol for evitaDB and doesn't make sense for other languages. If you're interested in the details of the REST implementation, please change your preferred language in the upper right corner. - - + + The [REST](https://restfulapi.net/) API with an [OpenAPI schema](https://swagger.io/specification/v3/) in evitaDB has been developed to allow users and developers to easily query domain-specific data from evitaDB via universal well-known API standard that REST APIs provide. @@ -132,4 +132,4 @@ which can even generate clients for your programming language. You can use any basic HTTP client your programming language supports. If you are looking for more, there are code generators that can generate whole typed client in your preferable language from the evitaDB's OpenAPI schemas. Official way of doing this is by using the [Swagger Codegen](https://swagger.io/tools/swagger-codegen/). - \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/data-model.md b/documentation/user/en/use/data-model.md index 38bd1b257..05be33568 100644 --- a/documentation/user/en/use/data-model.md +++ b/documentation/user/en/use/data-model.md @@ -87,30 +87,30 @@ Minimal entity definition consists of: Other entity data is purely optional and may not be used at all. The primary key can be set to `NULL` and let the database generate it automatically. - -This minimal entity structure is covered by interface -evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityReferenceContract.java -EvitaDB.Client/Models/Data/IEntityReference.cs. + +This minimal entity structure is covered by interface +evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityReferenceContract.java +EvitaDB.Client/Models/Data/IEntityReference.cs. Full entity with data, references, attributes and associated data is represented by interface -evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.java -EvitaDB.Client/Models/Data/IEntity.cs. - +evita_api/src/main/java/io/evitadb/api/requestResponse/data/EntityContract.java +EvitaDB.Client/Models/Data/IEntity.cs. + ### Entity type -Entity type must be a [String type](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) -[string type](https://learn.microsoft.com/en-us/dotnet/api/system.string). +Entity type must be a [String type](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) +[string type](https://learn.microsoft.com/en-us/dotnet/api/system.string). -Entity type is the main business key (equivalent to a *table name* in relational database) - all data of entities of +Entity type is the main business key (equivalent to a *table name* in relational database) - all data of entities of the same type is stored in a separate index. Within the entity type the entity is uniquely represented by [the primary key](#primary-key). ### Primary key -Primary key must be [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) -[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) positive -number (max. 263-1). It can be used for fast lookup of entity(s). Primary key must be unique +Primary key must be [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) +[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) positive +number (max. 263-1). It can be used for fast lookup of entity(s). Primary key must be unique within the same [entity type](#entity-type). It can be left `NULL` if it is to be generated automatically by the database. The primary key allows evitaDB to decide @@ -150,7 +150,7 @@ referred to by multiple child entities. A hierarchy always consists of entities Each entity must be part of at most one hierarchy (tree). - + @@ -162,8 +162,8 @@ Hierarchy definition is part of main entity schema: - - + + @@ -175,8 +175,8 @@ Hierarchy definition is part of main entity schema: - - + + @@ -185,15 +185,15 @@ Hierarchy definition is part of main entity schema. - - + + Hierarchy placement is represented by `parent` and `parentEntity` fields in entity object. Hierarchy definition is part of main entity schema. - + @@ -226,21 +226,21 @@ Attributes are also recommended to be used for frequently used data that accompa "perex", "main motive"), even if you don't necessarily need it for filtering/sorting purposes. evitaDB stores and fetches all attributes in a single block, so keeping this frequently used data in attributes reduces the overall I/O. - + The attribute provider ([entity](#entity-type) or [reference](#references)) is represented by the interface: -evita_api/src/main/java/io/evitadb/api/requestResponse/data/AttributesContract.java -EvitaDB.Client/Models/Data/IAttributes.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/data/AttributesContract.java +EvitaDB.Client/Models/Data/IAttributes.cs The attribute schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AttributeSchemaContract.java -EvitaDB.Client/Models/Schemas/IAttributeSchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AttributeSchemaContract.java +EvitaDB.Client/Models/Schemas/IAttributeSchema.cs - + More details about attributes are described in the [schema definition chapter](schema.md#attribute). @@ -254,8 +254,8 @@ that's why evitaDB provides special treatment for them. #### Data types in attributes Attributes allow using [variety of data types](data-types.md) and their arrays. The database supports all basic types, -date-time types and evita_common/src/main/java/io/evitadb/dataType/Range.java -EvitaDB.Client/DataTypes/Range.cs types. Range +date-time types and evita_common/src/main/java/io/evitadb/dataType/Range.java +EvitaDB.Client/DataTypes/Range.cs types. Range values are allowed using a special type of [query](../query/basics.md) filtering constraint - [`inRange`](../query/filtering/range.md). This filtering constraint allows to filter entities that are inside the range boundaries. @@ -293,19 +293,19 @@ The [search query](../query/basics.md) must contain specific Associated data are stored and fetched separately by their name and *locale* (if the associated data is [localized](#localized-associated-data)). - + AssociatedData provider ([entity](#entity-type)) is represented by the interface: -evita_api/src/main/java/io/evitadb/api/requestResponse/data/AssociatedDataContract.java -EvitaDB.Client/Models/Data/IAssociatedData.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/data/AssociatedDataContract.java +EvitaDB.Client/Models/Data/IAssociatedData.cs Associated data schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AssociatedDataSchemaContract.java -EvitaDB.Client/Models/Schemas/IAssociatedDataSchema.cs. +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AssociatedDataSchemaContract.java +EvitaDB.Client/Models/Schemas/IAssociatedDataSchema.cs. - + More details about associated data are described in the [schema definition chapter](schema.md#associated-data). @@ -321,21 +321,21 @@ The references, as the name suggests, refer to other entities (of the same or di allow entity filtering by the attributes defined on the reference relation or the attributes of the referenced entities. The references enable [statistics](../query/requirements/facet.md) computation if facet index is enabled for this referenced entity type. The reference is uniquely represented by -[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) -[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) +[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) +[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) positive number (max. 263-1) and -[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) -[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) +[String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) +[string](https://learn.microsoft.com/en-us/dotnet/api/system.string) entity type and may represent a facet that is part of one or more facet groups, also identified by -[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) -[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32). The reference identifier in an entity +[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) +[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32). The reference identifier in an entity is unique and belongs to a single group id. Among multiple entities, the reference to the same referenced entity may be part of different groups. The referenced entity type can refer to another entity managed by evitaDB, or it can refer to any external entity that -has a unique [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) -[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) key as its identifier. We +has a unique [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) +[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) key as its identifier. We expect that evitaDB will only partially manage data and that it will coexist with other systems in a runtime - such as content management systems, warehouse systems, ERPs and so on. @@ -343,21 +343,21 @@ The references may carry additional key-value data related to this entity relati the relationship to a stock). The data on references is subject to the same rules as [entity attributes](#attributes-unique-filterable-sortable-localized). - + -Reference is represented by the interface: -evita_api/src/main/java/io/evitadb/api/requestResponse/data/ReferenceContract.java -EvitaDB.Client/Models/Data/IReference.cs. +Reference is represented by the interface: +evita_api/src/main/java/io/evitadb/api/requestResponse/data/ReferenceContract.java +EvitaDB.Client/Models/Data/IReference.cs. Reference schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/ReferenceSchemaContract.java -EvitaDB.Client/Models/Schemas/IReferenceSchema.cs. +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/ReferenceSchemaContract.java +EvitaDB.Client/Models/Schemas/IReferenceSchema.cs. - + More details about references are described in the [schema definition chapter](schema.md#reference). @@ -372,8 +372,8 @@ The price has the following structure:
- [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `priceId` - [int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) `PriceId` + [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `priceId` + [int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) `PriceId`
Contains the identification of the price in the external systems. This ID is expected to be used for @@ -385,8 +385,8 @@ The price has the following structure: Entity B).
- [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) `priceList` - [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) `PriceList` + [String](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) `priceList` + [string](https://learn.microsoft.com/en-us/dotnet/api/system.string) `PriceList`
Contains the identification of the price list in the external system. Every price must refer to a price list. @@ -397,15 +397,15 @@ The price has the following structure: same price list.
- [Currency](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Currency.html) `currency` - [Currency](https://github.com/FgForrest/evitaDB-C-Sharp-client/blob/master/EvitaDB.Client/DataTypes/Currency.cs) `Currency` + [Currency](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Currency.html) `currency` + [Currency](https://github.com/FgForrest/evitaDB-C-Sharp-client/blob/master/EvitaDB.Client/DataTypes/Currency.cs) `Currency`
Identification of the currency. Three-letter form according to [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217).
- [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `innerRecordId` - [int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) `InnerRecordId` + [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `innerRecordId` + [int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) `InnerRecordId`
Some special products (such as master products or product sets) may contain prices of all "child" products so @@ -413,36 +413,36 @@ The price has the following structure: to distinguish the projected prices of the subordinate products in the product that represents them.
- [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `priceWithoutTax` - [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `PriceWithoutTax` + [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `priceWithoutTax` + [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `PriceWithoutTax`
Price without tax.
- [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `priceWithTax` - [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `PriceWithTax` + [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `priceWithTax` + [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `PriceWithTax`
Price with tax.
- [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `taxRate` - [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `TaxRate` + [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html) `taxRate` + [decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) `TaxRate`
Tax percentage (i.e. for 19% it'll be 19.00)
- [DateTimeRange](data-types.md#datetimerange) `validity` - `Validity` + [DateTimeRange](data-types.md#datetimerange) `validity` + `Validity`
Date and time interval for which the price is valid (inclusive).
- [boolean](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `sellable` - [bool](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool) `Sellable` + [boolean](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) `sellable` + [bool](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool) `Sellable`
Controls whether the price is subject to filtering/sorting logic, unindexed prices will be fetched along with @@ -452,24 +452,24 @@ The price has the following structure:
- + Price provider is represented by the interface: -evita_api/src/main/java/io/evitadb/api/requestResponse/data/PricesContract.java -EvitaDB.Client/Models/Data/IPrices.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/data/PricesContract.java +EvitaDB.Client/Models/Data/IPrices.cs Single price is represented by the interface: -evita_api/src/main/java/io/evitadb/api/requestResponse/data/PriceContract.java -EvitaDB.Client/Models/Data/IPrice.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/data/PriceContract.java +EvitaDB.Client/Models/Data/IPrice.cs Price schema is part of main entity schema: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EntitySchemaContract.java -EvitaDB.Client/Models/Schemas/IEntitySchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EntitySchemaContract.java +EvitaDB.Client/Models/Schemas/IEntitySchema.cs - + diff --git a/documentation/user/en/use/data-types.md b/documentation/user/en/use/data-types.md index fa00e6fdc..e740b9c34 100644 --- a/documentation/user/en/use/data-types.md +++ b/documentation/user/en/use/data-types.md @@ -22,7 +22,7 @@ There are two categories of data types: ## Simple data types - + evitaDB data types are limited to following list: @@ -71,8 +71,8 @@ evitaDB data types are limited to following list: - [Predecessor](#predecessor), formatted as `789` - - + + evitaDB data types are limited to following list: @@ -121,8 +121,8 @@ evitaDB data types are limited to following list: - [Predecessor](#predecessor), formatted as `789` - - + + The data types are based on the Java data types because that's how they are stored under the hood. The only difference is how they are formatted. evitaDB data types are limited to following list: @@ -172,9 +172,9 @@ is how they are formatted. evitaDB data types are limited to following list: - [Predecessor](#predecessor), formatted as `789` - + - + An array of a simple type is still a simple data type. All simple types can be wrapped in an array. You cannot mix arrays and non-array types in a single *attribute* / *associated data* schema. Once an *attribute* or *associated @@ -188,9 +188,9 @@ decisions are on your side, so think carefully which data type you choose and wh so that it requires a memory index. - + - + Application logic connected with evitaDB data types is located in @@ -198,9 +198,9 @@ Application logic connected with evitaDB data types is located in class. - + - + Application logic connected with evitaDB data types is located in @@ -208,20 +208,20 @@ Application logic connected with evitaDB data types is located in class. - + ### String - + The [string type](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html) is internally encoded with the character set [UTF-8](https://en.wikipedia.org/wiki/UTF-8). evitaDB query language and other I/O methods of evitaDB implicitly use this encoding. - - + + The [string type](https://learn.microsoft.com/en-us/dotnet/api/system.string) is internally encoded with the character set [UTF-8](https://en.wikipedia.org/wiki/UTF-8). evitaDB query language and other I/O methods of evitaDB implicitly use this encoding. - + - + ### Long @@ -239,11 +239,11 @@ are not precise enough for financial calculations. This is the same reason why B Even though the JSON format has its ways to ensure correct precision to some degree, we cannot guarantee that the client programming language parsing the number will use the correct data type that preserves the precision. - + ### Dates and times - + Although evitaDB supports *local* variants of the date time like [LocalDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/LocalDateTime.html), it's always converted to [OffsetDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/OffsetDateTime.html) @@ -251,29 +251,29 @@ using the evitaDB server system default timezone. You can control the default Ja [several ways](https://www.baeldung.com/java-jvm-time-zone). If your data is time zone specific, we recommend to work directly with the [OffsetDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/OffsetDateTime.html) on the client side and be explicit about the offset from the first day. - - + + Although evitaDB supports *local* variants of the date time like [DateTime](https://learn.microsoft.com/en-us/dotnet/api/system.datetime), it's always using the evitaDB server system default timezone. You can control the default Java timezone in [several ways](https://www.baeldung.com/java-jvm-time-zone). If your data is time zone specific, we recommend to work directly with the [DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset) on the client side and be explicit about the offset from the first day. - + - + ##### Why do we internally use OffsetDateTime for time information? - + - + ##### Why do we internally use DateTimeOffset for time information? - + Offset/time zone handling varies from database to database. We wanted to avoid setting the timezone in session or database configuration properties, as this mechanism is error-prone and impractical. Saving/loading date times with @@ -285,75 +285,75 @@ enough for our case - it identifies a globally valid time that is known at the t ### DateTimeRange - + The DateTimeRange represents a specific implementation of the evita_common/src/main/java/io/evitadb/dataType/Range.java defining from and to boundaries by the [OffsetDateTime](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/OffsetDateTime.html) data types. The offset date times are written in the ISO format. - - + + The DateTimeRange represents a specific implementation of the EvitaDB.Client/DataTypes/Range.cs defining from and to boundaries by the [DateTimeOffset](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset) data types. The offset date times are written in the ISO format. - + **Range is written as:** - when both boundaries are specified: - + ```plain [2021-01-01T00:00:00+01:00,2022-01-01T00:00:00+01:00] ``` - - + + ```json ["2021-01-01T00:00:00+01:00","2022-01-01T00:00:00+01:00"] ``` - + - when a left boundary (since) is specified: - + ```plain [2021-01-01T00:00:00+01:00,] ``` - - + + ```json ["2021-01-01T00:00:00+01:00",null] ``` - + - when a right boundary (until) is specified: - + ```plain [,2022-01-01T00:00:00+01:00] ``` - - + + ```json [null,"2022-01-01T00:00:00+01:00"] ``` - + ### NumberRange - + The NumberRange represents a specific implementation of the evita_common/src/main/java/io/evitadb/dataType/Range.java defining from and to boundaries by the [Number](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Number.html) @@ -361,8 +361,8 @@ data types. The supported number types are: Byte, Short, Integer, Long and BigDe Both boundaries of the number range must be of the same type - you cannot mix for example BigDecimal as lower bound and Byte as upper bound. - - + + The NumberRange represents a specific implementation of the EvitaDB.Client/DataTypes/Range.cs defining from and to boundaries by any of the supported @@ -370,64 +370,64 @@ data type. The supported number types are: byte, short, int, long and decimal. Both boundaries of the number range must be of the same type - you cannot mix for example decimal as lower bound and byte as upper bound. - + **Range is written as:** - when both boundaries are specified: - + ```plain [1,3.256] ``` - - + + ```json ["1","3.256"] ``` - + - when a left boundary (since) is specified: - + ```plain [1,] ``` - - + + ```json ["1",null] ``` - + - when a right boundary (until) is specified: - + ```plain [,3.256] ``` - - + + ```json [null,"3.256"] ``` - + ### Predecessor -The evita_common/src/main/java/io/evitadb/dataType/Predecessor.java -EvitaDB.Client/DataTypes/Predecessor.cs is a special data type +The evita_common/src/main/java/io/evitadb/dataType/Predecessor.java +EvitaDB.Client/DataTypes/Predecessor.cs is a special data type used to define a single oriented linked list of entities of the same type. It represents a pointer to a previous entity in the list. The head element is a special case and is represented by the constant `Predecessor#HEAD`. The predecessor attribute can only be used in the [attributes](data-model.md#attributes-unique-filterable-sortable-localised) of an @@ -460,7 +460,7 @@ concluded that the linked list is the least of all evils: - It doesn't require mass updates of surrounding entities or occasional "reshuffling". - it doesn't force the client logic to be complicated (and it plays well with the UI drag'n'drop repositioning flow) -- it is very data efficient - it only requires a single [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) +- it is very data efficient - it only requires a single [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) (4B) per single item in the list @@ -496,18 +496,18 @@ consistent for all other transactions. ## Complex data types - + The complex types are types that don't qualify as [simple evitaDB types](#simple-data-types) (or an array of simple evitaDB types). Complex types are stored in a -evita_common/src/main/java/io/evitadb/dataType/ComplexDataObject.java -EvitaDB.Client/DataTypes/ComplexDataObject.cs data structure that is +evita_common/src/main/java/io/evitadb/dataType/ComplexDataObject.java +EvitaDB.Client/DataTypes/ComplexDataObject.cs data structure that is intentionally similar to the JSON data structure so that it can be easily converted to JSON format and can also accept and store any valid JSON document. - + - + The complex types are all types that don't qualify as [simple evitaDB types](#simple-data-types) (or an array of simple evitaDB types). Complex types are written as JSON objects to allow any object structure with easy serialization and deserialization. @@ -516,9 +516,9 @@ supported by plain JSON. This means that you can store e.g. date time as a strin [simple data types](#simple-data-types), but internally, it will be stored as a plain string (because we don't have any information about the concrete data type), and it is up to you to do a manual conversion on the client side. - + - + The complex type in Java is a class that implements the serializable interface and does not belong to a `java` package or is not directly supported by the [simple data types](#simple-data-types)(i.e. `java.lang.URL` is forbidden to be @@ -526,8 +526,8 @@ stored in evitaDB, even if it is serializable and belongs to a `java` package, b the [simple data types](#simple-data-types)). The complex types are intended for the client POJO classes to carry larger data or to associate simple logic with the data. - - + + The complex type in C# is a record that does not belong among `built-in` C# types, and it is not directly supported by the [simple data types](#simple-data-types)(i.e. `System.Uri` is forbidden to be @@ -535,9 +535,9 @@ stored in evitaDB, even if it is serializable by design (implements ISerializabl `built-in` types, because it is not directly supported by the [simple data types](#simple-data-types)). The complex types are intended for the client POCO classes to carry larger data or to associate simple logic with the data. - + - + Associated data may even contain array of complex objects. Such data will be automatically converted to an array of @@ -553,8 +553,8 @@ Associated data may even contain array of complex objects. Such data will be aut - generic [Maps](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.html) - any array of [simple evitaDB types](#simple-data-types) or [complex types](#complex-data-types) - - + + Associated data may even contain array of complex objects. Such data will be automatically converted to an array of @@ -570,17 +570,17 @@ Associated data may even contain array of complex objects. Such data will be aut - generic [Dictionaries](https://learn.microsoft.com/cs-cz/dotnet/api/system.collections.idictionary) - any array of [simple evitaDB types](#simple-data-types) or [complex types](#complex-data-types) - - + + Associated data may even contain array of complex objects. Such data will be automatically converted to an array of `ComplexDataObject` types - i.e. `ComplexDataObjectArray`. - + - + ### Serialization @@ -624,9 +624,9 @@ The deserialization process may fail with two exceptions: - [InvalidCastException](https://learn.microsoft.com/en-us/dotnet/api/System.InvalidCastException) is raised when any of the serialized data was not deserialized due to a lack of a mutator method on the class it's being converted to - + - + ### Serialization @@ -830,4 +830,4 @@ public class ProductStockAvailability implements Serializable { ```
- \ No newline at end of file + \ No newline at end of file diff --git a/documentation/user/en/use/schema.md b/documentation/user/en/use/schema.md index 51783d57b..96b4d65de 100644 --- a/documentation/user/en/use/schema.md +++ b/documentation/user/en/use/schema.md @@ -61,7 +61,7 @@ the mutations directly or to write your own client driver. But you can open sour know about it! -All schema mutations implement interface evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/SchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/ISchemaMutation.cs +All schema mutations implement interface evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/SchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/ISchemaMutation.cs ## Structure @@ -90,11 +90,11 @@ Each named data object - [catalog](#catalog), [entity](#entity), [attribute](#at [associated data](#associated-data) and [reference](#reference) must be uniquely identifiable by its name within its parent scope. -The name validation logic and reserved words are present in the class evita_common/src/main/java/io/evitadb/utils/ClassifierUtils.javaEvitaDB.Client/Utils/ClassifierUtils.cs. +The name validation logic and reserved words are present in the class evita_common/src/main/java/io/evitadb/utils/ClassifierUtils.javaEvitaDB.Client/Utils/ClassifierUtils.cs. There is also a special property called `nameVariants` in the schema of each named object. It contains variants of the object name in different "developer" notations such as *camelCase*, *PascalCase*, *snake_case* and so on. See -evita_external_api/evita_external_api_core/src/main/java/io/evitadb/externalApi/api/catalog/schemaApi/model/NameVariantsDescriptor.javaEvitaDB.Client/Utils/NamingConvention.cs. +evita_external_api/evita_external_api_core/src/main/java/io/evitadb/externalApi/api/catalog/schemaApi/model/NameVariantsDescriptor.javaEvitaDB.Client/Utils/NamingConvention.cs. for a complete listing. @@ -108,21 +108,21 @@ for a complete listing. Top level mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/CreateCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/CreateCatalogSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/RemoveCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/RemoveCatalogSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/CreateCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/CreateCatalogSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/RemoveCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/RemoveCatalogSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaMutation.cs** Within `ModifyCatalogSchemaMutation` you can use mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaNameMutation.cs>** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaNameMutation.cs>** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyCatalogSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyCatalogSchemaDescriptionMutation.cs** And [entity top level mutations](#entity). - + The catalog schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/CatalogSchemaContract.javaEvitaDB.Client/Models/Schemas/ICatalogSchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/CatalogSchemaContract.javaEvitaDB.Client/Models/Schemas/ICatalogSchema.cs - + @@ -157,18 +157,18 @@ and thus share its complete definition. ##### List of mutations related to global attribute -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/CreateGlobalAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/CreateGlobalAttributeSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/UseGlobalAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/UseGlobalAttributeSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaGloballyUniqueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaGloballyUniqueMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/CreateGlobalAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/CreateGlobalAttributeSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/UseGlobalAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/UseGlobalAttributeSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaGloballyUniqueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaGloballyUniqueMutation.cs** And of course all [standard attribute mutations](#attributes). - + The global attribute schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/GlobalAttributeSchemaContract.java -EvitaDB.Client/Models/Schemas/IGlobalAttributeSchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/GlobalAttributeSchemaContract.java +EvitaDB.Client/Models/Schemas/IGlobalAttributeSchema.cs - + @@ -194,37 +194,37 @@ Entity schema can be made *deprecated*, which will be propagated to generated we ##### List of mutations related to entity type - + Top level entity mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/CreateEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/CreateEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/RemoveEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/RemoveEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyEntitySchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyEntitySchemaNameMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/CreateEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/CreateEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/RemoveEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/RemoveEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyEntitySchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyEntitySchemaNameMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/catalog/ModifyEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Catalogs/ModifyEntitySchemaMutation.cs** Within `ModifyEntitySchemaMutation` you can use mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/ModifyEntitySchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/ModifyEntitySchemaDescriptionMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/ModifyEntitySchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/ModifyEntitySchemaDeprecationNoticeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/ModifyEntitySchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/ModifyEntitySchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/ModifyEntitySchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/ModifyEntitySchemaDeprecationNoticeMutation.cs** - + - + The entity schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EntitySchemaContract.java -EvitaDB.Client/Models/Schemas/IEntitySchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EntitySchemaContract.java +EvitaDB.Client/Models/Schemas/IEntitySchema.cs - + #### Primary key generation If primary key generation is enabled, evitaDB assigns a unique -[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) -[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) number to a newly inserted entity. +[int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) +[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) number to a newly inserted entity. The primary key always starts with `1` and is incremented by `1`. evitaDB guarantees its uniqueness within the same entity type. The primary keys generated in this way are optimal for binary operations in the data structures used. @@ -237,7 +237,7 @@ entity type. The primary keys generated in this way are optimal for binary opera Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithGeneratedPrimaryKeyMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithGeneratedPrimaryKeyMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithGeneratedPrimaryKeyMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithGeneratedPrimaryKeyMutation.cs** @@ -263,8 +263,8 @@ will consume a lot of resources. The references will be created as `indexed` but There are several partial lax modes between strict and fully automatic evolution mode - see -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EvolutionMode.java -EvitaDB.Client/Models/Schemas/EvolutionMode.cs for details. +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/EvolutionMode.java +EvitaDB.Client/Models/Schemas/EvolutionMode.cs for details. For example - you can strictly control the entire schema, except for new locale or currency definitions, which are allowed to be added automatically on first use. @@ -277,8 +277,8 @@ allowed to be added automatically on first use. Within `ModifyEntitySchemaMutation` you can use mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowEvolutionModeInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowEvolutionModeInEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowEvolutionModeInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowEvolutionModeInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowEvolutionModeInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowEvolutionModeInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowEvolutionModeInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowEvolutionModeInEntitySchemaMutation.cs** @@ -312,10 +312,10 @@ enumeration values for them and change the Web API schemas every time a price li Within `ModifyEntitySchemaMutation` you can use mutations: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowCurrencyInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowCurrencyInEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowCurrencyInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowCurrencyInEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowLocaleInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowLocaleInEntitySchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowLocaleInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowLocaleInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowCurrencyInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowCurrencyInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowCurrencyInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowCurrencyInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/AllowLocaleInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/AllowLocaleInEntitySchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/DisallowLocaleInEntitySchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/DisallowLocaleInEntitySchemaMutation.cs** @@ -357,7 +357,7 @@ orphan nodes (sub-trees) are also appended. In this way, the hierarchy tree even Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithHierarchyMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithHierarchyMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithHierarchyMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithHierarchyMutation.cs** @@ -378,7 +378,7 @@ to it).For each combination of `priceList` and `currency` there is a special Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithPriceMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithPriceMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/entity/SetEntitySchemaWithPriceMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Entities/SetEntitySchemaWithPriceMutation.cs** @@ -393,12 +393,12 @@ sortable attribute and evita_engine/src/main/java/io/evitadb/index/ or evita_engine/src/main/java/io/evitadb/index/attribute/GlobalUniqueIndex.java for each unique attribute. Attributes that are neither `filterable` / `sortable` / `unique` don't consume operating memory. - + -Attribute schema can be marked as `localized`, meaning that it only makes sense in a specific -[locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html) -[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo). - +Attribute schema can be marked as `localized`, meaning that it only makes sense in a specific +[locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html) +[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo). + Attribute schema can be made *deprecated*, which will be propagated to generated web API documentation. @@ -411,26 +411,26 @@ Attribute schema can be made *deprecated*, which will be propagated to generated Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/CreateAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/CreateAttributeSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/RemoveAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/RemoveAttributeSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaNameMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDescriptionMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDefaultValueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDefaultValueMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDeprecationNoticeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaTypeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaTypeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaFilterableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaFilterableMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaLocalizedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaLocalizedMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaNullableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaNullableMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaRepresentativeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaRepresentativeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaSortableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaSortableMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaUniqueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaUniqueMutation.cs** - - +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/CreateAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/CreateAttributeSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/RemoveAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/RemoveAttributeSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaNameMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDefaultValueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDefaultValueMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaDeprecationNoticeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/ModifyAttributeSchemaTypeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/ModifyAttributeSchemaTypeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaFilterableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaFilterableMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaLocalizedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaLocalizedMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaNullableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaNullableMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaRepresentativeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaRepresentativeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaSortableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaSortableMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/attribute/SetAttributeSchemaUniqueMutation.javaEvitaDB.Client/Models/Schemas/Mutations/Attributes/SetAttributeSchemaUniqueMutation.cs** + + The attribute schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AttributeSchemaContract.java -EvitaDB.Client/Models/Schemas/IAttributeSchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AttributeSchemaContract.java +EvitaDB.Client/Models/Schemas/IAttributeSchema.cs - + @@ -442,8 +442,8 @@ assigned to a particular attribute. There is no other situation where the defaul #### Allowed decimal places The allowed decimal places setting is an optimization that allows rich numeric types (such -as [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html)[decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) for precise -number representation) to be converted to the primitive [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) type, which is much more +as [BigDecimal](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html)[decimal](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) for precise +number representation) to be converted to the primitive [int](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)[int](https://learn.microsoft.com/en-us/dotnet/api/system.int32) type, which is much more compact and can be used for fast binary searches in array/bitset representation. The original rich format is still present in an attribute container, but internally the database uses the primitive form when an attribute is part of is part of filter or sort conditions. @@ -480,14 +480,14 @@ Sortable attribute compound schema can be made *deprecated*, which will be propa Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/CreateSortableAttributeCompoundSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/CreateSortableAttributeCompoundSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/RemoveSortableAttributeCompoundSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/RemoveSortableAttributeCompoundSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaNameMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaDescriptionMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaDeprecationNoticeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/CreateSortableAttributeCompoundSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/CreateSortableAttributeCompoundSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/RemoveSortableAttributeCompoundSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/RemoveSortableAttributeCompoundSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaNameMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/sortableAttributeCompound/ModifySortableAttributeCompoundSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/SortableAttributeCompounds/ModifySortableAttributeCompoundSchemaDeprecationNoticeMutation.cs** The sortable attribute compound schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/SortableAttributeCompoundSchemaContract.javaEvitaDB.Client/Models/Schemas/ISortableAttributeCompoundSchema.cs +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/SortableAttributeCompoundSchemaContract.javaEvitaDB.Client/Models/Schemas/ISortableAttributeCompoundSchema.cs @@ -498,8 +498,8 @@ tens of associated data. Associated data schema can be marked as `localized`, meaning that it only makes sense in a specific -[locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html) -[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo).. +[locale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html) +[locale](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo).. Associated data schema can be made *deprecated*, which will be propagated to generated web API documentation. @@ -512,18 +512,18 @@ Associated data schema can be made *deprecated*, which will be propagated to gen Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/CreateAssociatedDataSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/CreateAssociatedDataSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/RemoveAssociatedDataSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/RemoveAssociatedDataSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaNameMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaDescriptionMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaDeprecationNoticeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaTypeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaTypeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/SetAssociatedDataSchemaLocalizedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/SetAssociatedDataSchemaLocalizedMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/SetAssociatedDataSchemaNullableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/SetAssociatedDataSchemaNullableMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/CreateAssociatedDataSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/CreateAssociatedDataSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/RemoveAssociatedDataSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/RemoveAssociatedDataSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaNameMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaDeprecationNoticeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/ModifyAssociatedDataSchemaTypeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/ModifyAssociatedDataSchemaTypeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/SetAssociatedDataSchemaLocalizedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/SetAssociatedDataSchemaLocalizedMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/associatedData/SetAssociatedDataSchemaNullableMutation.javaEvitaDB.Client/Models/Schemas/Mutations/AssociatedData/SetAssociatedDataSchemaNullableMutation.cs** - -The associated data schema is described by: evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AssociatedDataSchemaContract.javaEvitaDB.Client/Models/Schemas/IAssociatedDataSchema.cs - + +The associated data schema is described by: evita_api/src/main/java/io/evitadb/api/requestResponse/schema/AssociatedDataSchemaContract.javaEvitaDB.Client/Models/Schemas/IAssociatedDataSchema.cs + @@ -566,27 +566,27 @@ conforms to the creator's mental model. Within `ModifyEntitySchemaMutation` you can use mutation: -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/CreateReferenceSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/CreateReferenceSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/RemoveReferenceSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/RemoveReferenceSchemaMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaNameMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaDescriptionMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaDeprecationNoticeMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaCardinalityMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaCardinalityMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaRelatedEntityMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaRelatedEntityMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaRelatedEntityGroupMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaRelatedEntityGroupMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/SetReferenceSchemaIndexedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/SetReferenceSchemaIndexedMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/SetReferenceSchemaFacetedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/SetReferenceSchemaFacetedMutation.cs** -- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceAttributeSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/CreateReferenceSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/CreateReferenceSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/RemoveReferenceSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/RemoveReferenceSchemaMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaNameMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaNameMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaDescriptionMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaDescriptionMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaDeprecationNoticeMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaDeprecationNoticeMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaCardinalityMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaCardinalityMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaRelatedEntityMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaRelatedEntityMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceSchemaRelatedEntityGroupMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceSchemaRelatedEntityGroupMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/SetReferenceSchemaIndexedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/SetReferenceSchemaIndexedMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/SetReferenceSchemaFacetedMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/SetReferenceSchemaFacetedMutation.cs** +- **evita_api/src/main/java/io/evitadb/api/requestResponse/schema/mutation/reference/ModifyReferenceAttributeSchemaMutation.javaEvitaDB.Client/Models/Schemas/Mutations/References/ModifyReferenceAttributeSchemaMutation.cs** The `ModifyReferenceAttributeSchemaMutation` expect nested [attribute mutation](#attributes). - + The reference schema is described by: -evita_api/src/main/java/io/evitadb/api/requestResponse/schema/ReferenceSchemaContract.java -EvitaDB.Client/Models/Schemas/IReferenceSchema.cs> +evita_api/src/main/java/io/evitadb/api/requestResponse/schema/ReferenceSchemaContract.java +EvitaDB.Client/Models/Schemas/IReferenceSchema.cs> - + diff --git a/evita_api/src/main/java/io/evitadb/api/proxy/impl/entityBuilder/SetReferenceMethodClassifier.java b/evita_api/src/main/java/io/evitadb/api/proxy/impl/entityBuilder/SetReferenceMethodClassifier.java index 29946c886..940542f87 100644 --- a/evita_api/src/main/java/io/evitadb/api/proxy/impl/entityBuilder/SetReferenceMethodClassifier.java +++ b/evita_api/src/main/java/io/evitadb/api/proxy/impl/entityBuilder/SetReferenceMethodClassifier.java @@ -304,10 +304,13 @@ private static void getOrCreateReferenceWithId( final Object referenceProxy = reference .map(referenceContract -> theState.getOrCreateEntityReferenceProxy((Class) expectedType, referenceContract)) .orElseGet( - () -> theState.createEntityReferenceProxy( - theState.getEntitySchema(), referenceSchema, (Class) expectedType, ProxyType.REFERENCE, - referencedId - ) + () -> { + theState.entityBuilder().setReference(referenceSchema.getName(), referencedId); + return theState.createEntityReferenceProxy( + theState.getEntitySchema(), referenceSchema, (Class) expectedType, ProxyType.REFERENCE, + referencedId + ); + } ); //noinspection unchecked final Consumer consumer = (Consumer) args[consumerLocation]; @@ -461,6 +464,7 @@ private static void createReferencedEntityWithId( ) { final EntityBuilder entityBuilder = theState.entityBuilder(); final int referencedId = EvitaDataTypes.toTargetType((Serializable) args[referenceIdLocation], int.class); + entityBuilder.setReference(referenceSchema.getName(), referencedId); final Object referencedEntityInstance = theState.createEntityReferenceProxy( theState.getEntitySchema(), referenceSchema, @@ -468,7 +472,6 @@ private static void createReferencedEntityWithId( ProxyType.REFERENCE, referencedId ); - entityBuilder.setReference(referenceSchema.getName(), referencedId); //noinspection unchecked final Consumer consumer = (Consumer) args[consumerLocation]; consumer.accept(referencedEntityInstance); @@ -634,6 +637,7 @@ private static CurriedMethodContextInvocationHandler references = theState.entityBuilder() .getReferences(referenceName); if (references.isEmpty()) { + theState.entityBuilder().setReference(referenceSchema.getName(), referencedId); return theState.createEntityReferenceProxy( theState.getEntitySchema(), referenceSchema, expectedType, ProxyType.REFERENCE, referencedId @@ -1738,15 +1742,14 @@ private static CurriedMethodContextInvocationHandler { final EntityBuilder entityBuilder = theState.entityBuilder(); final int referencedId = EvitaDataTypes.toTargetType((Serializable) args[0], int.class); - final Object referencedEntityInstance = theState.createEntityReferenceProxy( + entityBuilder.setReference(referenceSchema.getName(), referencedId); + return theState.createEntityReferenceProxy( theState.getEntitySchema(), referenceSchema, expectedType, ProxyType.REFERENCE, referencedId ); - entityBuilder.setReference(referenceSchema.getName(), referencedId); - return referencedEntityInstance; }; } } diff --git a/evita_common/src/main/java/io/evitadb/exception/InvalidEvitaVersionException.java b/evita_common/src/main/java/io/evitadb/exception/InvalidEvitaVersionException.java new file mode 100644 index 000000000..4087d9a3c --- /dev/null +++ b/evita_common/src/main/java/io/evitadb/exception/InvalidEvitaVersionException.java @@ -0,0 +1,45 @@ +/* + * + * _ _ ____ ____ + * _____ _(_) |_ __ _| _ \| __ ) + * / _ \ \ / / | __/ _` | | | | _ \ + * | __/\ V /| | || (_| | |_| | |_) | + * \___| \_/ |_|\__\__,_|____/|____/ + * + * Copyright (c) 2023-2024 + * + * Licensed under the Business Source License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/FgForrest/evitaDB/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.evitadb.exception; + +import javax.annotation.Nonnull; +import java.io.Serial; + +/** + * This exception is thrown when version of EvitaClient or server is unknown or has invalid format. + * + * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2021 + */ +public class InvalidEvitaVersionException extends EvitaInternalError { + @Serial private static final long serialVersionUID = 6174951598824773806L; + + public InvalidEvitaVersionException(@Nonnull String privateMessage, @Nonnull String publicMessage, @Nonnull Throwable cause) { + super(privateMessage, publicMessage, cause); + } + + public InvalidEvitaVersionException(@Nonnull String privateMessage, @Nonnull String publicMessage) { + super(privateMessage, publicMessage); + } + +} diff --git a/evita_common/src/main/java/io/evitadb/utils/VersionUtils.java b/evita_common/src/main/java/io/evitadb/utils/VersionUtils.java index 4d0732c03..229ff54a3 100644 --- a/evita_common/src/main/java/io/evitadb/utils/VersionUtils.java +++ b/evita_common/src/main/java/io/evitadb/utils/VersionUtils.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ package io.evitadb.utils; +import io.evitadb.exception.InvalidEvitaVersionException; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.InputStream; @@ -87,21 +89,28 @@ public record SemVer( * * @param version the string version in the format "major.minor.patch" */ - private SemVer(@Nonnull String... version) { - this( - Integer.parseInt(version[0]), - Integer.parseInt(version[1]), - version.length > 2 ? version[2] : null - ); - } + public static SemVer fromString(@Nonnull String version) { + if (version.equals("?")) { + throw new InvalidEvitaVersionException( + "Invalid version string: `" + version + "`.", + "Invalid version string: `" + version + "`." + ); + } - /** - * Constructs a SemVer object from a string version. - * - * @param version the string version in the format "major.minor.patch" - */ - public SemVer(@Nonnull String version) { - this(version.replace("-SNAPSHOT", "").split("\\.")); + final String[] versionParts = version.replace("-SNAPSHOT", "").split("\\."); + try { + return new SemVer( + Integer.parseInt(versionParts[0]), + Integer.parseInt(versionParts[1]), + versionParts.length > 2 ? versionParts[2] : null + ); + } catch (NumberFormatException e) { + throw new InvalidEvitaVersionException( + "Invalid version string: `" + version + "`.", + "Invalid version string: `" + version + "`.", + e + ); + } } @Override diff --git a/evita_engine/src/main/java/io/evitadb/core/SessionRegistry.java b/evita_engine/src/main/java/io/evitadb/core/SessionRegistry.java index 76932136c..ac1b67827 100644 --- a/evita_engine/src/main/java/io/evitadb/core/SessionRegistry.java +++ b/evita_engine/src/main/java/io/evitadb/core/SessionRegistry.java @@ -186,7 +186,7 @@ public Object invoke(Object proxy, Method method, Object[] args) { // unwrap and rethrow throw evitaInternalError; } else { - log.error("Unexpected internal Evita error occurred: {}", ex.getCause().getMessage(), ex); + log.error("Unexpected internal Evita error occurred: {}", ex.getCause().getMessage(), targetException); throw new EvitaInternalError( "Unexpected internal Evita error occurred: " + ex.getCause().getMessage(), "Unexpected internal Evita error occurred.", diff --git a/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java b/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java index a803b16a7..d10bb758e 100644 --- a/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java +++ b/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClient.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ import io.evitadb.driver.pooling.ChannelPool; import io.evitadb.exception.EvitaInternalError; import io.evitadb.exception.EvitaInvalidUsageException; +import io.evitadb.exception.InvalidEvitaVersionException; import io.evitadb.externalApi.grpc.dataType.EvitaDataTypesConverter; import io.evitadb.externalApi.grpc.generated.*; import io.evitadb.externalApi.grpc.generated.EvitaServiceGrpc.EvitaServiceBlockingStub; @@ -183,8 +184,22 @@ public EvitaClient( try { final SystemStatus systemStatus = this.getSystemStatus(); - final SemVer serverVersion = new SemVer(systemStatus.version()); - final SemVer clientVersion = new SemVer(getVersion()); + final SemVer serverVersion; + final SemVer clientVersion; + + try { + serverVersion = SemVer.fromString(systemStatus.version()); + } catch (InvalidEvitaVersionException e) { + log.warn("Server version `{}` is not a valid semantic version. Aborting version check, this situation may lead to compatibility issues.", systemStatus.version()); + return; + } + try { + clientVersion = SemVer.fromString(getVersion()); + } catch (InvalidEvitaVersionException e) { + log.warn("Client version `{}` is not a valid semantic version. Aborting version check, this situation may lead to compatibility issues.", getVersion()); + return; + } + final int comparisonResult = SemVer.compare(clientVersion, serverVersion); if (comparisonResult < 0) { log.warn( diff --git a/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClientSession.java b/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClientSession.java index 1bc8cf940..a6ff7a79c 100644 --- a/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClientSession.java +++ b/evita_external_api/evita_external_api_grpc/client/src/main/java/io/evitadb/driver/EvitaClientSession.java @@ -225,7 +225,7 @@ public class EvitaClientSession implements EvitaSessionContract { */ private long lastCall; - private static void assertRequestMakesSense(@Nonnull Query query, @Nonnull Class expectedType) { + private static Query assertRequestMakesSenseAndEntityTypeIsPresent(@Nonnull Query query, @Nonnull Class expectedType, @Nonnull ReflectionLookup reflectionLookup) { if (EntityContract.class.isAssignableFrom(expectedType) && (query.getRequire() == null || FinderVisitor.findConstraints(query.getRequire(), EntityFetch.class::isInstance, SeparateEntityContentRequireContainer.class::isInstance).isEmpty())) { @@ -235,6 +235,20 @@ private static void assertRequestMakesSense(@Nonnull Qu "will be returned by the server!" ); } + if (query.getCollection() == null) { + final String entityTypeByExpectedType = extractEntityTypeFromClass(expectedType, reflectionLookup) + .orElseGet(() -> ofNullable(query.getCollection()) + .map(io.evitadb.api.query.head.Collection::getEntityType) + .orElseThrow(() -> new CollectionNotFoundException(expectedType))); + return Query.query( + collection(entityTypeByExpectedType), + query.getFilterBy(), + query.getOrderBy(), + query.getRequire() + ).normalizeQuery(); + } else { + return query.normalizeQuery(); + } } public EvitaClientSession( @@ -444,17 +458,11 @@ public List queryList(@Nonnull Query query, @Nonnull @Override public > T query(@Nonnull Query query, @Nonnull Class expectedType) throws UnexpectedResultException, InstanceTerminatedException { assertActive(); - assertRequestMakesSense(query, expectedType); - final String entityTypeByExpectedType = extractEntityTypeFromClass(expectedType, reflectionLookup) - .orElseGet(() -> ofNullable(query.getCollection()) - .map(io.evitadb.api.query.head.Collection::getEntityType) - .orElseThrow(() -> new CollectionNotFoundException(expectedType))); - - final StringWithParameters stringWithParameters = query.normalizeQuery().toStringWithParameterExtraction(); + final Query finalQuery = assertRequestMakesSenseAndEntityTypeIsPresent(query, expectedType, reflectionLookup); + final StringWithParameters stringWithParameters = finalQuery.toStringWithParameterExtraction(); final GrpcQueryResponse grpcResponse = executeWithEvitaSessionService(evitaSessionService -> evitaSessionService.query( GrpcQueryRequest.newBuilder() - .setCollection(entityTypeByExpectedType) .setQuery(stringWithParameters.query()) .addAllPositionalQueryParams( stringWithParameters.parameters() @@ -472,11 +480,11 @@ public > T query(@Nonnull Que ); //noinspection unchecked return (T) new EvitaEntityReferenceResponse( - query, recordPage, + finalQuery, recordPage, getEvitaResponseExtraResults( grpcResponse, new EvitaRequest( - query, + finalQuery, OffsetDateTime.now(), EntityReference.class, null, @@ -485,6 +493,10 @@ public > T query(@Nonnull Que ) ); } else { + final String expectedEntityType = ofNullable(finalQuery.getCollection()) + .map(io.evitadb.api.query.head.Collection::getEntityType) + .orElse(null); + final DataChunk recordPage; if (grpcResponse.getRecordPage().getBinaryEntitiesList().isEmpty()) { // convert to Sealed entities @@ -493,10 +505,10 @@ public > T query(@Nonnull Que grpcRecordPage -> EntityConverter.toEntities( grpcRecordPage.getSealedEntitiesList(), new EvitaRequest( - query, + finalQuery, OffsetDateTime.now(), expectedType, - entityTypeByExpectedType, + expectedEntityType, this::createEntityProxy ), (entityType, schemaVersion) -> schemaCache.getEntitySchemaOrThrow( @@ -520,14 +532,14 @@ public > T query(@Nonnull Que //noinspection unchecked return (T) new EvitaEntityResponse<>( - query, recordPage, + finalQuery, recordPage, getEvitaResponseExtraResults( grpcResponse, new EvitaRequest( - query, + finalQuery, OffsetDateTime.now(), expectedType, - entityTypeByExpectedType, + expectedEntityType, this::createEntityProxy ) ) @@ -1400,17 +1412,11 @@ private List queryListInternal( @Nonnull EvitaRequest evitaRequest ) { assertActive(); - assertRequestMakesSense(query, expectedType); - final String entityTypeByExpectedType = extractEntityTypeFromClass(expectedType, reflectionLookup) - .orElseGet(() -> ofNullable(query.getCollection()) - .map(io.evitadb.api.query.head.Collection::getEntityType) - .orElseThrow(() -> new CollectionNotFoundException(expectedType))); - - final StringWithParameters stringWithParameters = query.normalizeQuery().toStringWithParameterExtraction(); + final Query finalQuery = assertRequestMakesSenseAndEntityTypeIsPresent(query, expectedType, reflectionLookup); + final StringWithParameters stringWithParameters = finalQuery.toStringWithParameterExtraction(); final GrpcQueryListResponse grpcResponse = executeWithEvitaSessionService(evitaSessionService -> evitaSessionService.queryList( GrpcQueryRequest.newBuilder() - .setCollection(entityTypeByExpectedType) .setQuery(stringWithParameters.query()) .addAllPositionalQueryParams( stringWithParameters.parameters() @@ -1514,17 +1520,11 @@ private Optional queryOneInternal( @Nonnull EvitaRequest evitaRequest ) { assertActive(); - assertRequestMakesSense(query, expectedType); - final String entityTypeByExpectedType = extractEntityTypeFromClass(expectedType, reflectionLookup) - .orElseGet(() -> ofNullable(query.getCollection()) - .map(io.evitadb.api.query.head.Collection::getEntityType) - .orElseThrow(() -> new CollectionNotFoundException(expectedType))); - - final StringWithParameters stringWithParameters = query.normalizeQuery().toStringWithParameterExtraction(); + final Query finalQuery = assertRequestMakesSenseAndEntityTypeIsPresent(query, expectedType, reflectionLookup); + final StringWithParameters stringWithParameters = finalQuery.toStringWithParameterExtraction(); final GrpcQueryOneResponse grpcResponse = executeWithEvitaSessionService(evitaSessionService -> evitaSessionService.queryOne( GrpcQueryRequest.newBuilder() - .setCollection(entityTypeByExpectedType) .setQuery(stringWithParameters.query()) .addAllPositionalQueryParams( stringWithParameters.parameters() diff --git a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaSessionService.java b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaSessionService.java index ad060e314..06df40a97 100644 --- a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaSessionService.java +++ b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/services/EvitaSessionService.java @@ -580,7 +580,7 @@ public void query(@Nonnull GrpcQueryRequest request, @Nonnull StreamObserver responseEntities = session.queryList(evitaRequest); diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcEvitaSessionAPI.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcEvitaSessionAPI.java index 126964145..038297fbd 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcEvitaSessionAPI.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcEvitaSessionAPI.java @@ -356,271 +356,271 @@ public static void registerAllExtensions( "tyCollectionSizeResponse\022\014\n\004size\030\001 \001(\005\"-" + "\n\032GrpcGoLiveAndCloseResponse\022\017\n\007success\030" + "\001 \001(\010\".\n\027GrpcEntityTypesResponse\022\023\n\013enti" + - "tyTypes\030\001 \003(\t\"\344\002\n\020GrpcQueryRequest\022\022\n\nco" + - "llection\030\001 \001(\t\022\r\n\005query\030\002 \001(\t\022T\n\025positio" + - "nalQueryParams\030\003 \003(\01325.io.evitadb.extern" + - "alApi.grpc.generated.GrpcQueryParam\022g\n\020n" + - "amedQueryParams\030\004 \003(\0132M.io.evitadb.exter" + - "nalApi.grpc.generated.GrpcQueryRequest.N" + - "amedQueryParamsEntry\032n\n\025NamedQueryParams" + - "Entry\022\013\n\003key\030\001 \001(\t\022D\n\005value\030\002 \001(\01325.io.e" + - "vitadb.externalApi.grpc.generated.GrpcQu" + - "eryParam:\0028\001\"\254\001\n\021GrpcQueryResponse\022H\n\nre" + - "cordPage\030\001 \001(\01324.io.evitadb.externalApi." + - "grpc.generated.GrpcDataChunk\022M\n\014extraRes" + - "ults\030\002 \001(\01327.io.evitadb.externalApi.grpc" + - ".generated.GrpcExtraResults\"\211\002\n\024GrpcQuer" + - "yOneResponse\022S\n\017entityReference\030\001 \001(\0132:." + - "io.evitadb.externalApi.grpc.generated.Gr" + - "pcEntityReference\022M\n\014sealedEntity\030\002 \001(\0132" + - "7.io.evitadb.externalApi.grpc.generated." + - "GrpcSealedEntity\022M\n\014binaryEntity\030\003 \001(\01327" + - ".io.evitadb.externalApi.grpc.generated.G" + - "rpcBinaryEntity\"\217\002\n\025GrpcQueryListRespons" + - "e\022T\n\020entityReferences\030\001 \003(\0132:.io.evitadb" + - ".externalApi.grpc.generated.GrpcEntityRe" + - "ference\022O\n\016sealedEntities\030\002 \003(\01327.io.evi" + - "tadb.externalApi.grpc.generated.GrpcSeal" + - "edEntity\022O\n\016binaryEntities\030\003 \003(\01327.io.ev" + - "itadb.externalApi.grpc.generated.GrpcBin" + - "aryEntity\"\263\003\n\027GrpcUpsertEntityRequest\022Q\n" + - "\016entityMutation\030\001 \001(\01329.io.evitadb.exter" + - "nalApi.grpc.generated.GrpcEntityMutation" + - "\022\017\n\007require\030\002 \001(\t\022T\n\025positionalQueryPara" + - "ms\030\003 \003(\01325.io.evitadb.externalApi.grpc.g" + - "enerated.GrpcQueryParam\022n\n\020namedQueryPar" + - "ams\030\004 \003(\0132T.io.evitadb.externalApi.grpc." + - "generated.GrpcUpsertEntityRequest.NamedQ" + - "ueryParamsEntry\032n\n\025NamedQueryParamsEntry" + - "\022\013\n\003key\030\001 \001(\t\022D\n\005value\030\002 \001(\01325.io.evitad" + + "tyTypes\030\001 \003(\t\"\320\002\n\020GrpcQueryRequest\022\r\n\005qu" + + "ery\030\001 \001(\t\022T\n\025positionalQueryParams\030\002 \003(\013" + + "25.io.evitadb.externalApi.grpc.generated" + + ".GrpcQueryParam\022g\n\020namedQueryParams\030\003 \003(" + + "\0132M.io.evitadb.externalApi.grpc.generate" + + "d.GrpcQueryRequest.NamedQueryParamsEntry" + + "\032n\n\025NamedQueryParamsEntry\022\013\n\003key\030\001 \001(\t\022D" + + "\n\005value\030\002 \001(\01325.io.evitadb.externalApi.g" + + "rpc.generated.GrpcQueryParam:\0028\001\"\254\001\n\021Grp" + + "cQueryResponse\022H\n\nrecordPage\030\001 \001(\01324.io." + + "evitadb.externalApi.grpc.generated.GrpcD" + + "ataChunk\022M\n\014extraResults\030\002 \001(\01327.io.evit" + + "adb.externalApi.grpc.generated.GrpcExtra" + + "Results\"\211\002\n\024GrpcQueryOneResponse\022S\n\017enti" + + "tyReference\030\001 \001(\0132:.io.evitadb.externalA" + + "pi.grpc.generated.GrpcEntityReference\022M\n" + + "\014sealedEntity\030\002 \001(\01327.io.evitadb.externa" + + "lApi.grpc.generated.GrpcSealedEntity\022M\n\014" + + "binaryEntity\030\003 \001(\01327.io.evitadb.external" + + "Api.grpc.generated.GrpcBinaryEntity\"\217\002\n\025" + + "GrpcQueryListResponse\022T\n\020entityReference" + + "s\030\001 \003(\0132:.io.evitadb.externalApi.grpc.ge" + + "nerated.GrpcEntityReference\022O\n\016sealedEnt" + + "ities\030\002 \003(\01327.io.evitadb.externalApi.grp" + + "c.generated.GrpcSealedEntity\022O\n\016binaryEn" + + "tities\030\003 \003(\01327.io.evitadb.externalApi.gr" + + "pc.generated.GrpcBinaryEntity\"\263\003\n\027GrpcUp" + + "sertEntityRequest\022Q\n\016entityMutation\030\001 \001(" + + "\01329.io.evitadb.externalApi.grpc.generate" + + "d.GrpcEntityMutation\022\017\n\007require\030\002 \001(\t\022T\n" + + "\025positionalQueryParams\030\003 \003(\01325.io.evitad" + "b.externalApi.grpc.generated.GrpcQueryPa" + - "ram:\0028\001\"\245\003\n\027GrpcDeleteEntityRequest\022\022\n\ne" + - "ntityType\030\001 \001(\t\022/\n\nprimaryKey\030\002 \001(\0132\033.go" + - "ogle.protobuf.Int32Value\022\017\n\007require\030\003 \001(" + - "\t\022T\n\025positionalQueryParams\030\004 \003(\01325.io.ev" + + "ram\022n\n\020namedQueryParams\030\004 \003(\0132T.io.evita" + + "db.externalApi.grpc.generated.GrpcUpsert" + + "EntityRequest.NamedQueryParamsEntry\032n\n\025N" + + "amedQueryParamsEntry\022\013\n\003key\030\001 \001(\t\022D\n\005val" + + "ue\030\002 \001(\01325.io.evitadb.externalApi.grpc.g" + + "enerated.GrpcQueryParam:\0028\001\"\245\003\n\027GrpcDele" + + "teEntityRequest\022\022\n\nentityType\030\001 \001(\t\022/\n\np" + + "rimaryKey\030\002 \001(\0132\033.google.protobuf.Int32V" + + "alue\022\017\n\007require\030\003 \001(\t\022T\n\025positionalQuery" + + "Params\030\004 \003(\01325.io.evitadb.externalApi.gr" + + "pc.generated.GrpcQueryParam\022n\n\020namedQuer" + + "yParams\030\005 \003(\0132T.io.evitadb.externalApi.g" + + "rpc.generated.GrpcDeleteEntityRequest.Na" + + "medQueryParamsEntry\032n\n\025NamedQueryParamsE" + + "ntry\022\013\n\003key\030\001 \001(\t\022D\n\005value\030\002 \001(\01325.io.ev" + "itadb.externalApi.grpc.generated.GrpcQue" + - "ryParam\022n\n\020namedQueryParams\030\005 \003(\0132T.io.e" + - "vitadb.externalApi.grpc.generated.GrpcDe" + - "leteEntityRequest.NamedQueryParamsEntry\032" + - "n\n\025NamedQueryParamsEntry\022\013\n\003key\030\001 \001(\t\022D\n" + - "\005value\030\002 \001(\01325.io.evitadb.externalApi.gr" + - "pc.generated.GrpcQueryParam:\0028\001\"\342\002\n\031Grpc" + - "DeleteEntitiesRequest\022\r\n\005query\030\001 \001(\t\022T\n\025" + - "positionalQueryParams\030\002 \003(\01325.io.evitadb" + - ".externalApi.grpc.generated.GrpcQueryPar" + - "am\022p\n\020namedQueryParams\030\003 \003(\0132V.io.evitad" + - "b.externalApi.grpc.generated.GrpcDeleteE" + - "ntitiesRequest.NamedQueryParamsEntry\032n\n\025" + - "NamedQueryParamsEntry\022\013\n\003key\030\001 \001(\t\022D\n\005va" + - "lue\030\002 \001(\01325.io.evitadb.externalApi.grpc." + - "generated.GrpcQueryParam:\0028\001\"\310\001\n\030GrpcUps" + - "ertEntityResponse\022U\n\017entityReference\030\001 \001" + + "ryParam:\0028\001\"\342\002\n\031GrpcDeleteEntitiesReques" + + "t\022\r\n\005query\030\001 \001(\t\022T\n\025positionalQueryParam" + + "s\030\002 \003(\01325.io.evitadb.externalApi.grpc.ge" + + "nerated.GrpcQueryParam\022p\n\020namedQueryPara" + + "ms\030\003 \003(\0132V.io.evitadb.externalApi.grpc.g" + + "enerated.GrpcDeleteEntitiesRequest.Named" + + "QueryParamsEntry\032n\n\025NamedQueryParamsEntr" + + "y\022\013\n\003key\030\001 \001(\t\022D\n\005value\030\002 \001(\01325.io.evita" + + "db.externalApi.grpc.generated.GrpcQueryP" + + "aram:\0028\001\"\310\001\n\030GrpcUpsertEntityResponse\022U\n" + + "\017entityReference\030\001 \001(\0132:.io.evitadb.exte" + + "rnalApi.grpc.generated.GrpcEntityReferen" + + "ceH\000\022I\n\006entity\030\002 \001(\01327.io.evitadb.extern" + + "alApi.grpc.generated.GrpcSealedEntityH\000B" + + "\n\n\010response\"\310\001\n\030GrpcDeleteEntityResponse" + + "\022U\n\017entityReference\030\001 \001(\0132:.io.evitadb.e" + + "xternalApi.grpc.generated.GrpcEntityRefe" + + "renceH\000\022I\n\006entity\030\002 \001(\01327.io.evitadb.ext" + + "ernalApi.grpc.generated.GrpcSealedEntity" + + "H\000B\n\n\010response\"\206\002\n\'GrpcDeleteEntityAndIt" + + "sHierarchyResponse\022\027\n\017deletedEntities\030\001 " + + "\001(\005\022`\n\032deletedRootEntityReference\030\002 \001(\0132" + + ":.io.evitadb.externalApi.grpc.generated." + + "GrpcEntityReferenceH\000\022T\n\021deletedRootEnti" + + "ty\030\003 \001(\01327.io.evitadb.externalApi.grpc.g" + + "enerated.GrpcSealedEntityH\000B\n\n\010response\"" + + "\213\001\n\032GrpcDeleteEntitiesResponse\022\027\n\017delete" + + "dEntities\030\001 \001(\005\022T\n\023deletedEntityBodies\030\002" + + " \003(\01327.io.evitadb.externalApi.grpc.gener" + + "ated.GrpcSealedEntity\"Q\n\033GrpcOpenTransac" + + "tionResponse\022\033\n\023alreadyOpenedBefore\030\001 \001(" + + "\010\022\025\n\rtransactionId\030\002 \001(\003\"/\n\033GrpcCloseTra" + + "nsactionRequest\022\020\n\010rollback\030\001 \001(\010\"\311\035\n\016Gr" + + "pcQueryParam\022\025\n\013stringValue\030\001 \001(\tH\000\022\026\n\014i" + + "ntegerValue\030\002 \001(\005H\000\022\023\n\tlongValue\030\003 \001(\003H\000" + + "\022\026\n\014booleanValue\030\004 \001(\010H\000\022P\n\017bigDecimalVa" + + "lue\030\005 \001(\01325.io.evitadb.externalApi.grpc." + + "generated.GrpcBigDecimalH\000\022V\n\022dateTimeRa" + + "ngeValue\030\006 \001(\01328.io.evitadb.externalApi." + + "grpc.generated.GrpcDateTimeRangeH\000\022`\n\027in" + + "tegerNumberRangeValue\030\007 \001(\0132=.io.evitadb" + + ".externalApi.grpc.generated.GrpcIntegerN" + + "umberRangeH\000\022Z\n\024longNumberRangeValue\030\010 \001" + "(\0132:.io.evitadb.externalApi.grpc.generat" + - "ed.GrpcEntityReferenceH\000\022I\n\006entity\030\002 \001(\013" + - "27.io.evitadb.externalApi.grpc.generated" + - ".GrpcSealedEntityH\000B\n\n\010response\"\310\001\n\030Grpc" + - "DeleteEntityResponse\022U\n\017entityReference\030" + - "\001 \001(\0132:.io.evitadb.externalApi.grpc.gene" + - "rated.GrpcEntityReferenceH\000\022I\n\006entity\030\002 " + - "\001(\01327.io.evitadb.externalApi.grpc.genera" + - "ted.GrpcSealedEntityH\000B\n\n\010response\"\206\002\n\'G" + - "rpcDeleteEntityAndItsHierarchyResponse\022\027" + - "\n\017deletedEntities\030\001 \001(\005\022`\n\032deletedRootEn" + - "tityReference\030\002 \001(\0132:.io.evitadb.externa" + - "lApi.grpc.generated.GrpcEntityReferenceH" + - "\000\022T\n\021deletedRootEntity\030\003 \001(\01327.io.evitad" + - "b.externalApi.grpc.generated.GrpcSealedE" + - "ntityH\000B\n\n\010response\"\213\001\n\032GrpcDeleteEntiti" + - "esResponse\022\027\n\017deletedEntities\030\001 \001(\005\022T\n\023d" + - "eletedEntityBodies\030\002 \003(\01327.io.evitadb.ex" + - "ternalApi.grpc.generated.GrpcSealedEntit" + - "y\"Q\n\033GrpcOpenTransactionResponse\022\033\n\023alre" + - "adyOpenedBefore\030\001 \001(\010\022\025\n\rtransactionId\030\002" + - " \001(\003\"/\n\033GrpcCloseTransactionRequest\022\020\n\010r" + - "ollback\030\001 \001(\010\"\311\035\n\016GrpcQueryParam\022\025\n\013stri" + - "ngValue\030\001 \001(\tH\000\022\026\n\014integerValue\030\002 \001(\005H\000\022" + - "\023\n\tlongValue\030\003 \001(\003H\000\022\026\n\014booleanValue\030\004 \001" + - "(\010H\000\022P\n\017bigDecimalValue\030\005 \001(\01325.io.evita" + - "db.externalApi.grpc.generated.GrpcBigDec" + - "imalH\000\022V\n\022dateTimeRangeValue\030\006 \001(\01328.io." + - "evitadb.externalApi.grpc.generated.GrpcD" + - "ateTimeRangeH\000\022`\n\027integerNumberRangeValu" + - "e\030\007 \001(\0132=.io.evitadb.externalApi.grpc.ge" + - "nerated.GrpcIntegerNumberRangeH\000\022Z\n\024long" + - "NumberRangeValue\030\010 \001(\0132:.io.evitadb.exte" + - "rnalApi.grpc.generated.GrpcLongNumberRan" + - "geH\000\022f\n\032bigDecimalNumberRangeValue\030\t \001(\013" + - "2@.io.evitadb.externalApi.grpc.generated" + - ".GrpcBigDecimalNumberRangeH\000\022X\n\023offsetDa" + - "teTimeValue\030\n \001(\01329.io.evitadb.externalA" + - "pi.grpc.generated.GrpcOffsetDateTimeH\000\022H" + - "\n\013localeValue\030\013 \001(\01321.io.evitadb.externa" + - "lApi.grpc.generated.GrpcLocaleH\000\022L\n\rcurr" + - "encyValue\030\014 \001(\01323.io.evitadb.externalApi" + - ".grpc.generated.GrpcCurrencyH\000\022d\n\031facetS" + - "tatisticsDepthValue\030\r \001(\0162?.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcFacetStati" + - "sticsDepthH\000\022Y\n\024queryPriceModelValue\030\016 \001" + - "(\01629.io.evitadb.externalApi.grpc.generat" + - "ed.GrpcQueryPriceModeH\000\022\\\n\025priceContentM" + - "odeValue\030\017 \001(\0162;.io.evitadb.externalApi." + - "grpc.generated.GrpcPriceContentModeH\000\022a\n" + - "\025attributeSpecialValue\030\020 \001(\0162@.io.evitad" + - "b.externalApi.grpc.generated.GrpcAttribu" + - "teSpecialValueH\000\022X\n\023orderDirectionValue\030" + - "\021 \001(\01629.io.evitadb.externalApi.grpc.gene" + - "rated.GrpcOrderDirectionH\000\022w\n emptyHiera" + - "rchicalEntityBehaviour\030\022 \001(\0162K.io.evitad" + - "b.externalApi.grpc.generated.GrpcEmptyHi" + - "erarchicalEntityBehaviourH\000\022S\n\016statistic" + - "sBase\030\023 \001(\01629.io.evitadb.externalApi.grp" + - "c.generated.GrpcStatisticsBaseH\000\022S\n\016stat" + - "isticsType\030\024 \001(\01629.io.evitadb.externalAp" + - "i.grpc.generated.GrpcStatisticsTypeH\000\022Y\n" + - "\021histogramBehavior\030\025 \001(\0162<.io.evitadb.ex" + - "ternalApi.grpc.generated.GrpcHistogramBe" + - "haviorH\000\022R\n\020stringArrayValue\030e \001(\01326.io." + - "evitadb.externalApi.grpc.generated.GrpcS" + - "tringArrayH\000\022T\n\021integerArrayValue\030f \001(\0132" + - "7.io.evitadb.externalApi.grpc.generated." + - "GrpcIntegerArrayH\000\022N\n\016longArrayValue\030g \001" + - "(\01324.io.evitadb.externalApi.grpc.generat" + - "ed.GrpcLongArrayH\000\022T\n\021booleanArrayValue\030" + - "h \001(\01327.io.evitadb.externalApi.grpc.gene" + - "rated.GrpcBooleanArrayH\000\022Z\n\024bigDecimalAr" + - "rayValue\030i \001(\0132:.io.evitadb.externalApi." + - "grpc.generated.GrpcBigDecimalArrayH\000\022`\n\027" + - "dateTimeRangeArrayValue\030j \001(\0132=.io.evita" + - "db.externalApi.grpc.generated.GrpcDateTi" + - "meRangeArrayH\000\022j\n\034integerNumberRangeArra" + - "yValue\030k \001(\0132B.io.evitadb.externalApi.gr" + - "pc.generated.GrpcIntegerNumberRangeArray" + - "H\000\022d\n\031longNumberRangeArrayValue\030l \001(\0132?." + + "ed.GrpcLongNumberRangeH\000\022f\n\032bigDecimalNu" + + "mberRangeValue\030\t \001(\0132@.io.evitadb.extern" + + "alApi.grpc.generated.GrpcBigDecimalNumbe" + + "rRangeH\000\022X\n\023offsetDateTimeValue\030\n \001(\01329." + "io.evitadb.externalApi.grpc.generated.Gr" + - "pcLongNumberRangeArrayH\000\022p\n\037bigDecimalNu" + - "mberRangeArrayValue\030m \001(\0132E.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcBigDecimal" + - "NumberRangeArrayH\000\022b\n\030offsetDateTimeArra" + - "yValue\030n \001(\0132>.io.evitadb.externalApi.gr" + - "pc.generated.GrpcOffsetDateTimeArrayH\000\022R" + - "\n\020localeArrayValue\030o \001(\01326.io.evitadb.ex" + - "ternalApi.grpc.generated.GrpcLocaleArray" + - "H\000\022V\n\022currencyArrayValue\030p \001(\01328.io.evit" + - "adb.externalApi.grpc.generated.GrpcCurre" + - "ncyArrayH\000\022n\n\036facetStatisticsDepthArrayV" + - "alue\030q \001(\0132D.io.evitadb.externalApi.grpc" + - ".generated.GrpcFacetStatisticsDepthArray" + - "H\000\022c\n\031queryPriceModelArrayValue\030r \001(\0132>." + - "io.evitadb.externalApi.grpc.generated.Gr" + - "pcQueryPriceModeArrayH\000\022f\n\032priceContentM" + - "odeArrayValue\030s \001(\0132@.io.evitadb.externa" + - "lApi.grpc.generated.GrpcPriceContentMode" + - "ArrayH\000\022k\n\032attributeSpecialArrayValue\030t " + - "\001(\0132E.io.evitadb.externalApi.grpc.genera" + - "ted.GrpcAttributeSpecialValueArrayH\000\022b\n\030" + - "orderDirectionArrayValue\030u \001(\0132>.io.evit" + - "adb.externalApi.grpc.generated.GrpcOrder" + - "DirectionArrayH\000\022\206\001\n*emptyHierarchicalEn" + - "tityBehaviourArrayValue\030v \001(\0132P.io.evita" + - "db.externalApi.grpc.generated.GrpcEmptyH" + - "ierarchicalEntityBehaviourArrayH\000\022b\n\030sta" + - "tisticsBaseArrayValue\030w \001(\0132>.io.evitadb" + + "pcOffsetDateTimeH\000\022H\n\013localeValue\030\013 \001(\0132" + + "1.io.evitadb.externalApi.grpc.generated." + + "GrpcLocaleH\000\022L\n\rcurrencyValue\030\014 \001(\01323.io" + + ".evitadb.externalApi.grpc.generated.Grpc" + + "CurrencyH\000\022d\n\031facetStatisticsDepthValue\030" + + "\r \001(\0162?.io.evitadb.externalApi.grpc.gene" + + "rated.GrpcFacetStatisticsDepthH\000\022Y\n\024quer" + + "yPriceModelValue\030\016 \001(\01629.io.evitadb.exte" + + "rnalApi.grpc.generated.GrpcQueryPriceMod" + + "eH\000\022\\\n\025priceContentModeValue\030\017 \001(\0162;.io." + + "evitadb.externalApi.grpc.generated.GrpcP" + + "riceContentModeH\000\022a\n\025attributeSpecialVal" + + "ue\030\020 \001(\0162@.io.evitadb.externalApi.grpc.g" + + "enerated.GrpcAttributeSpecialValueH\000\022X\n\023" + + "orderDirectionValue\030\021 \001(\01629.io.evitadb.e" + + "xternalApi.grpc.generated.GrpcOrderDirec" + + "tionH\000\022w\n emptyHierarchicalEntityBehavio" + + "ur\030\022 \001(\0162K.io.evitadb.externalApi.grpc.g" + + "enerated.GrpcEmptyHierarchicalEntityBeha" + + "viourH\000\022S\n\016statisticsBase\030\023 \001(\01629.io.evi" + + "tadb.externalApi.grpc.generated.GrpcStat" + + "isticsBaseH\000\022S\n\016statisticsType\030\024 \001(\01629.i" + + "o.evitadb.externalApi.grpc.generated.Grp" + + "cStatisticsTypeH\000\022Y\n\021histogramBehavior\030\025" + + " \001(\0162<.io.evitadb.externalApi.grpc.gener" + + "ated.GrpcHistogramBehaviorH\000\022R\n\020stringAr" + + "rayValue\030e \001(\01326.io.evitadb.externalApi." + + "grpc.generated.GrpcStringArrayH\000\022T\n\021inte" + + "gerArrayValue\030f \001(\01327.io.evitadb.externa" + + "lApi.grpc.generated.GrpcIntegerArrayH\000\022N" + + "\n\016longArrayValue\030g \001(\01324.io.evitadb.exte" + + "rnalApi.grpc.generated.GrpcLongArrayH\000\022T" + + "\n\021booleanArrayValue\030h \001(\01327.io.evitadb.e" + + "xternalApi.grpc.generated.GrpcBooleanArr" + + "ayH\000\022Z\n\024bigDecimalArrayValue\030i \001(\0132:.io." + + "evitadb.externalApi.grpc.generated.GrpcB" + + "igDecimalArrayH\000\022`\n\027dateTimeRangeArrayVa" + + "lue\030j \001(\0132=.io.evitadb.externalApi.grpc." + + "generated.GrpcDateTimeRangeArrayH\000\022j\n\034in" + + "tegerNumberRangeArrayValue\030k \001(\0132B.io.ev" + + "itadb.externalApi.grpc.generated.GrpcInt" + + "egerNumberRangeArrayH\000\022d\n\031longNumberRang" + + "eArrayValue\030l \001(\0132?.io.evitadb.externalA" + + "pi.grpc.generated.GrpcLongNumberRangeArr" + + "ayH\000\022p\n\037bigDecimalNumberRangeArrayValue\030" + + "m \001(\0132E.io.evitadb.externalApi.grpc.gene" + + "rated.GrpcBigDecimalNumberRangeArrayH\000\022b" + + "\n\030offsetDateTimeArrayValue\030n \001(\0132>.io.ev" + + "itadb.externalApi.grpc.generated.GrpcOff" + + "setDateTimeArrayH\000\022R\n\020localeArrayValue\030o" + + " \001(\01326.io.evitadb.externalApi.grpc.gener" + + "ated.GrpcLocaleArrayH\000\022V\n\022currencyArrayV" + + "alue\030p \001(\01328.io.evitadb.externalApi.grpc" + + ".generated.GrpcCurrencyArrayH\000\022n\n\036facetS" + + "tatisticsDepthArrayValue\030q \001(\0132D.io.evit" + + "adb.externalApi.grpc.generated.GrpcFacet" + + "StatisticsDepthArrayH\000\022c\n\031queryPriceMode" + + "lArrayValue\030r \001(\0132>.io.evitadb.externalA" + + "pi.grpc.generated.GrpcQueryPriceModeArra" + + "yH\000\022f\n\032priceContentModeArrayValue\030s \001(\0132" + + "@.io.evitadb.externalApi.grpc.generated." + + "GrpcPriceContentModeArrayH\000\022k\n\032attribute" + + "SpecialArrayValue\030t \001(\0132E.io.evitadb.ext" + + "ernalApi.grpc.generated.GrpcAttributeSpe" + + "cialValueArrayH\000\022b\n\030orderDirectionArrayV" + + "alue\030u \001(\0132>.io.evitadb.externalApi.grpc" + + ".generated.GrpcOrderDirectionArrayH\000\022\206\001\n" + + "*emptyHierarchicalEntityBehaviourArrayVa" + + "lue\030v \001(\0132P.io.evitadb.externalApi.grpc." + + "generated.GrpcEmptyHierarchicalEntityBeh" + + "aviourArrayH\000\022b\n\030statisticsBaseArrayValu" + + "e\030w \001(\0132>.io.evitadb.externalApi.grpc.ge" + + "nerated.GrpcStatisticsBaseArrayH\000\022b\n\030sta" + + "tisticsTypeArrayValue\030x \001(\0132>.io.evitadb" + ".externalApi.grpc.generated.GrpcStatisti" + - "csBaseArrayH\000\022b\n\030statisticsTypeArrayValu" + - "e\030x \001(\0132>.io.evitadb.externalApi.grpc.ge" + - "nerated.GrpcStatisticsTypeArrayH\000\022p\n\037his" + - "togramBehaviorTypeArrayValue\030y \001(\0132E.io." + - "evitadb.externalApi.grpc.generated.GrpcH" + - "istogramBehaviorTypeArrayH\000B\014\n\nqueryPara" + - "m2\315\033\n\023EvitaSessionService\022l\n\020GetCatalogS" + - "chema\022\026.google.protobuf.Empty\032@.io.evita" + - "db.externalApi.grpc.generated.GrpcCatalo" + - "gSchemaResponse\022j\n\017GetCatalogState\022\026.goo" + - "gle.protobuf.Empty\032?.io.evitadb.external" + - "Api.grpc.generated.GrpcCatalogStateRespo" + - "nse\022\222\001\n\017GetEntitySchema\022>.io.evitadb.ext" + - "ernalApi.grpc.generated.GrpcEntitySchema" + - "Request\032?.io.evitadb.externalApi.grpc.ge" + - "nerated.GrpcEntitySchemaResponse\022k\n\021GetA" + - "llEntityTypes\022\026.google.protobuf.Empty\032>." + + "csTypeArrayH\000\022p\n\037histogramBehaviorTypeAr" + + "rayValue\030y \001(\0132E.io.evitadb.externalApi." + + "grpc.generated.GrpcHistogramBehaviorType" + + "ArrayH\000B\014\n\nqueryParam2\315\033\n\023EvitaSessionSe" + + "rvice\022l\n\020GetCatalogSchema\022\026.google.proto" + + "buf.Empty\032@.io.evitadb.externalApi.grpc." + + "generated.GrpcCatalogSchemaResponse\022j\n\017G" + + "etCatalogState\022\026.google.protobuf.Empty\032?" + + ".io.evitadb.externalApi.grpc.generated.G" + + "rpcCatalogStateResponse\022\222\001\n\017GetEntitySch" + + "ema\022>.io.evitadb.externalApi.grpc.genera" + + "ted.GrpcEntitySchemaRequest\032?.io.evitadb" + + ".externalApi.grpc.generated.GrpcEntitySc" + + "hemaResponse\022k\n\021GetAllEntityTypes\022\026.goog" + + "le.protobuf.Empty\032>.io.evitadb.externalA" + + "pi.grpc.generated.GrpcEntityTypesRespons" + + "e\022k\n\016GoLiveAndClose\022\026.google.protobuf.Em" + + "pty\032A.io.evitadb.externalApi.grpc.genera" + + "ted.GrpcGoLiveAndCloseResponse\0227\n\005Close\022" + + "\026.google.protobuf.Empty\032\026.google.protobu" + + "f.Empty\022\200\001\n\010QueryOne\0227.io.evitadb.extern" + + "alApi.grpc.generated.GrpcQueryRequest\032;." + "io.evitadb.externalApi.grpc.generated.Gr" + - "pcEntityTypesResponse\022k\n\016GoLiveAndClose\022" + - "\026.google.protobuf.Empty\032A.io.evitadb.ext" + - "ernalApi.grpc.generated.GrpcGoLiveAndClo" + - "seResponse\0227\n\005Close\022\026.google.protobuf.Em" + - "pty\032\026.google.protobuf.Empty\022\200\001\n\010QueryOne" + + "pcQueryOneResponse\022\202\001\n\tQueryList\0227.io.ev" + + "itadb.externalApi.grpc.generated.GrpcQue" + + "ryRequest\032<.io.evitadb.externalApi.grpc." + + "generated.GrpcQueryListResponse\022z\n\005Query" + "\0227.io.evitadb.externalApi.grpc.generated" + - ".GrpcQueryRequest\032;.io.evitadb.externalA" + - "pi.grpc.generated.GrpcQueryOneResponse\022\202" + - "\001\n\tQueryList\0227.io.evitadb.externalApi.gr" + - "pc.generated.GrpcQueryRequest\032<.io.evita" + - "db.externalApi.grpc.generated.GrpcQueryL" + - "istResponse\022z\n\005Query\0227.io.evitadb.extern" + - "alApi.grpc.generated.GrpcQueryRequest\0328." + - "io.evitadb.externalApi.grpc.generated.Gr" + - "pcQueryResponse\022\200\001\n\tGetEntity\0228.io.evita" + - "db.externalApi.grpc.generated.GrpcEntity" + - "Request\0329.io.evitadb.externalApi.grpc.ge" + - "nerated.GrpcEntityResponse\022\244\001\n\023UpdateCat" + - "alogSchema\022E.io.evitadb.externalApi.grpc" + - ".generated.GrpcUpdateCatalogSchemaReques" + - "t\032F.io.evitadb.externalApi.grpc.generate" + - "d.GrpcUpdateCatalogSchemaResponse\022\264\001\n\033Up" + - "dateAndFetchCatalogSchema\022E.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcUpdateCata" + - "logSchemaRequest\032N.io.evitadb.externalAp" + - "i.grpc.generated.GrpcUpdateAndFetchCatal" + - "ogSchemaResponse\022\241\001\n\022DefineEntitySchema\022" + - "D.io.evitadb.externalApi.grpc.generated." + - "GrpcDefineEntitySchemaRequest\032E.io.evita" + - "db.externalApi.grpc.generated.GrpcDefine" + - "EntitySchemaResponse\022\241\001\n\022UpdateEntitySch" + - "ema\022D.io.evitadb.externalApi.grpc.genera" + - "ted.GrpcUpdateEntitySchemaRequest\032E.io.e" + - "vitadb.externalApi.grpc.generated.GrpcUp" + - "dateEntitySchemaResponse\022\261\001\n\032UpdateAndFe" + - "tchEntitySchema\022D.io.evitadb.externalApi" + - ".grpc.generated.GrpcUpdateEntitySchemaRe" + - "quest\032M.io.evitadb.externalApi.grpc.gene" + - "rated.GrpcUpdateAndFetchEntitySchemaResp" + - "onse\022\233\001\n\020DeleteCollection\022B.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcDeleteColl" + - "ectionRequest\032C.io.evitadb.externalApi.g" + - "rpc.generated.GrpcDeleteCollectionRespon" + - "se\022\233\001\n\020RenameCollection\022B.io.evitadb.ext" + - "ernalApi.grpc.generated.GrpcRenameCollec" + - "tionRequest\032C.io.evitadb.externalApi.grp" + - "c.generated.GrpcRenameCollectionResponse" + - "\022\236\001\n\021ReplaceCollection\022C.io.evitadb.exte" + - "rnalApi.grpc.generated.GrpcReplaceCollec" + - "tionRequest\032D.io.evitadb.externalApi.grp" + - "c.generated.GrpcReplaceCollectionRespons" + - "e\022\252\001\n\027GetEntityCollectionSize\022F.io.evita" + - "db.externalApi.grpc.generated.GrpcEntity" + - "CollectionSizeRequest\032G.io.evitadb.exter" + - "nalApi.grpc.generated.GrpcEntityCollecti" + - "onSizeResponse\022\217\001\n\014UpsertEntity\022>.io.evi" + - "tadb.externalApi.grpc.generated.GrpcUpse" + - "rtEntityRequest\032?.io.evitadb.externalApi" + - ".grpc.generated.GrpcUpsertEntityResponse" + - "\022\217\001\n\014DeleteEntity\022>.io.evitadb.externalA" + - "pi.grpc.generated.GrpcDeleteEntityReques" + - "t\032?.io.evitadb.externalApi.grpc.generate" + - "d.GrpcDeleteEntityResponse\022\255\001\n\033DeleteEnt" + - "ityAndItsHierarchy\022>.io.evitadb.external" + - "Api.grpc.generated.GrpcDeleteEntityReque" + - "st\032N.io.evitadb.externalApi.grpc.generat" + - "ed.GrpcDeleteEntityAndItsHierarchyRespon" + - "se\022\225\001\n\016DeleteEntities\022@.io.evitadb.exter" + - "nalApi.grpc.generated.GrpcDeleteEntities" + - "Request\032A.io.evitadb.externalApi.grpc.ge" + - "nerated.GrpcDeleteEntitiesResponse\022m\n\017Op" + - "enTransaction\022\026.google.protobuf.Empty\032B." + - "io.evitadb.externalApi.grpc.generated.Gr" + - "pcOpenTransactionResponse\022n\n\020CloseTransa" + + ".GrpcQueryRequest\0328.io.evitadb.externalA" + + "pi.grpc.generated.GrpcQueryResponse\022\200\001\n\t" + + "GetEntity\0228.io.evitadb.externalApi.grpc." + + "generated.GrpcEntityRequest\0329.io.evitadb" + + ".externalApi.grpc.generated.GrpcEntityRe" + + "sponse\022\244\001\n\023UpdateCatalogSchema\022E.io.evit" + + "adb.externalApi.grpc.generated.GrpcUpdat" + + "eCatalogSchemaRequest\032F.io.evitadb.exter" + + "nalApi.grpc.generated.GrpcUpdateCatalogS" + + "chemaResponse\022\264\001\n\033UpdateAndFetchCatalogS" + + "chema\022E.io.evitadb.externalApi.grpc.gene" + + "rated.GrpcUpdateCatalogSchemaRequest\032N.i" + + "o.evitadb.externalApi.grpc.generated.Grp" + + "cUpdateAndFetchCatalogSchemaResponse\022\241\001\n" + + "\022DefineEntitySchema\022D.io.evitadb.externa" + + "lApi.grpc.generated.GrpcDefineEntitySche" + + "maRequest\032E.io.evitadb.externalApi.grpc." + + "generated.GrpcDefineEntitySchemaResponse" + + "\022\241\001\n\022UpdateEntitySchema\022D.io.evitadb.ext" + + "ernalApi.grpc.generated.GrpcUpdateEntity" + + "SchemaRequest\032E.io.evitadb.externalApi.g" + + "rpc.generated.GrpcUpdateEntitySchemaResp" + + "onse\022\261\001\n\032UpdateAndFetchEntitySchema\022D.io" + + ".evitadb.externalApi.grpc.generated.Grpc" + + "UpdateEntitySchemaRequest\032M.io.evitadb.e" + + "xternalApi.grpc.generated.GrpcUpdateAndF" + + "etchEntitySchemaResponse\022\233\001\n\020DeleteColle" + "ction\022B.io.evitadb.externalApi.grpc.gene" + - "rated.GrpcCloseTransactionRequest\032\026.goog" + - "le.protobuf.EmptyB\014P\001\252\002\007EvitaDBb\006proto3" + "rated.GrpcDeleteCollectionRequest\032C.io.e" + + "vitadb.externalApi.grpc.generated.GrpcDe" + + "leteCollectionResponse\022\233\001\n\020RenameCollect" + + "ion\022B.io.evitadb.externalApi.grpc.genera" + + "ted.GrpcRenameCollectionRequest\032C.io.evi" + + "tadb.externalApi.grpc.generated.GrpcRena" + + "meCollectionResponse\022\236\001\n\021ReplaceCollecti" + + "on\022C.io.evitadb.externalApi.grpc.generat" + + "ed.GrpcReplaceCollectionRequest\032D.io.evi" + + "tadb.externalApi.grpc.generated.GrpcRepl" + + "aceCollectionResponse\022\252\001\n\027GetEntityColle" + + "ctionSize\022F.io.evitadb.externalApi.grpc." + + "generated.GrpcEntityCollectionSizeReques" + + "t\032G.io.evitadb.externalApi.grpc.generate" + + "d.GrpcEntityCollectionSizeResponse\022\217\001\n\014U" + + "psertEntity\022>.io.evitadb.externalApi.grp" + + "c.generated.GrpcUpsertEntityRequest\032?.io" + + ".evitadb.externalApi.grpc.generated.Grpc" + + "UpsertEntityResponse\022\217\001\n\014DeleteEntity\022>." + + "io.evitadb.externalApi.grpc.generated.Gr" + + "pcDeleteEntityRequest\032?.io.evitadb.exter" + + "nalApi.grpc.generated.GrpcDeleteEntityRe" + + "sponse\022\255\001\n\033DeleteEntityAndItsHierarchy\022>" + + ".io.evitadb.externalApi.grpc.generated.G" + + "rpcDeleteEntityRequest\032N.io.evitadb.exte" + + "rnalApi.grpc.generated.GrpcDeleteEntityA" + + "ndItsHierarchyResponse\022\225\001\n\016DeleteEntitie" + + "s\022@.io.evitadb.externalApi.grpc.generate" + + "d.GrpcDeleteEntitiesRequest\032A.io.evitadb" + + ".externalApi.grpc.generated.GrpcDeleteEn" + + "titiesResponse\022m\n\017OpenTransaction\022\026.goog" + + "le.protobuf.Empty\032B.io.evitadb.externalA" + + "pi.grpc.generated.GrpcOpenTransactionRes" + + "ponse\022n\n\020CloseTransaction\022B.io.evitadb.e" + + "xternalApi.grpc.generated.GrpcCloseTrans" + + "actionRequest\032\026.google.protobuf.EmptyB\014P" + + "\001\252\002\007EvitaDBb\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -810,7 +810,7 @@ public static void registerAllExtensions( internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryRequest_descriptor, - new java.lang.String[] { "Collection", "Query", "PositionalQueryParams", "NamedQueryParams", }); + new java.lang.String[] { "Query", "PositionalQueryParams", "NamedQueryParams", }); internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryRequest_NamedQueryParamsEntry_descriptor = internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryRequest_descriptor.getNestedTypes().get(0); internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryRequest_NamedQueryParamsEntry_fieldAccessorTable = new diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java index 412233885..990e43b6c 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023-2024 + * Copyright (c) 2023 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -39,62 +39,62 @@ public static void registerAllExtensions( } static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcHistogram_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcHistogram_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcHistogram_GrpcBucket_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcHistogram_GrpcBucket_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetGroupStatistics_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetGroupStatistics_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetStatistics_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetStatistics_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_HierarchyEntry_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_HierarchyEntry_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcLevelInfos_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcLevelInfos_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcLevelInfo_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcLevelInfo_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryTelemetry_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcQueryTelemetry_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_AttributeHistogramEntry_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_AttributeHistogramEntry_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_HierarchyEntry_descriptor; - static final + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_evitadb_externalApi_grpc_generated_GrpcExtraResults_HierarchyEntry_fieldAccessorTable; diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcHistogram.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcHistogram.java index dccbcb85d..d5fe78fcd 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcHistogram.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcHistogram.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023-2024 + * Copyright (c) 2023 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -851,7 +851,7 @@ public Builder clearThreshold() { * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal threshold = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder getThresholdBuilder() { - + onChanged(); return getThresholdFieldBuilder().getBuilder(); } @@ -878,7 +878,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder getThreshol * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal threshold = 2; */ private com.google.protobuf.SingleFieldBuilderV3< - io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> + io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> getThresholdFieldBuilder() { if (thresholdBuilder_ == null) { thresholdBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< @@ -916,7 +916,7 @@ public int getOccurrences() { * @return This builder for chaining. */ public Builder setOccurrences(int value) { - + occurrences_ = value; onChanged(); return this; @@ -931,7 +931,7 @@ public Builder setOccurrences(int value) { * @return This builder for chaining. */ public Builder clearOccurrences() { - + occurrences_ = 0; onChanged(); return this; @@ -960,7 +960,7 @@ public boolean getRequested() { * @return This builder for chaining. */ public Builder setRequested(boolean value) { - + requested_ = value; onChanged(); return this; @@ -974,7 +974,7 @@ public Builder setRequested(boolean value) { * @return This builder for chaining. */ public Builder clearRequested() { - + requested_ = false; onChanged(); return this; @@ -1156,7 +1156,7 @@ public java.util.Listrepeated .io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket buckets = 4; */ @java.lang.Override - public java.util.List + public java.util.List getBucketsOrBuilderList() { return buckets_; } @@ -1588,7 +1588,7 @@ public Builder mergeFrom(io.evitadb.externalApi.grpc.generated.GrpcHistogram oth bucketsBuilder_ = null; buckets_ = other.buckets_; bitField0_ = (bitField0_ & ~0x00000001); - bucketsBuilder_ = + bucketsBuilder_ = com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? getBucketsFieldBuilder() : null; } else { @@ -1741,7 +1741,7 @@ public Builder clearMin() { * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal min = 1; */ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder getMinBuilder() { - + onChanged(); return getMinFieldBuilder().getBuilder(); } @@ -1768,7 +1768,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder getMinOrBui * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal min = 1; */ private com.google.protobuf.SingleFieldBuilderV3< - io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> + io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> getMinFieldBuilder() { if (minBuilder_ == null) { minBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< @@ -1917,7 +1917,7 @@ public Builder clearMax() { * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal max = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder getMaxBuilder() { - + onChanged(); return getMaxFieldBuilder().getBuilder(); } @@ -1950,7 +1950,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder getMaxOrBui * .io.evitadb.externalApi.grpc.generated.GrpcBigDecimal max = 2; */ private com.google.protobuf.SingleFieldBuilderV3< - io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> + io.evitadb.externalApi.grpc.generated.GrpcBigDecimal, io.evitadb.externalApi.grpc.generated.GrpcBigDecimal.Builder, io.evitadb.externalApi.grpc.generated.GrpcBigDecimalOrBuilder> getMaxFieldBuilder() { if (maxBuilder_ == null) { maxBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< @@ -1988,7 +1988,7 @@ public int getOverallCount() { * @return This builder for chaining. */ public Builder setOverallCount(int value) { - + overallCount_ = value; onChanged(); return this; @@ -2003,7 +2003,7 @@ public Builder setOverallCount(int value) { * @return This builder for chaining. */ public Builder clearOverallCount() { - + overallCount_ = 0; onChanged(); return this; @@ -2279,7 +2279,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucketOrBuilder g * * repeated .io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket buckets = 4; */ - public java.util.List + public java.util.List getBucketsOrBuilderList() { if (bucketsBuilder_ != null) { return bucketsBuilder_.getMessageOrBuilderList(); @@ -2320,12 +2320,12 @@ public io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket.Builder ad * * repeated .io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket buckets = 4; */ - public java.util.List + public java.util.List getBucketsBuilderList() { return getBucketsFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilderV3< - io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket, io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket.Builder, io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucketOrBuilder> + io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket, io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucket.Builder, io.evitadb.externalApi.grpc.generated.GrpcHistogram.GrpcBucketOrBuilder> getBucketsFieldBuilder() { if (bucketsBuilder_ == null) { bucketsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequest.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequest.java index f71e4c5f3..58431dd95 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequest.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequest.java @@ -43,7 +43,6 @@ private GrpcQueryRequest(com.google.protobuf.GeneratedMessageV3.Builder build super(builder); } private GrpcQueryRequest() { - collection_ = ""; query_ = ""; positionalQueryParams_ = java.util.Collections.emptyList(); } @@ -82,16 +81,10 @@ private GrpcQueryRequest( case 10: { java.lang.String s = input.readStringRequireUtf8(); - collection_ = s; - break; - } - case 18: { - java.lang.String s = input.readStringRequireUtf8(); - query_ = s; break; } - case 26: { + case 18: { if (!((mutable_bitField0_ & 0x00000001) != 0)) { positionalQueryParams_ = new java.util.ArrayList(); mutable_bitField0_ |= 0x00000001; @@ -100,7 +93,7 @@ private GrpcQueryRequest( input.readMessage(io.evitadb.externalApi.grpc.generated.GrpcQueryParam.parser(), extensionRegistry)); break; } - case 34: { + case 26: { if (!((mutable_bitField0_ & 0x00000002) != 0)) { namedQueryParams_ = com.google.protobuf.MapField.newMapField( NamedQueryParamsDefaultEntryHolder.defaultEntry); @@ -145,7 +138,7 @@ private GrpcQueryRequest( protected com.google.protobuf.MapField internalGetMapField( int number) { switch (number) { - case 4: + case 3: return internalGetNamedQueryParams(); default: throw new RuntimeException( @@ -160,60 +153,14 @@ protected com.google.protobuf.MapField internalGetMapField( io.evitadb.externalApi.grpc.generated.GrpcQueryRequest.class, io.evitadb.externalApi.grpc.generated.GrpcQueryRequest.Builder.class); } - public static final int COLLECTION_FIELD_NUMBER = 1; - private volatile java.lang.Object collection_; - /** - *
-   * The entity type that is queried.
-   * 
- * - * string collection = 1; - * @return The collection. - */ - @java.lang.Override - public java.lang.String getCollection() { - java.lang.Object ref = collection_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - collection_ = s; - return s; - } - } - /** - *
-   * The entity type that is queried.
-   * 
- * - * string collection = 1; - * @return The bytes for collection. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getCollectionBytes() { - java.lang.Object ref = collection_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - collection_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int QUERY_FIELD_NUMBER = 2; + public static final int QUERY_FIELD_NUMBER = 1; private volatile java.lang.Object query_; /** *
    * The string part of the parametrised query.
    * 
* - * string query = 2; + * string query = 1; * @return The query. */ @java.lang.Override @@ -234,7 +181,7 @@ public java.lang.String getQuery() { * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @return The bytes for query. */ @java.lang.Override @@ -252,14 +199,14 @@ public java.lang.String getQuery() { } } - public static final int POSITIONALQUERYPARAMS_FIELD_NUMBER = 3; + public static final int POSITIONALQUERYPARAMS_FIELD_NUMBER = 2; private java.util.List positionalQueryParams_; /** *
    * The positional query parameters.
    * 
* - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ @java.lang.Override public java.util.List getPositionalQueryParamsList() { @@ -270,7 +217,7 @@ public java.util.List getP * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ @java.lang.Override public java.util.List @@ -282,7 +229,7 @@ public java.util.List getP * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ @java.lang.Override public int getPositionalQueryParamsCount() { @@ -293,7 +240,7 @@ public int getPositionalQueryParamsCount() { * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ @java.lang.Override public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getPositionalQueryParams(int index) { @@ -304,7 +251,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getPositionalQueryPa * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ @java.lang.Override public io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPositionalQueryParamsOrBuilder( @@ -312,7 +259,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPosition return positionalQueryParams_.get(index); } - public static final int NAMEDQUERYPARAMS_FIELD_NUMBER = 4; + public static final int NAMEDQUERYPARAMS_FIELD_NUMBER = 3; private static final class NamedQueryParamsDefaultEntryHolder { static final com.google.protobuf.MapEntry< java.lang.String, io.evitadb.externalApi.grpc.generated.GrpcQueryParam> defaultEntry = @@ -343,7 +290,7 @@ public int getNamedQueryParamsCount() { * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -365,7 +312,7 @@ public java.util.Map * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -377,7 +324,7 @@ public java.util.Map * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -394,7 +341,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getNamedQueryParamsO * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -423,21 +370,18 @@ public final boolean isInitialized() { @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(collection_)) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, collection_); - } if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(query_)) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 2, query_); + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, query_); } for (int i = 0; i < positionalQueryParams_.size(); i++) { - output.writeMessage(3, positionalQueryParams_.get(i)); + output.writeMessage(2, positionalQueryParams_.get(i)); } com.google.protobuf.GeneratedMessageV3 .serializeStringMapTo( output, internalGetNamedQueryParams(), NamedQueryParamsDefaultEntryHolder.defaultEntry, - 4); + 3); unknownFields.writeTo(output); } @@ -447,15 +391,12 @@ public int getSerializedSize() { if (size != -1) return size; size = 0; - if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(collection_)) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, collection_); - } if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(query_)) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, query_); + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, query_); } for (int i = 0; i < positionalQueryParams_.size(); i++) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, positionalQueryParams_.get(i)); + .computeMessageSize(2, positionalQueryParams_.get(i)); } for (java.util.Map.Entry entry : internalGetNamedQueryParams().getMap().entrySet()) { @@ -465,7 +406,7 @@ public int getSerializedSize() { .setValue(entry.getValue()) .build(); size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, namedQueryParams__); + .computeMessageSize(3, namedQueryParams__); } size += unknownFields.getSerializedSize(); memoizedSize = size; @@ -482,8 +423,6 @@ public boolean equals(final java.lang.Object obj) { } io.evitadb.externalApi.grpc.generated.GrpcQueryRequest other = (io.evitadb.externalApi.grpc.generated.GrpcQueryRequest) obj; - if (!getCollection() - .equals(other.getCollection())) return false; if (!getQuery() .equals(other.getQuery())) return false; if (!getPositionalQueryParamsList() @@ -501,8 +440,6 @@ public int hashCode() { } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + COLLECTION_FIELD_NUMBER; - hash = (53 * hash) + getCollection().hashCode(); hash = (37 * hash) + QUERY_FIELD_NUMBER; hash = (53 * hash) + getQuery().hashCode(); if (getPositionalQueryParamsCount() > 0) { @@ -628,7 +565,7 @@ public static final class Builder extends protected com.google.protobuf.MapField internalGetMapField( int number) { switch (number) { - case 4: + case 3: return internalGetNamedQueryParams(); default: throw new RuntimeException( @@ -639,7 +576,7 @@ protected com.google.protobuf.MapField internalGetMapField( protected com.google.protobuf.MapField internalGetMutableMapField( int number) { switch (number) { - case 4: + case 3: return internalGetMutableNamedQueryParams(); default: throw new RuntimeException( @@ -673,8 +610,6 @@ private void maybeForceBuilderInitialization() { @java.lang.Override public Builder clear() { super.clear(); - collection_ = ""; - query_ = ""; if (positionalQueryParamsBuilder_ == null) { @@ -711,7 +646,6 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryRequest build() { public io.evitadb.externalApi.grpc.generated.GrpcQueryRequest buildPartial() { io.evitadb.externalApi.grpc.generated.GrpcQueryRequest result = new io.evitadb.externalApi.grpc.generated.GrpcQueryRequest(this); int from_bitField0_ = bitField0_; - result.collection_ = collection_; result.query_ = query_; if (positionalQueryParamsBuilder_ == null) { if (((bitField0_ & 0x00000001) != 0)) { @@ -772,10 +706,6 @@ public Builder mergeFrom(com.google.protobuf.Message other) { public Builder mergeFrom(io.evitadb.externalApi.grpc.generated.GrpcQueryRequest other) { if (other == io.evitadb.externalApi.grpc.generated.GrpcQueryRequest.getDefaultInstance()) return this; - if (!other.getCollection().isEmpty()) { - collection_ = other.collection_; - onChanged(); - } if (!other.getQuery().isEmpty()) { query_ = other.query_; onChanged(); @@ -838,109 +768,13 @@ public Builder mergeFrom( } private int bitField0_; - private java.lang.Object collection_ = ""; - /** - *
-     * The entity type that is queried.
-     * 
- * - * string collection = 1; - * @return The collection. - */ - public java.lang.String getCollection() { - java.lang.Object ref = collection_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - collection_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - *
-     * The entity type that is queried.
-     * 
- * - * string collection = 1; - * @return The bytes for collection. - */ - public com.google.protobuf.ByteString - getCollectionBytes() { - java.lang.Object ref = collection_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - collection_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - *
-     * The entity type that is queried.
-     * 
- * - * string collection = 1; - * @param value The collection to set. - * @return This builder for chaining. - */ - public Builder setCollection( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - - collection_ = value; - onChanged(); - return this; - } - /** - *
-     * The entity type that is queried.
-     * 
- * - * string collection = 1; - * @return This builder for chaining. - */ - public Builder clearCollection() { - - collection_ = getDefaultInstance().getCollection(); - onChanged(); - return this; - } - /** - *
-     * The entity type that is queried.
-     * 
- * - * string collection = 1; - * @param value The bytes for collection to set. - * @return This builder for chaining. - */ - public Builder setCollectionBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - collection_ = value; - onChanged(); - return this; - } - private java.lang.Object query_ = ""; /** *
      * The string part of the parametrised query.
      * 
* - * string query = 2; + * string query = 1; * @return The query. */ public java.lang.String getQuery() { @@ -960,7 +794,7 @@ public java.lang.String getQuery() { * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @return The bytes for query. */ public com.google.protobuf.ByteString @@ -981,7 +815,7 @@ public java.lang.String getQuery() { * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @param value The query to set. * @return This builder for chaining. */ @@ -1000,7 +834,7 @@ public Builder setQuery( * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @return This builder for chaining. */ public Builder clearQuery() { @@ -1014,7 +848,7 @@ public Builder clearQuery() { * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @param value The bytes for query to set. * @return This builder for chaining. */ @@ -1047,7 +881,7 @@ private void ensurePositionalQueryParamsIsMutable() { * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public java.util.List getPositionalQueryParamsList() { if (positionalQueryParamsBuilder_ == null) { @@ -1061,7 +895,7 @@ public java.util.List getP * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public int getPositionalQueryParamsCount() { if (positionalQueryParamsBuilder_ == null) { @@ -1075,7 +909,7 @@ public int getPositionalQueryParamsCount() { * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getPositionalQueryParams(int index) { if (positionalQueryParamsBuilder_ == null) { @@ -1089,7 +923,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getPositionalQueryPa * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder setPositionalQueryParams( int index, io.evitadb.externalApi.grpc.generated.GrpcQueryParam value) { @@ -1110,7 +944,7 @@ public Builder setPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder setPositionalQueryParams( int index, io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder builderForValue) { @@ -1128,7 +962,7 @@ public Builder setPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder addPositionalQueryParams(io.evitadb.externalApi.grpc.generated.GrpcQueryParam value) { if (positionalQueryParamsBuilder_ == null) { @@ -1148,7 +982,7 @@ public Builder addPositionalQueryParams(io.evitadb.externalApi.grpc.generated.Gr * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder addPositionalQueryParams( int index, io.evitadb.externalApi.grpc.generated.GrpcQueryParam value) { @@ -1169,7 +1003,7 @@ public Builder addPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder addPositionalQueryParams( io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder builderForValue) { @@ -1187,7 +1021,7 @@ public Builder addPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder addPositionalQueryParams( int index, io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder builderForValue) { @@ -1205,7 +1039,7 @@ public Builder addPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder addAllPositionalQueryParams( java.lang.Iterable values) { @@ -1224,7 +1058,7 @@ public Builder addAllPositionalQueryParams( * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder clearPositionalQueryParams() { if (positionalQueryParamsBuilder_ == null) { @@ -1241,7 +1075,7 @@ public Builder clearPositionalQueryParams() { * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public Builder removePositionalQueryParams(int index) { if (positionalQueryParamsBuilder_ == null) { @@ -1258,7 +1092,7 @@ public Builder removePositionalQueryParams(int index) { * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder getPositionalQueryParamsBuilder( int index) { @@ -1269,7 +1103,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder getPositiona * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPositionalQueryParamsOrBuilder( int index) { @@ -1283,7 +1117,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPosition * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public java.util.List getPositionalQueryParamsOrBuilderList() { @@ -1298,7 +1132,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPosition * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder addPositionalQueryParamsBuilder() { return getPositionalQueryParamsFieldBuilder().addBuilder( @@ -1309,7 +1143,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder addPositiona * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder addPositionalQueryParamsBuilder( int index) { @@ -1321,7 +1155,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam.Builder addPositiona * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ public java.util.List getPositionalQueryParamsBuilderList() { @@ -1373,7 +1207,7 @@ public int getNamedQueryParamsCount() { * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -1395,7 +1229,7 @@ public java.util.Map * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -1407,7 +1241,7 @@ public java.util.Map * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -1424,7 +1258,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcQueryParam getNamedQueryParamsO * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ @java.lang.Override @@ -1449,7 +1283,7 @@ public Builder clearNamedQueryParams() { * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ public Builder removeNamedQueryParams( @@ -1472,7 +1306,7 @@ public Builder removeNamedQueryParams( * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ public Builder putNamedQueryParams( java.lang.String key, @@ -1491,7 +1325,7 @@ public Builder putNamedQueryParams( * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ public Builder putAllNamedQueryParams( diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequestOrBuilder.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequestOrBuilder.java index c778f43c9..abfb8b552 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequestOrBuilder.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcQueryRequestOrBuilder.java @@ -30,32 +30,12 @@ public interface GrpcQueryRequestOrBuilder extends // @@protoc_insertion_point(interface_extends:io.evitadb.externalApi.grpc.generated.GrpcQueryRequest) com.google.protobuf.MessageOrBuilder { - /** - *
-   * The entity type that is queried.
-   * 
- * - * string collection = 1; - * @return The collection. - */ - java.lang.String getCollection(); - /** - *
-   * The entity type that is queried.
-   * 
- * - * string collection = 1; - * @return The bytes for collection. - */ - com.google.protobuf.ByteString - getCollectionBytes(); - /** *
    * The string part of the parametrised query.
    * 
* - * string query = 2; + * string query = 1; * @return The query. */ java.lang.String getQuery(); @@ -64,7 +44,7 @@ public interface GrpcQueryRequestOrBuilder extends * The string part of the parametrised query. * * - * string query = 2; + * string query = 1; * @return The bytes for query. */ com.google.protobuf.ByteString @@ -75,7 +55,7 @@ public interface GrpcQueryRequestOrBuilder extends * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ java.util.List getPositionalQueryParamsList(); @@ -84,7 +64,7 @@ public interface GrpcQueryRequestOrBuilder extends * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ io.evitadb.externalApi.grpc.generated.GrpcQueryParam getPositionalQueryParams(int index); /** @@ -92,7 +72,7 @@ public interface GrpcQueryRequestOrBuilder extends * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ int getPositionalQueryParamsCount(); /** @@ -100,7 +80,7 @@ public interface GrpcQueryRequestOrBuilder extends * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ java.util.List getPositionalQueryParamsOrBuilderList(); @@ -109,7 +89,7 @@ public interface GrpcQueryRequestOrBuilder extends * The positional query parameters. * * - * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 3; + * repeated .io.evitadb.externalApi.grpc.generated.GrpcQueryParam positionalQueryParams = 2; */ io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPositionalQueryParamsOrBuilder( int index); @@ -119,7 +99,7 @@ io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPositionalQuery * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ int getNamedQueryParamsCount(); /** @@ -127,7 +107,7 @@ io.evitadb.externalApi.grpc.generated.GrpcQueryParamOrBuilder getPositionalQuery * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ boolean containsNamedQueryParams( java.lang.String key); @@ -142,7 +122,7 @@ boolean containsNamedQueryParams( * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ java.util.Map getNamedQueryParamsMap(); @@ -151,7 +131,7 @@ boolean containsNamedQueryParams( * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ io.evitadb.externalApi.grpc.generated.GrpcQueryParam getNamedQueryParamsOrDefault( @@ -162,7 +142,7 @@ io.evitadb.externalApi.grpc.generated.GrpcQueryParam getNamedQueryParamsOrDefaul * The named query parameters. * * - * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 4; + * map<string, .io.evitadb.externalApi.grpc.generated.GrpcQueryParam> namedQueryParams = 3; */ io.evitadb.externalApi.grpc.generated.GrpcQueryParam getNamedQueryParamsOrThrow( diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcEvitaSessionAPI.proto b/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcEvitaSessionAPI.proto index b2e835085..e07b80eab 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcEvitaSessionAPI.proto +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcEvitaSessionAPI.proto @@ -221,14 +221,12 @@ message GrpcEntityTypesResponse { // Request for specifying a query to be executed. message GrpcQueryRequest { - // The entity type that is queried. - string collection = 1; // The string part of the parametrised query. - string query = 2; + string query = 1; // The positional query parameters. - repeated GrpcQueryParam positionalQueryParams = 3; + repeated GrpcQueryParam positionalQueryParams = 2; // The named query parameters. - map namedQueryParams = 4; + map namedQueryParams = 3; } // Response to Query request. diff --git a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/builder/RestBuildingContext.java b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/builder/RestBuildingContext.java index a6443fcdb..f6ad3bc48 100644 --- a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/builder/RestBuildingContext.java +++ b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/api/builder/RestBuildingContext.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ package io.evitadb.externalApi.rest.api.builder; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import io.evitadb.core.Evita; import io.evitadb.externalApi.configuration.AbstractApiConfiguration; @@ -107,6 +108,7 @@ protected ObjectMapper setupObjectMapper() { final SimpleModule module = new SimpleModule(); module.addSerializer(new BigDecimalSerializer()); objectMapper.registerModule(module); + objectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); return objectMapper; } diff --git a/evita_functional_tests/src/test/java/io/evitadb/documentation/UserDocumentationTest.java b/evita_functional_tests/src/test/java/io/evitadb/documentation/UserDocumentationTest.java index 9061947f9..8eb704d47 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/documentation/UserDocumentationTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/documentation/UserDocumentationTest.java @@ -406,7 +406,7 @@ Stream testDocumentation() throws IOException { Environment.DEMO_SERVER, it, new ExampleFilter[]{ -// ExampleFilter.CSHARP, + ExampleFilter.CSHARP, ExampleFilter.JAVA, ExampleFilter.REST, ExampleFilter.GRAPHQL, diff --git a/evita_functional_tests/src/test/java/io/evitadb/documentation/graphql/GraphQLTestContext.java b/evita_functional_tests/src/test/java/io/evitadb/documentation/graphql/GraphQLTestContext.java index 5c5641cde..5b7a08665 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/documentation/graphql/GraphQLTestContext.java +++ b/evita_functional_tests/src/test/java/io/evitadb/documentation/graphql/GraphQLTestContext.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ public class GraphQLTestContext implements TestContext { public GraphQLTestContext(@Nonnull Environment profile) { this.graphQLClient = profile == Environment.LOCALHOST ? - new GraphQLClient("https://localhost:5555", false) : - new GraphQLClient("https://demo.evitadb.io:5555"); + new GraphQLClient("https://localhost:5555", false, false) : + new GraphQLClient("https://demo.evitadb.io:5555", true, false); } } diff --git a/evita_functional_tests/src/test/java/io/evitadb/documentation/rest/RestTestContext.java b/evita_functional_tests/src/test/java/io/evitadb/documentation/rest/RestTestContext.java index a5d610c06..28f9b4055 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/documentation/rest/RestTestContext.java +++ b/evita_functional_tests/src/test/java/io/evitadb/documentation/rest/RestTestContext.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ public class RestTestContext implements TestContext { public RestTestContext(@Nonnull Environment profile) { this.restClient = profile == Environment.LOCALHOST ? - new RestClient("https://localhost:5555", false) : - new RestClient("https://demo.evitadb.io:5555"); + new RestClient("https://localhost:5555", false, false) : + new RestClient("https://demo.evitadb.io:5555", true, false); } } diff --git a/evita_functional_tests/src/test/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/CatalogGraphQLQueryEntityQueryFunctionalTest.java b/evita_functional_tests/src/test/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/CatalogGraphQLQueryEntityQueryFunctionalTest.java index 20a084625..4b4679bda 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/CatalogGraphQLQueryEntityQueryFunctionalTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/externalApi/graphql/api/catalog/dataApi/CatalogGraphQLQueryEntityQueryFunctionalTest.java @@ -3185,10 +3185,10 @@ void shouldReturnErrorForMultipleAttributeHistogramBucketsBehavior(GraphQLTester max overallCount buckets(requestedCount: 10, behavior: OPTIMIZED) { - index + threshold } otherBuckets: buckets(requestedCount: 10) { - index + threshold } } } @@ -3716,12 +3716,10 @@ void shouldReturnErrorForMultiplePriceHistogramBucketsBehaviors(GraphQLTester te max overallCount buckets(requestedCount: 10, behavior: OPTIMIZED) { - index threshold occurrences } otherBuckets: buckets(requestedCount: 10) { - index threshold occurrences } diff --git a/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/graphql/artificial/GraphQLArtificialBenchmarkState.java b/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/graphql/artificial/GraphQLArtificialBenchmarkState.java index c005aaea4..67bde45b8 100644 --- a/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/graphql/artificial/GraphQLArtificialBenchmarkState.java +++ b/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/graphql/artificial/GraphQLArtificialBenchmarkState.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,8 @@ public GraphQLClient getSession() { try { return new GraphQLClient( "https://" + InetAddress.getByName("localhost").getHostAddress() + ":5555/gql/test-catalog", - false + false, + true ); } catch (UnknownHostException e) { throw new EvitaInternalError("Unknown host.", e); diff --git a/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/rest/artificial/RestArtificialBenchmarkState.java b/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/rest/artificial/RestArtificialBenchmarkState.java index 31c1c6c31..4dbe856a7 100644 --- a/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/rest/artificial/RestArtificialBenchmarkState.java +++ b/evita_performance_tests/src/main/java/io/evitadb/performance/externalApi/rest/artificial/RestArtificialBenchmarkState.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ public abstract class RestArtificialBenchmarkState extends AbstractArtificialBen public RestClient getSession() { return getSession(() -> { try { - return new RestClient("https://" + InetAddress.getByName("localhost").getHostAddress() + ":5555", false); + return new RestClient("https://" + InetAddress.getByName("localhost").getHostAddress() + ":5555", false, true); } catch (UnknownHostException e) { throw new EvitaInternalError("Could not create REST API URL:", e); } diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseListener.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseListener.java index 10969995d..81d424d1d 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseListener.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseListener.java @@ -1,26 +1,3 @@ -/* - * - * _ _ ____ ____ - * _____ _(_) |_ __ _| _ \| __ ) - * / _ \ \ / / | __/ _` | | | | _ \ - * | __/\ V /| | || (_| | |_| | |_) | - * \___| \_/ |_|\__\__,_|____/|____/ - * - * Copyright (c) 2023-2024 - * - * Licensed under the Business Source License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/FgForrest/evitaDB/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - // Generated from EvitaQL.g4 by ANTLR 4.9.2 package io.evitadb.api.query.parser.grammar; diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseVisitor.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseVisitor.java index 102022558..1e714e8c1 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseVisitor.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLBaseVisitor.java @@ -1,26 +1,3 @@ -/* - * - * _ _ ____ ____ - * _____ _(_) |_ __ _| _ \| __ ) - * / _ \ \ / / | __/ _` | | | | _ \ - * | __/\ V /| | || (_| | |_| | |_) | - * \___| \_/ |_|\__\__,_|____/|____/ - * - * Copyright (c) 2023-2024 - * - * Licensed under the Business Source License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/FgForrest/evitaDB/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - // Generated from EvitaQL.g4 by ANTLR 4.9.2 package io.evitadb.api.query.parser.grammar; diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLLexer.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLLexer.java index 9dd93082d..d38fdecd2 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLLexer.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLLexer.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023-2024 + * Copyright (c) 2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLListener.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLListener.java index b60e2fec6..ac162fed8 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLListener.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLListener.java @@ -1,26 +1,3 @@ -/* - * - * _ _ ____ ____ - * _____ _(_) |_ __ _| _ \| __ ) - * / _ \ \ / / | __/ _` | | | | _ \ - * | __/\ V /| | || (_| | |_| | |_) | - * \___| \_/ |_|\__\__,_|____/|____/ - * - * Copyright (c) 2023-2024 - * - * Licensed under the Business Source License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/FgForrest/evitaDB/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - // Generated from EvitaQL.g4 by ANTLR 4.9.2 package io.evitadb.api.query.parser.grammar; diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLParser.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLParser.java index 3a93a7677..7fb5fccbd 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLParser.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLParser.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023-2024 + * Copyright (c) 2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. diff --git a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLVisitor.java b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLVisitor.java index de2f34e0f..88f71f0dd 100644 --- a/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLVisitor.java +++ b/evita_query/src/main/java/io/evitadb/api/query/parser/grammar/EvitaQLVisitor.java @@ -1,26 +1,3 @@ -/* - * - * _ _ ____ ____ - * _____ _(_) |_ __ _| _ \| __ ) - * / _ \ \ / / | __/ _` | | | | _ \ - * | __/\ V /| | || (_| | |_| | |_) | - * \___| \_/ |_|\__\__,_|____/|____/ - * - * Copyright (c) 2023-2024 - * - * Licensed under the Business Source License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/FgForrest/evitaDB/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - // Generated from EvitaQL.g4 by ANTLR 4.9.2 package io.evitadb.api.query.parser.grammar; diff --git a/evita_test_support/pom.xml b/evita_test_support/pom.xml index 7df10f4aa..e5a16fbe0 100644 --- a/evita_test_support/pom.xml +++ b/evita_test_support/pom.xml @@ -143,5 +143,10 @@ rest-assured 5.3.0 + + com.squareup.okhttp3 + okhttp + 4.12.0 + \ No newline at end of file diff --git a/evita_test_support/src/main/java/io/evitadb/test/client/ApiClient.java b/evita_test_support/src/main/java/io/evitadb/test/client/ApiClient.java index d4f72a6da..24beb7dae 100644 --- a/evita_test_support/src/main/java/io/evitadb/test/client/ApiClient.java +++ b/evita_test_support/src/main/java/io/evitadb/test/client/ApiClient.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -26,20 +26,20 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.evitadb.exception.EvitaInternalError; +import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; +import okhttp3.ResponseBody; import javax.annotation.Nonnull; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; +import javax.net.ssl.X509TrustManager; import java.io.IOException; -import java.net.Socket; -import java.net.http.HttpClient; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.concurrent.TimeUnit; /** * Ancestor for simple clients calling mainly JSON-based HTTP APIs. @@ -50,81 +50,57 @@ abstract class ApiClient { protected static final ObjectMapper objectMapper = new ObjectMapper(); - protected final boolean validateSsl; @Nonnull protected final String url; + @Nonnull protected final OkHttpClient client; - protected ApiClient(@Nonnull String url) { - this(url, true); + protected ApiClient(@Nonnull String url, boolean validateSsl, boolean useConnectionPool) { + this.url = url; + this.client = createClient(validateSsl, useConnectionPool); } - protected ApiClient(@Nonnull String url, boolean validateSsl) { - this.url = url; - this.validateSsl = validateSsl; + protected OkHttpClient createClient(boolean validateSsl, boolean useConnectionPool) { + final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); - } + if (!useConnectionPool) { + clientBuilder.connectionPool(new ConnectionPool(0, 1, TimeUnit.NANOSECONDS)); + } - @Nonnull - protected HttpClient createClient() { - // todo lho - this is terrible, but I all other way result in `HTTP/1.1 header parser received no bytes` - if (validateSsl) { - return HttpClient.newBuilder() - .build(); - } else { + if (!validateSsl) { // Create a trust manager that does not validate certificate chains - final TrustManager trustManager = new NoValidateTrustManager(); - SSLContext sslContext = null; + final TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + } + }; + // Install the all-trusting trust manager + final SSLContext sc; + try { + sc = SSLContext.getInstance("SSL"); + } catch (NoSuchAlgorithmException e) { + throw new EvitaInternalError("Cannot get SSL context.", e); + } try { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom()); - } catch (NoSuchAlgorithmException | KeyManagementException e) { - throw new EvitaInternalError("Could create no-validate trust manager: ", e); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + } catch (KeyManagementException e) { + throw new EvitaInternalError("Cannot init SSL context with custom trust manager.", e); } - return HttpClient.newBuilder() - .sslContext(sslContext) - .build(); + // Create an all-trusting host verifier + HostnameVerifier hostnameVerifier = (hostname, session) -> true; + + clientBuilder + .sslSocketFactory(sc.getSocketFactory(), (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier(hostnameVerifier); } + return clientBuilder.build(); } @Nonnull - protected JsonNode readResponseBody(@Nonnull String body) throws IOException { - return objectMapper.readTree(body); - } - - private static class NoValidateTrustManager extends X509ExtendedTrustManager { - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { - - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { - - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { - - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { - - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[]{}; - } + protected JsonNode readResponseBody(@Nonnull ResponseBody responseBody) throws IOException { + return objectMapper.readTree(responseBody.string()); } } diff --git a/evita_test_support/src/main/java/io/evitadb/test/client/GraphQLClient.java b/evita_test_support/src/main/java/io/evitadb/test/client/GraphQLClient.java index fc7a8db23..f232411ed 100644 --- a/evita_test_support/src/main/java/io/evitadb/test/client/GraphQLClient.java +++ b/evita_test_support/src/main/java/io/evitadb/test/client/GraphQLClient.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -28,13 +28,13 @@ import io.evitadb.exception.EvitaInternalError; import io.evitadb.externalApi.graphql.io.GraphQLRequest; import io.evitadb.utils.Assert; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; import javax.annotation.Nonnull; import java.io.IOException; -import java.net.URI; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandlers; /** * Simple client for calling GraphQL requests from documentation. @@ -43,12 +43,8 @@ */ public class GraphQLClient extends ApiClient { - public GraphQLClient(@Nonnull String url) { - super(url); - } - - public GraphQLClient(@Nonnull String url, boolean validateSsl) { - super(url, validateSsl); + public GraphQLClient(@Nonnull String url, boolean validateSsl, boolean useConnectionPool) { + super(url, validateSsl, useConnectionPool); } @Nonnull @@ -58,11 +54,15 @@ public JsonNode call(@Nonnull String document) { @Nonnull public JsonNode call(@Nonnull String instancePath, @Nonnull String document) { + final Request request; try { - final HttpRequest request = createRequest(instancePath, document); - final HttpResponse response = createClient().send(request, BodyHandlers.ofString()); + request = createRequest(instancePath, document); + } catch (IOException e) { + throw new EvitaInternalError("Unexpected error.", e); + } - final int responseCode = response.statusCode(); + try (Response response = client.newCall(request).execute()) { + final int responseCode = response.code(); if (responseCode == 200) { final JsonNode responseBody = readResponseBody(response.body()); validateResponseBody(responseBody); @@ -70,26 +70,31 @@ public JsonNode call(@Nonnull String instancePath, @Nonnull String document) { return responseBody; } if (responseCode >= 400 && responseCode <= 499 && responseCode != 404) { - throw new EvitaInternalError("Call to GraphQL instance `" + this.url + instancePath + "` ended with status " + responseCode + ", query was:\n" + document + "\n and response was: \n" + response.body()); + final String errorResponseString = response.body() != null ? response.body().string() : "no response body"; + throw new EvitaInternalError("Call to GraphQL instance `" + this.url + instancePath + "` ended with status " + responseCode + ", query was:\n" + document + "\n and response was: \n" + errorResponseString); } throw new EvitaInternalError("Call to GraphQL server ended with status " + responseCode + ", query was:\n" + document); - } catch (IOException | InterruptedException e) { + } catch (IOException e) { throw new EvitaInternalError("Unexpected error.", e); } } @Nonnull - private HttpRequest createRequest(@Nonnull String instancePath, @Nonnull String document) throws IOException { + private Request createRequest(@Nonnull String instancePath, @Nonnull String document) throws IOException { + return new Request.Builder() + .url(this.url + instancePath) + .addHeader("Accept", "application/graphql-response+json") + .addHeader("Content-Type", "application/json") + .method("POST", RequestBody.create(createRequestBody(document), MediaType.parse("application/json"))) + .build(); + } + + protected String createRequestBody(@Nonnull String document) throws IOException { final GraphQLRequest requestBody = new GraphQLRequest(document, null, null, null); final String requestBodyJson = objectMapper.writeValueAsString(requestBody); - return HttpRequest.newBuilder() - .uri(URI.create(this.url + instancePath)) - .method("POST", HttpRequest.BodyPublishers.ofString(requestBodyJson)) - .header("Accept", "application/graphql-response+json") - .header("Content-Type", "application/json") - .build(); + return requestBodyJson; } private void validateResponseBody(@Nonnull JsonNode responseBody) throws JsonProcessingException { diff --git a/evita_test_support/src/main/java/io/evitadb/test/client/RestClient.java b/evita_test_support/src/main/java/io/evitadb/test/client/RestClient.java index 764594adf..48669e6ec 100644 --- a/evita_test_support/src/main/java/io/evitadb/test/client/RestClient.java +++ b/evita_test_support/src/main/java/io/evitadb/test/client/RestClient.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -23,19 +23,17 @@ package io.evitadb.test.client; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import io.evitadb.exception.EvitaInternalError; import io.evitadb.utils.Assert; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandlers; import java.util.Optional; /** @@ -45,21 +43,16 @@ */ public class RestClient extends ApiClient { - public RestClient(@Nonnull String url) { - super(url); - } - - public RestClient(@Nonnull String url, boolean validateSsl) { - super(url, validateSsl); + public RestClient(@Nonnull String url, boolean validateSsl, boolean useConnectionPool) { + super(url, validateSsl, useConnectionPool); } @Nullable public Optional call(@Nonnull String method, @Nonnull String resource, @Nullable String body) { - try { - final HttpRequest request = createRequest(method, resource, body); - final HttpResponse response = createClient().send(request, BodyHandlers.ofString()); + final Request request = createRequest(method, resource, body); - final int responseCode = response.statusCode(); + try (Response response = client.newCall(request).execute()) { + final int responseCode = response.code(); if (responseCode == 200) { final JsonNode responseBody = readResponseBody(response.body()); validateResponseBody(responseBody); @@ -70,26 +63,28 @@ public Optional call(@Nonnull String method, @Nonnull String resource, return Optional.empty(); } if (responseCode >= 400 && responseCode <= 499) { - throw new EvitaInternalError("Call to REST server `" + this.url + resource + "` ended with status " + responseCode + " and response: \n" + response.body()); + final String errorResponseString = response.body() != null ? response.body().string() : "no response body"; + throw new EvitaInternalError("Call to REST server `" + this.url + resource + "` ended with status " + responseCode + " and response: \n" + errorResponseString); } throw new EvitaInternalError("Call to REST server `" + this.url + resource + "` ended with status " + responseCode); - } catch (IOException | URISyntaxException | InterruptedException e) { + } catch (IOException e) { throw new EvitaInternalError("Unexpected error.", e); } } @Nonnull - private HttpRequest createRequest(@Nonnull String method, @Nonnull String resource, @Nullable String body) throws IOException, URISyntaxException { - return HttpRequest.newBuilder() - .uri(URI.create(this.url + resource)) - .method(method, body != null && !body.isBlank() ? HttpRequest.BodyPublishers.ofString(body) : HttpRequest.BodyPublishers.noBody()) - .header("Accept", "application/json") - .header("Content-Type", "application/json") + private Request createRequest(@Nonnull String method, @Nonnull String resource, @Nullable String body) { + return new Request.Builder() + .url(this.url + resource) + .addHeader("Accept", "application/json") + .addHeader("Content-Type", "application/json") + .method(method, body != null && !body.isBlank() ? RequestBody.create(body, MediaType.parse("application/json")) : null) .build(); + } - private void validateResponseBody(@Nonnull JsonNode responseBody) throws JsonProcessingException { + private void validateResponseBody(@Nonnull JsonNode responseBody) { Assert.isPremiseValid( responseBody != null && !responseBody.isNull(), "Call to REST server ended with empty data." diff --git a/evita_test_support/src/main/java/module-info.java b/evita_test_support/src/main/java/module-info.java index 284bfc67f..316f3bea7 100644 --- a/evita_test_support/src/main/java/module-info.java +++ b/evita_test_support/src/main/java/module-info.java @@ -33,4 +33,5 @@ requires evita.external.api.graphql; requires evita.external.api.rest; requires evita.external.api.lab; + requires okhttp3; } \ No newline at end of file