Moving to Mongo instead of Postgresql for storage.

This will allow us to store the widget, plugin & page information much more cleanly and directly into the DB.
This commit is contained in:
Arpit Mohan 2019-03-19 12:13:21 +05:30
parent 9cea9f94f2
commit f7aaafacfb
13 changed files with 116 additions and 78 deletions

View File

@ -23,10 +23,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId> <artifactId>spring-boot-starter-cache</artifactId>
</dependency> </dependency>
<dependency> <!--<dependency>-->
<groupId>org.springframework.boot</groupId> <!--<groupId>org.springframework.boot</groupId>-->
<artifactId>spring-boot-starter-data-jpa</artifactId> <!--<artifactId>spring-boot-starter-data-jpa</artifactId>-->
</dependency> <!--</dependency>-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
@ -41,6 +41,10 @@
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>

View File

@ -2,12 +2,12 @@ package com.mobtools.server.configurations;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.mongodb.config.EnableMongoAuditing;
import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers; import reactor.core.scheduler.Schedulers;
@Configuration @Configuration
@EnableJpaAuditing @EnableMongoAuditing
public class CommonConfig { public class CommonConfig {
private String ELASTIC_THREAD_POOL_NAME = "mobtools-elastic-pool"; private String ELASTIC_THREAD_POOL_NAME = "mobtools-elastic-pool";
@ -16,4 +16,5 @@ public class CommonConfig {
public Scheduler scheduler() { public Scheduler scheduler() {
return Schedulers.newElastic(ELASTIC_THREAD_POOL_NAME); return Schedulers.newElastic(ELASTIC_THREAD_POOL_NAME);
} }
} }

View File

@ -0,0 +1,27 @@
package com.mobtools.server.configurations;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
@EnableReactiveMongoRepositories
public class MongoConfig extends AbstractReactiveMongoConfiguration {
@Override
public MongoClient reactiveMongoClient() {
return MongoClients.create();
}
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() throws Exception {
return new ReactiveMongoTemplate(reactiveMongoClient(), "mobtools");
}
@Override
protected String getDatabaseName() {
return "mobtools";
}
}

View File

@ -38,9 +38,9 @@ public class WidgetController extends BaseController {
.map(widget -> new ResponseDto<>(HttpStatus.OK.value(), widget, null)); .map(widget -> new ResponseDto<>(HttpStatus.OK.value(), widget, null));
} }
@PutMapping("") @PutMapping("/{id}")
public Mono<ResponseDto<Widget>> update(@RequestBody Widget widget) throws Exception { public Mono<ResponseDto<Widget>> update(@PathVariable String id, @RequestBody Widget widget) throws Exception {
return widgetService.update(widget) return widgetService.update(id, widget)
.map(updatedWidget -> new ResponseDto<>(HttpStatus.OK.value(), updatedWidget, null)); .map(updatedWidget -> new ResponseDto<>(HttpStatus.OK.value(), updatedWidget, null));
} }

View File

@ -3,45 +3,41 @@ package com.mobtools.server.domains;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate; import org.springframework.data.annotation.*;
import org.springframework.data.annotation.CreatedBy; import org.springframework.data.domain.Persistable;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date; import java.util.Date;
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter @Getter
@Setter @Setter
@ToString @ToString
@DynamicUpdate public abstract class BaseDomain implements Persistable<String> {
public abstract class BaseDomain implements Serializable {
private static final long serialVersionUID = 7459916000501322517L; private static final long serialVersionUID = 7459916000501322517L;
@Temporal(TemporalType.TIMESTAMP) @Id
@Column(nullable = false, updatable = false) private String id;
@CreatedDate @CreatedDate
protected Date createdAt; protected Date createdAt;
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
@LastModifiedDate @LastModifiedDate
protected Date updatedAt; protected Date updatedAt;
@Column
@CreatedBy @CreatedBy
protected String createdBy; protected String createdBy;
@Column
@LastModifiedBy @LastModifiedBy
protected String modifiedBy; protected String modifiedBy;
@Column(nullable = false)
protected Boolean deleted = false; protected Boolean deleted = false;
// @Version
// protected Long version;
@Override
public boolean isNew() {
return this.getId() == null;
}
} }

View File

@ -4,20 +4,15 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.*;
@Entity
@Getter @Getter
@Setter @Setter
@ToString @ToString
@NoArgsConstructor @NoArgsConstructor
@SequenceGenerator(initialValue = 1, name = "tenant_gen", sequenceName = "tenant_gen") @Document
public class Tenant extends BaseDomain { public class Tenant extends BaseDomain {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tenant_gen")
@Column(nullable = false, updatable = false)
private Long id;
private String domain; private String domain;

View File

@ -4,27 +4,17 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.*;
@Entity
// Specially adding the table name here because the keyword "User" is reserved in Postgres
@Table(name = "users")
@Getter @Getter
@Setter @Setter
@ToString @ToString
@NoArgsConstructor @NoArgsConstructor
@SequenceGenerator(initialValue = 1, name = "user_gen", sequenceName = "user_gen") @Document
public class User extends BaseDomain { public class User extends BaseDomain {
@Id
@Column(nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_gen")
private Long id;
@Column
private String name; private String name;
@Column
private String email; private String email;
} }

View File

@ -4,30 +4,19 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.*;
@Entity
@Getter @Getter
@Setter @Setter
@ToString @ToString
@NoArgsConstructor @NoArgsConstructor
@SequenceGenerator(initialValue = 1, name = "widget_gen", sequenceName = "widget_gen") @Document
public class Widget extends BaseDomain { public class Widget extends BaseDomain {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "widget_gen")
@Column(nullable = false, updatable = false)
private Long id;
@Column
private String name; private String name;
@Column
private WidgetType type; private WidgetType type;
@Column
private PricingPlan pricingPlan; private PricingPlan pricingPlan;
} }

View File

@ -1,11 +1,11 @@
package com.mobtools.server.repositories; package com.mobtools.server.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import java.io.Serializable; import java.io.Serializable;
@NoRepositoryBean @NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> { public interface BaseRepository<T, ID extends Serializable> extends ReactiveCrudRepository<T, ID> {
} }

View File

@ -2,9 +2,10 @@ package com.mobtools.server.repositories;
import com.mobtools.server.domains.Widget; import com.mobtools.server.domains.Widget;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
@Repository @Repository
public interface WidgetRepository extends BaseRepository<Widget, Long> { public interface WidgetRepository extends BaseRepository<Widget, Long> {
Widget findByName(String name); Mono<Widget> findByName(String name);
} }

View File

@ -12,5 +12,5 @@ public interface WidgetService {
Mono<Widget> create(Widget widget); Mono<Widget> create(Widget widget);
Mono<Widget> update(Widget widget) throws Exception; Mono<Widget> update(String id, Widget widget) throws Exception;
} }

View File

@ -2,8 +2,15 @@ package com.mobtools.server.services;
import com.mobtools.server.domains.Widget; import com.mobtools.server.domains.Widget;
import com.mobtools.server.repositories.WidgetRepository; import com.mobtools.server.repositories.WidgetRepository;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -15,40 +22,61 @@ public class WidgetServiceImpl extends BaseService implements WidgetService {
private WidgetRepository widgetRepository; private WidgetRepository widgetRepository;
private final MongoConverter mongoConverter;
private final ReactiveMongoTemplate mongoTemplate;
@Autowired @Autowired
public WidgetServiceImpl(Scheduler scheduler, WidgetRepository widgetRepository) { public WidgetServiceImpl(Scheduler scheduler, WidgetRepository widgetRepository, MongoConverter mongoConverter, ReactiveMongoTemplate mongoTemplate) {
super(scheduler); super(scheduler);
this.widgetRepository = widgetRepository; this.widgetRepository = widgetRepository;
this.mongoConverter = mongoConverter;
this.mongoTemplate = mongoTemplate;
} }
@Override @Override
public Mono<Widget> getByName(String name) { public Mono<Widget> getByName(String name) {
return Mono.fromCallable(() -> widgetRepository.findByName(name)) return widgetRepository.findByName(name);
.subscribeOn(scheduler);
} }
@Override @Override
public Flux<Widget> get() { public Flux<Widget> get() {
return Mono.fromCallable(() -> widgetRepository.findAll()) return widgetRepository.findAll();
.flatMapMany(Flux::fromIterable)
.subscribeOn(scheduler);
} }
@Override @Override
public Mono<Widget> create(Widget widget) { public Mono<Widget> create(Widget widget) {
return Mono.fromCallable(
() -> widgetRepository.save(widget) return widgetRepository.save(widget);
).subscribeOn(this.scheduler);
} }
@Override @Override
public Mono<Widget> update(Widget widget) throws Exception { public Mono<Widget> update(String id, Widget widget) throws Exception {
if(widget.getId() == null) { if (id == null) {
throw new Exception("Invalid id provided"); throw new Exception("Invalid id provided");
} }
return Mono.fromCallable( Query query = new Query();
() -> widgetRepository.save(widget) query.addCriteria(Criteria.where("id").is(id));
).subscribeOn(this.scheduler);
Update updateObj = new Update();
// DBObject update = getDbObject(widget);
// Map<String, Object> updateMap = update.toMap();
// updateMap.entrySet().stream().forEach(entry -> {
// updateObj.set(entry.getKey(), entry.getValue());
// });
updateObj.set("name", "testName");
mongoTemplate.updateFirst(query,updateObj, Widget.class);
return widgetRepository.save(widget);
}
private DBObject getDbObject(Object o) {
BasicDBObject basicDBObject = new BasicDBObject();
mongoConverter.write(o, basicDBObject);
return basicDBObject;
} }
} }

View File

@ -14,3 +14,10 @@ spring.jpa.show-sql=true
# Jackson Properties # Jackson Properties
spring.jackson.default-property-inclusion=non_null spring.jackson.default-property-inclusion=non_null
#Mongo properties
spring.data.mongodb.database=mobtools
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
#spring.data.mongodb.username=
#spring.data.mongodb.password=