Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- when updating version, don't forget to update administration-guide.asciidoc -->
<!-- when updating version, don't forget to update
administration-guide.asciidoc -->
<graphql.version>21.5</graphql.version>
<graphql-scalars.version>21.0</graphql-scalars.version>
<graphql-dataloader.version>3.2.2</graphql-dataloader.version>
<graphql-filter.version>3.0.7</graphql-filter.version>
<graphql-filter.version>3.0.8</graphql-filter.version>
<pf4j.version>3.14.1</pf4j.version>
<asm.version>3.3.1</asm.version>
<spring.security.version>6.3.5</spring.security.version>
Expand Down Expand Up @@ -49,7 +50,8 @@
<micrometer.version>1.15.5</micrometer.version>
</properties>

<!-- IMPORTANT: Always keep dependencies in-sync with mesh-plugin-parent pom in order to avoid duplicate libraries in shaded plugin jars -->
<!-- IMPORTANT: Always keep dependencies in-sync with mesh-plugin-parent pom
in order to avoid duplicate libraries in shaded plugin jars -->
<dependencyManagement>
<dependencies>
<!-- Logging -->
Expand Down Expand Up @@ -183,11 +185,11 @@
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Expand All @@ -198,11 +200,11 @@
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Expand Down Expand Up @@ -270,7 +272,7 @@
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.9.0</version>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
Expand All @@ -283,7 +285,7 @@
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
</dependency>
Expand Down Expand Up @@ -381,6 +383,11 @@
<artifactId>vertx-hazelcast</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-json-schema</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-common</artifactId>
Expand Down Expand Up @@ -808,9 +815,9 @@
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.squareup.inject</groupId>
Expand All @@ -833,9 +840,9 @@
<version>${hazelcast-hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>${hibernate.version}</version>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Core: A new field type, `JSON`, has been added. Having a string in its base, it provides such additional functionality, as JSON structure / schema verification, and extended JsonPath filtering in GraphQL requests.
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ node_error_invalid_microschema_field_value=Der Wert für das Feld "{0}" darf nic
node_list_item_not_found=Der in der Liste angegebene Node mit der uuid {0} konnte nicht gefunden werden.
node_update_failed=Aktualisierung des Node "{0}" ist fehlgeschlagen.
node_error_invalid_string_field_value=Das String Feld "{0}" darf nicht mit dem Wert "{1}" befüllt werden.
node_error_invalid_json_field_value=Das JSON Feld "{0}" darf nicht mit dem Wert "{1}" befüllt werden.
node_error_string_field_value_too_long=Das String Feld "{0}" kann höchstens {1} Zeichen enthalten, übergeben wurden {2} Zeichen.
node_conflicting_segmentfield_update=Das Segmentfeld "{0}" kann nicht mit dem Wert "{1}" befüllt werden, weil dieser Wert bereits verwendet wird.
node_conflicting_segmentfield_upload=Die Datei "{1}" kann nicht in das Segmentfeld "{0}" geladen werden, weil der Dateiname bereits verwendet wird.
Expand Down
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ node_error_invalid_schema_field_value=The field "{0}" is not allowed to use sche
node_list_item_not_found=Node within node list with uuid {0} could not be found.
node_update_failed=Update of node "{0}" failed.
node_error_invalid_string_field_value=The string field "{0}" must not be set to value "{1}".
node_error_invalid_json_field_value=The JSON field "{0}" must not be set to value "{1}".
node_error_string_field_value_too_long=The string Feld "{0}" can only hold up to {1} characters, but {2} characters were given.
node_conflicting_segmentfield_update=The segment field "{0}" must not be set to value "{1}" because this value is already used.
node_conflicting_segmentfield_upload=The file "{1}" cannot be uploaded into the segment field "{0}" because the filename is already in use.
Expand Down
1 change: 1 addition & 0 deletions common/src/main/resources/i18n/translations_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ node_error_invalid_microschema_field_value=字段“{0}”的值不得使用内
node_list_item_not_found=在uuid为{0}的节点列表中找不到节点。
node_update_failed=节点“{0}”更新失败。
node_error_invalid_string_field_value=字符串字段“{0}”不得设置为值“{1}”。
node_error_invalid_json_field_value=JSON 字段“{0}”不能设置为值“{1}”。
node_conflicting_segmentfield_update=分节字段“{0}”不得设置为值“{1}”,因为该值已被使用。
node_conflicting_segmentfield_upload=文件“{1}”无法上传到分节字段“{0}”中,因为文件名已被使用。
node_conflicting_segmentfield_move=无法移动节点,因为分节字段“{0}”中的值“{1}”发生冲突。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.hibernate.query.Query;
import org.hibernate.query.internal.QueryOptionsImpl;
import org.hibernate.query.spi.Limit;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.spi.TypeConfiguration;
import org.slf4j.Logger;

Expand All @@ -46,6 +47,7 @@
import com.gentics.mesh.core.data.project.HibProject;
import com.gentics.mesh.core.data.schema.HibFieldSchemaVersionElement;
import com.gentics.mesh.core.rest.common.FieldTypes;
import com.gentics.mesh.core.rest.node.field.JsonContent;
import com.gentics.mesh.database.HibernateTx;
import com.gentics.mesh.etc.config.HibernateMeshOptions;
import com.gentics.mesh.hibernate.MeshTablePrefixStrategy;
Expand Down Expand Up @@ -385,6 +387,11 @@ public String getSqlTypeName(FieldTypes type, String uuidTypeName) {
TypeConfiguration typeConfig = getSessionMetadataIntegrator().getSessionFactoryImplementor().getTypeConfiguration();
Dialect dialect = getHibernateDialect();
switch (type) {
case JSON:
return typeConfig.getDdlTypeRegistry().getTypeName(
SqlTypes.JSON,
new Size(getSqlTypePrecision(type), getSqlTypeScale(type), getSqlTypeLength(type)),
typeConfig.getBasicTypeForJavaType(JsonContent.class));
case STRING:
case HTML:
return typeConfig.getDdlTypeRegistry().getTypeName(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@
<includeAll path="entries-3.0.x" relativeToChangelogFile="true" errorIfMissingOrEmpty="false"/>
<!-- 3.1.x changes -->
<includeAll path="entries-3.1.x" relativeToChangelogFile="true" errorIfMissingOrEmpty="false"/>
<!-- 3.3.x changes -->
<includeAll path="entries-3.3.x" relativeToChangelogFile="true" errorIfMissingOrEmpty="false"/>
</databaseChangeLog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.6.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd">

<property name="json.type" value="NCLOB" dbms="oracle"/>
<property name="json.type" value="JSON" dbms="mariadb,mysql"/>
<property name="json.type" value="TEXT" dbms="postgresql,hsqldb"/>
<property name="json.type" value="NTEXT" dbms="mssql"/>

<changeSet author="s.plyhun@gentics.com" id="gpu-2210-1">
<createTable tableName="mesh_jsonlistitem">
<column name="dbuuid" type="${uuid.type}">
<constraints nullable="false" primaryKey="true" primaryKeyName="mesh_jsonlistitem_pkey"/>
</column>
<column name="containertype" type="${smalltext.type}">
<constraints nullable="false"/>
</column>
<column name="containeruuid" type="${uuid.type}">
<constraints nullable="false"/>
</column>
<column name="containerversionuuid" type="${uuid.type}">
<constraints nullable="false"/>
</column>
<column name="fieldkey" type="${fieldkey.type}">
<constraints nullable="false"/>
</column>
<column name="valueoruuid" type="${largetext.type}"/>
<column name="itemindex" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="listuuid" type="${uuid.type}">
<constraints nullable="false"/>
</column>
</createTable>
<createIndex tableName="mesh_jsonlistitem" indexName="idx_mesh_jsonlistitem_containeruuid_containertype_fieldkey" clustered="false">
<column name="containeruuid" />
<column name="containertype" />
<column name="fieldkey" />
</createIndex>
</changeSet>
</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.dialect.HSQLDialect;
import org.hsqldb.jdbcDriver;

import com.gentics.mesh.etc.config.HibernateMeshOptions;
import com.gentics.mesh.hibernate.dialect.HSQLJsonAwareDialect;

/**
* HSQLDB Mesh database connector
Expand Down Expand Up @@ -47,8 +47,7 @@ protected String getDefaultDriverClassName() {

@Override
protected String getDefaultDialectClassName() {
// TODO Auto-generated method stub
return HSQLDialect.class.getCanonicalName();
return HSQLJsonAwareDialect.class.getCanonicalName();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.gentics.mesh.hibernate.dialect;

import static org.hibernate.type.SqlTypes.JSON;

import java.sql.Types;

import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;

import com.gentics.mesh.database.connector.QueryUtils;

/**
* JSON object supporting (via VARCHAR) dialect of HSQLDB.
*/
public class HSQLJsonAwareDialect extends HSQLDialect {

@Override
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.registerColumnTypes( typeContributions, serviceRegistry );
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "varchar(" + QueryUtils.DEFAULT_STRING_LENGTH + ")", this ) );
}

@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry();
jdbcTypeRegistry.addDescriptorIfAbsent( SqlTypes.JSON, JsonJdbcType.INSTANCE );
super.contributeTypes( typeContributions, serviceRegistry );
}

@Override
public boolean equivalentTypes(int typeCode1, int typeCode2) {
return typeCode1 == Types.LONGVARCHAR && typeCode2 == SqlTypes.JSON
|| typeCode1 == SqlTypes.JSON && typeCode2 == Types.LONGVARCHAR
|| super.equivalentTypes( typeCode1, typeCode2 );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public void handleGetPathField(RoutingContext rc) {
// Check if field is JSON, to set corresponding HTTP header value
String contentType = rc.response().headers().get(HttpHeaders.CONTENT_TYPE);
ac.send(
HttpConstants.APPLICATION_JSON_UTF8.equals(contentType) ? field.toJson(ac.isMinify(options.getHttpServerOptions())) : field.toString(),
(HttpConstants.APPLICATION_JSON_UTF8.equals(contentType) && FieldTypes.valueByName(field.getType()) != FieldTypes.JSON) ? field.toJson(ac.isMinify(options.getHttpServerOptions())) : field.toString(),
HttpResponseStatus.valueOf(rc.response().getStatusCode()),
contentType);
}
Expand Down
14 changes: 10 additions & 4 deletions doc/src/main/hugo/content/docs/building-blocks.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ include::content/docs/api/response{apiLatest}/\{project\}/nodes/\{nodeUuid\}/200

== Schema

Typically, each project will require a set of different content types. Together they can be considered the content model of your project. Staying with the example of a product catalogue website: a product, product category, product image, and product manual each represent a separate content type. In Gentics Mesh, a *schema* is used to define such content types in terms of a couple of standard fields (e.g. ```uuid```, ```name```, ```description```, ```version```, etc.) and an arbitrary number of custom fields. Available <<Schema Field Types,field types>> are ```string```, ```number```, ```HTML```, ```date```, ```binary```, ```list```, ```node```, ```micronode```, ```boolean```. You can think of a schema as a blueprint for new content items.
Typically, each project will require a set of different content types. Together they can be considered the content model of your project. Staying with the example of a product catalogue website: a product, product category, product image, and product manual each represent a separate content type. In Gentics Mesh, a *schema* is used to define such content types in terms of a couple of standard fields (e.g. ```uuid```, ```name```, ```description```, ```version```, etc.) and an arbitrary number of custom fields. Available <<Schema Field Types,field types>> are ```string```, ```number```, ```HTML```, ```date```, ```binary```, ```list```, ```node```, ```micronode```, ```boolean```, ```json```. You can think of a schema as a blueprint for new content items.

TIP: Using the ```container``` property, a schema can be configured to allow for hierarchically structuring nodes. Nodes based on a such a schema may contain child nodes. This is the basis for building link:{{< relref "features.asciidoc" >}}#_contenttrees[content trees] in Gentics Mesh and leveraging the power of automatic link:{{< relref "features.asciidoc" >}}#_navigation[navigation menus], link:{{< relref "features.asciidoc" >}}#_breadcrumbs[breadcrumbs] and link:{{< relref "features.asciidoc" >}}#_prettyurls[pretty URLs].

Expand Down Expand Up @@ -287,6 +287,12 @@ The ```html``` field type stores HTML data.
The ```required``` property indicates if the field is mandatory or not.


===== JSON
The ```json``` field type stores JSON data.
The ```required``` property indicates if the field is mandatory or not.
The optional ```allow``` property acts as a whitelist for allowed field schemas.


===== Micronode
A ```micronode``` field type stores a single micronode. A micronode is similar to a node. Typically they do not exist on their own but are tied to their (parent) node, e.g. a caption to be used in a image node. For a detailed description see our definition of <<micronode>>.
The ```required``` property indicates if the field is mandatory or not.
Expand All @@ -302,7 +308,7 @@ A ```node``` field type must have an ```allow``` property, which acts as a white
===== List
A ```list``` field type allows for specifying a list with elements on the basis of other field types and thus represents a powerful mechanism for building your content model:

(1) Within a node you can have simple lists of arbitrary length. The ```listType``` property then has to be of type ```string```, ```number```, ```date```, ```boolean```, or ```HTML```. E.g. handling your recipe nodes of your food blog will be a breeze with string-typed lists for ingredients.
(1) Within a node you can have simple lists of arbitrary length. The ```listType``` property then has to be of type ```string```, ```number```, ```date```, ```boolean```, ```json```, or ```HTML```. E.g. handling your recipe nodes of your food blog will be a breeze with string-typed lists for ingredients.

(2) You can unleash the power of micronodes, by specifying a list with the ```listType``` property set to ```micronode```, and the ```allow``` property set to the allowed microschemas. For example, besides having title, teaser, date and author fields, your blog post schema could define a content field of type list allowing to insert any of your microschemas (e.g. YouTube Video, Image, Text, Galleries, Google Maps, etc.).

Expand Down Expand Up @@ -399,9 +405,9 @@ Microschemas share the same properties as schemas except for the properties ```d

=== Schema Field Types

In comparison to nodes, micronodes can be built with schema field types ```String```, ```Number```, ```Date```, ```Boolean```, ```HTML```, ```Node```, and ```Lists```.
In comparison to nodes, micronodes can be built with schema field types ```String```, ```Number```, ```Date```, ```Boolean```, ```JSON```, ```HTML```, ```Node```, and ```Lists```.

Fields of type ```list``` in micronodes can be of type: ```String```, ```Number```, ```Date```, ```Boolean```, ```HTML```, and ```Node```.
Fields of type ```list``` in micronodes can be of type: ```String```, ```Number```, ```Date```, ```Boolean```,```JSON``` , ```HTML```, and ```Node```.

== Tag

Expand Down
Loading