diff --git a/jnosql-mapping/jnosql-mapping-semistructured/.gitignore b/jnosql-mapping/jnosql-mapping-semistructured/.gitignore
new file mode 100644
index 000000000..defb1dc0b
--- /dev/null
+++ b/jnosql-mapping/jnosql-mapping-semistructured/.gitignore
@@ -0,0 +1,15 @@
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+test-output/
+/doc
+*.iml
+*.log
+.classpath
+-project
+/.resourceCache
+/.project
+/.idea
+.settings/
diff --git a/jnosql-mapping/jnosql-mapping-semistructured/pom.xml b/jnosql-mapping/jnosql-mapping-semistructured/pom.xml
new file mode 100644
index 000000000..68d4f8fa2
--- /dev/null
+++ b/jnosql-mapping/jnosql-mapping-semistructured/pom.xml
@@ -0,0 +1,46 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.jnosql.mapping
+ jnosql-mapping-parent
+ 1.1.1-SNAPSHOT
+
+
+ jnosql-mapping-column
+ jar
+
+
+
+ org.eclipse.jnosql.communication
+ jnosql-communication-column
+ ${project.version}
+
+
+ ${project.groupId}
+ jnosql-mapping-core
+ ${project.version}
+
+
+ jakarta.nosql
+ nosql-column
+ ${jakarta.nosql.version}
+
+
+
+
diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractColumnTemplate.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractColumnTemplate.java
new file mode 100644
index 000000000..2f9329164
--- /dev/null
+++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractColumnTemplate.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2022 Contributors to the Eclipse Foundation
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
+ *
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ *
+ * Otavio Santana
+ */
+package org.eclipse.jnosql.mapping.column;
+
+
+import jakarta.data.exceptions.NonUniqueResultException;
+import jakarta.nosql.PreparedStatement;
+import jakarta.nosql.QueryMapper;
+import jakarta.nosql.column.ColumnTemplate;
+import org.eclipse.jnosql.communication.column.ColumnDeleteQuery;
+import org.eclipse.jnosql.communication.column.ColumnEntity;
+import org.eclipse.jnosql.communication.column.ColumnManager;
+import org.eclipse.jnosql.communication.column.ColumnObserverParser;
+import org.eclipse.jnosql.communication.column.ColumnQuery;
+import org.eclipse.jnosql.communication.column.ColumnQueryParser;
+import org.eclipse.jnosql.mapping.core.Converters;
+import org.eclipse.jnosql.mapping.IdNotFoundException;
+import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata;
+import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
+import org.eclipse.jnosql.mapping.metadata.FieldMetadata;
+import org.eclipse.jnosql.mapping.core.util.ConverterUtil;
+import org.eclipse.jnosql.mapping.metadata.InheritanceMetadata;
+
+import java.time.Duration;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * The template method to {@link ColumnTemplate}
+ */
+public abstract class AbstractColumnTemplate implements JNoSQLColumnTemplate {
+
+ private static final ColumnQueryParser PARSER = new ColumnQueryParser();
+
+ protected abstract ColumnEntityConverter getConverter();
+
+ protected abstract ColumnManager getManager();
+
+ protected abstract ColumnEventPersistManager getEventManager();
+
+ protected abstract EntitiesMetadata getEntities();
+
+ protected abstract Converters getConverters();
+
+ private final UnaryOperator insert = e -> getManager().insert(e);
+
+ private final UnaryOperator update = e -> getManager().update(e);
+
+ private ColumnObserverParser observer;
+
+
+ private ColumnObserverParser getObserver() {
+ if (Objects.isNull(observer)) {
+ observer = new ColumnMapperObserver(getEntities());
+ }
+ return observer;
+ }
+
+ @Override
+ public T insert(T entity) {
+ requireNonNull(entity, "entity is required");
+ return persist(entity, insert);
+ }
+
+
+ @Override
+ public T insert(T entity, Duration ttl) {
+ requireNonNull(entity, "entity is required");
+ requireNonNull(ttl, "ttl is required");
+ return persist(entity, e -> getManager().insert(e, ttl));
+ }
+
+
+ @Override
+ public T update(T entity) {
+ requireNonNull(entity, "entity is required");
+ return persist(entity, update);
+ }
+
+ @Override
+ public Iterable update(Iterable entities) {
+ requireNonNull(entities, "entity is required");
+ return StreamSupport.stream(entities.spliterator(), false)
+ .map(this::update).collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterable insert(Iterable entities) {
+ requireNonNull(entities, "entities is required");
+ return StreamSupport.stream(entities.spliterator(), false)
+ .map(this::insert).collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterable insert(Iterable entities, Duration ttl) {
+ requireNonNull(entities, "entities is required");
+ requireNonNull(ttl, "ttl is required");
+ return StreamSupport.stream(entities.spliterator(), false)
+ .map(e -> insert(e, ttl))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void delete(ColumnDeleteQuery query) {
+ requireNonNull(query, "query is required");
+ getManager().delete(query);
+ }
+
+
+ @Override
+ public Stream select(ColumnQuery query) {
+ requireNonNull(query, "query is required");
+ return executeQuery(query);
+ }
+
+ @Override
+ public long count(ColumnQuery query) {
+ return getManager().count(query);
+ }
+
+ @Override
+ public boolean exists(ColumnQuery query) {
+ return getManager().exists(query);
+ }
+
+ @Override
+ public Optional singleResult(ColumnQuery query) {
+ requireNonNull(query, "query is required");
+ final Stream select = select(query);
+
+ final Iterator iterator = select.iterator();
+
+ if (!iterator.hasNext()) {
+ return Optional.empty();
+ }
+ final T entity = iterator.next();
+
+ if (!iterator.hasNext()) {
+ return Optional.of(entity);
+ }
+ throw new NonUniqueResultException("No Unique result found to the query: " + query);
+ }
+
+ @Override
+ public Optional find(Class type, K id) {
+ requireNonNull(type, "type is required");
+ requireNonNull(id, "id is required");
+ EntityMetadata entityMetadata = getEntities().get(type);
+ FieldMetadata idField = entityMetadata.id()
+ .orElseThrow(() -> IdNotFoundException.newInstance(type));
+
+ Object value = ConverterUtil.getValue(id, entityMetadata, idField.fieldName(), getConverters());
+ ColumnQuery query = ColumnQuery.select().from(entityMetadata.name())
+ .where(idField.name()).eq(value).build();
+
+ return singleResult(query);
+ }
+
+ @Override
+ public void delete(Class type, K id) {
+ requireNonNull(type, "type is required");
+ requireNonNull(id, "id is required");
+
+ EntityMetadata entityMetadata = getEntities().get(type);
+ FieldMetadata idField = entityMetadata.id()
+ .orElseThrow(() -> IdNotFoundException.newInstance(type));
+ Object value = ConverterUtil.getValue(id, entityMetadata, idField.fieldName(), getConverters());
+
+ ColumnDeleteQuery query = ColumnDeleteQuery.delete().from(entityMetadata.name())
+ .where(idField.name()).eq(value).build();
+ getManager().delete(query);
+ }
+
+
+ @Override
+ public Stream query(String query) {
+ requireNonNull(query, "query is required");
+ return PARSER.query(query, getManager(), getObserver()).map(c -> getConverter().toEntity(c));
+ }
+
+ @Override
+ public Optional singleResult(String query) {
+ Stream entities = query(query);
+ final Iterator iterator = entities.iterator();
+
+ if (!iterator.hasNext()) {
+ return Optional.empty();
+ }
+ final T entity = iterator.next();
+ if (!iterator.hasNext()) {
+ return Optional.of(entity);
+ }
+ throw new NonUniqueResultException("No unique result found to the query: " + query);
+ }
+
+ @Override
+ public PreparedStatement prepare(String query) {
+ return new ColumnPreparedStatement(PARSER.prepare(query, getManager(), getObserver()), getConverter());
+ }
+
+
+ @Override
+ public long count(String columnFamily) {
+ return getManager().count(columnFamily);
+ }
+
+
+ @Override
+ public long count(Class type) {
+ requireNonNull(type, "entity class is required");
+ return getManager().count(findAllQuery(type));
+ }
+
+ private Stream executeQuery(ColumnQuery query) {
+ requireNonNull(query, "query is required");
+ Stream entities = getManager().select(query);
+ Function function = e -> getConverter().toEntity(e);
+ return entities.map(function).peek(getEventManager()::firePostEntity);
+ }
+
+ @Override
+ public QueryMapper.MapperFrom select(Class type) {
+ Objects.requireNonNull(type, "type is required");
+ EntityMetadata metadata = getEntities().get(type);
+ return new ColumnMapperSelect(metadata, getConverters(), this);
+ }
+
+ @Override
+ public QueryMapper.MapperDeleteFrom delete(Class type) {
+ Objects.requireNonNull(type, "type is required");
+ EntityMetadata metadata = getEntities().get(type);
+ return new ColumnMapperDelete(metadata, getConverters(), this);
+ }
+
+ @Override
+ public Stream findAll(Class type) {
+ Objects.requireNonNull(type, "type is required");
+ return select(findAllQuery(type));
+ }
+
+ @Override
+ public void deleteAll(Class type) {
+ Objects.requireNonNull(type, "type is required");
+ EntityMetadata metadata = getEntities().get(type);
+ if(metadata.inheritance().isPresent()){
+ InheritanceMetadata inheritanceMetadata = metadata.inheritance().orElseThrow();
+ if(!inheritanceMetadata.parent().equals(metadata.type())){
+ getManager().delete(ColumnDeleteQuery.delete().from(metadata.name())
+ .where(inheritanceMetadata.discriminatorColumn())
+ .eq(inheritanceMetadata.discriminatorValue()).build());
+ return;
+ }
+ }
+ getManager().delete(ColumnDeleteQuery.delete().from(metadata.name()).build());
+ }
+
+ protected T persist(T entity, UnaryOperator persistAction) {
+ return Stream.of(entity)
+ .map(toUnary(getEventManager()::firePreEntity))
+ .map(getConverter()::toColumn)
+ .map(persistAction)
+ .map(t -> getConverter().toEntity(entity, t))
+ .map(toUnary(getEventManager()::firePostEntity))
+ .findFirst()
+ .orElseThrow();
+ }
+
+ private UnaryOperator toUnary(Consumer consumer) {
+ return t -> {
+ consumer.accept(t);
+ return t;
+ };
+ }
+
+ private ColumnQuery findAllQuery(Class type){
+ EntityMetadata metadata = getEntities().get(type);
+
+ if(metadata.inheritance().isPresent()){
+ InheritanceMetadata inheritanceMetadata = metadata.inheritance().orElseThrow();
+ if(!inheritanceMetadata.parent().equals(metadata.type())){
+ return ColumnQuery.select().from(metadata.name())
+ .where(inheritanceMetadata.discriminatorColumn()).eq(inheritanceMetadata.discriminatorValue()).build();
+ }
+ }
+ return ColumnQuery.select().from(metadata.name()).build();
+ }
+}
diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractMapperQuery.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractMapperQuery.java
new file mode 100644
index 000000000..44bcda20b
--- /dev/null
+++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/column/AbstractMapperQuery.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2022 Contributors to the Eclipse Foundation
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
+ *
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ *
+ * Otavio Santana
+ */
+package org.eclipse.jnosql.mapping.column;
+
+import org.eclipse.jnosql.communication.column.Column;
+import org.eclipse.jnosql.communication.column.ColumnCondition;
+import org.eclipse.jnosql.mapping.core.Converters;
+import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
+import org.eclipse.jnosql.mapping.core.util.ConverterUtil;
+
+import java.util.List;
+import java.util.stream.StreamSupport;
+
+import static java.util.Arrays.asList;
+import static java.util.Objects.nonNull;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
+
+abstract class AbstractMapperQuery {
+
+ protected final String columnFamily;
+
+ protected boolean negate;
+
+ protected ColumnCondition condition;
+
+ protected boolean and;
+
+ protected String name;
+
+ protected transient final EntityMetadata mapping;
+
+ protected transient final Converters converters;
+
+ protected transient final JNoSQLColumnTemplate template;
+
+ protected long start;
+
+ protected long limit;
+
+
+ AbstractMapperQuery(EntityMetadata mapping, Converters converters, JNoSQLColumnTemplate template) {
+ this.mapping = mapping;
+ this.converters = converters;
+ this.columnFamily = mapping.name();
+ this.template = template;
+ mapping.inheritance().ifPresent(i -> {
+ if(!i.parent().equals(mapping.type())){
+ this.condition = ColumnCondition.eq(Column.of(i.discriminatorColumn(), i.discriminatorValue()));
+ this.and = true;
+ }
+ });
+ }
+
+ protected void appendCondition(ColumnCondition incomingCondition) {
+ ColumnCondition columnCondition = getColumnCondition(incomingCondition);
+
+ if (nonNull(condition)) {
+ this.condition = and ? this.condition.and(columnCondition) : this.condition.or(columnCondition);
+ } else {
+ this.condition = columnCondition;
+ }
+
+ this.negate = false;
+ this.name = null;
+ }
+
+ protected void betweenImpl(T valueA, T valueB) {
+ requireNonNull(valueA, "valueA is required");
+ requireNonNull(valueB, "valueB is required");
+ ColumnCondition newCondition = ColumnCondition
+ .between(Column.of(mapping.columnField(name), asList(getValue(valueA), getValue(valueB))));
+ appendCondition(newCondition);
+ }
+
+
+ protected void inImpl(Iterable values) {
+
+ requireNonNull(values, "values is required");
+ List