11package com .featureprobe .api .service ;
22
33import com .featureprobe .api .base .constants .MessageKey ;
4+ import com .featureprobe .api .base .util .JsonMapper ;
5+ import com .featureprobe .api .dao .entity .SegmentVersion ;
46import com .featureprobe .api .dao .exception .ResourceConflictException ;
57import com .featureprobe .api .dao .exception .ResourceNotFoundException ;
8+ import com .featureprobe .api .dao .repository .SegmentVersionRepository ;
69import com .featureprobe .api .dao .utils .PageRequestUtil ;
710import com .featureprobe .api .dto .SegmentCreateRequest ;
11+ import com .featureprobe .api .dto .SegmentPublishRequest ;
812import com .featureprobe .api .dto .SegmentResponse ;
913import com .featureprobe .api .dto .SegmentSearchRequest ;
1014import com .featureprobe .api .dto .SegmentUpdateRequest ;
15+ import com .featureprobe .api .dto .SegmentVersionRequest ;
16+ import com .featureprobe .api .dto .SegmentVersionResponse ;
1117import com .featureprobe .api .dto .ToggleSegmentResponse ;
1218import com .featureprobe .api .dao .entity .Environment ;
1319import com .featureprobe .api .dao .entity .Project ;
2632import com .featureprobe .api .dao .repository .TargetingSegmentRepository ;
2733import com .featureprobe .api .dao .repository .ToggleRepository ;
2834import com .featureprobe .api .base .model .PaginationRequest ;
35+ import com .featureprobe .api .mapper .SegmentVersionMapper ;
2936import lombok .AllArgsConstructor ;
3037import lombok .extern .slf4j .Slf4j ;
3138import org .apache .commons .collections4 .CollectionUtils ;
3643import org .springframework .data .domain .Sort ;
3744import org .springframework .data .jpa .domain .Specification ;
3845import org .springframework .stereotype .Service ;
46+ import org .springframework .transaction .annotation .Transactional ;
3947
4048import javax .persistence .EntityManager ;
4149import javax .persistence .PersistenceContext ;
4250import javax .persistence .criteria .Predicate ;
51+ import java .util .Collections ;
4352import java .util .List ;
4453import java .util .Optional ;
4554import java .util .Set ;
@@ -61,6 +70,9 @@ public class SegmentService {
6170 private EnvironmentRepository environmentRepository ;
6271
6372 private ProjectRepository projectRepository ;
73+
74+ private SegmentVersionRepository segmentVersionRepository ;
75+
6476 private ChangeLogService changeLogService ;
6577
6678 @ PersistenceContext
@@ -79,30 +91,68 @@ public SegmentResponse create(String projectKey, SegmentCreateRequest createRequ
7991 Segment segment = SegmentMapper .INSTANCE .requestToEntity (createRequest );
8092 segment .setProjectKey (projectKey );
8193 segment .setUniqueKey (StringUtils .join (projectKey , "$" , createRequest .getKey ()));
82- if ( CollectionUtils . isNotEmpty ( project . getEnvironments ())) {
83- for ( Environment environment : project . getEnvironments ()) {
84- changeLogService . create ( environment , ChangeLogType . CHANGE );
85- }
86- }
87- return SegmentMapper .INSTANCE .entityToResponse (segmentRepository . save ( segment ) );
94+ segment . setRules ( JsonMapper . toJSONString ( Collections . emptyList ()));
95+ segment . setVersion ( 1L );
96+ saveSegmentChangeLog ( project );
97+ Segment savedSegment = segmentRepository . save ( segment );
98+ saveSegmentVersion ( buildSegmentVersion ( savedSegment , null , null ));
99+ return SegmentMapper .INSTANCE .entityToResponse (savedSegment );
88100 }
89101
102+ @ Transactional (rollbackFor = Exception .class )
90103 public SegmentResponse update (String projectKey , String segmentKey , SegmentUpdateRequest updateRequest ) {
91- Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey );
104+ Project project = projectRepository .findByKey (projectKey ).orElseThrow (() ->
105+ new ResourceNotFoundException (ResourceType .PROJECT , projectKey ));
106+ Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey ).orElseThrow (() ->
107+ new ResourceNotFoundException (ResourceType .SEGMENT , projectKey + "_" + segmentKey ));
92108 if (!StringUtils .equals (segment .getName (), updateRequest .getName ())) {
93109 validateName (projectKey , updateRequest .getName ());
94110 }
95111 SegmentMapper .INSTANCE .mapEntity (updateRequest , segment );
112+ saveSegmentChangeLog (project );
96113 return SegmentMapper .INSTANCE .entityToResponse (segmentRepository .save (segment ));
97114 }
98115
116+ @ Transactional (rollbackFor = Exception .class )
117+ public SegmentResponse publish (String projectKey , String segmentKey , SegmentPublishRequest publishRequest ) {
118+ Project project = projectRepository .findByKey (projectKey ).orElseThrow (() ->
119+ new ResourceNotFoundException (ResourceType .PROJECT , projectKey ));
120+ Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey ).orElseThrow (() ->
121+ new ResourceNotFoundException (ResourceType .SEGMENT , projectKey + "_" + segmentKey ));
122+ Long oldVersion = segment .getVersion ();
123+ SegmentMapper .INSTANCE .mapEntity (publishRequest , segment );
124+ Segment updatedSegment = segmentRepository .saveAndFlush (segment );
125+ if (updatedSegment .getVersion () > oldVersion ) {
126+ saveSegmentVersion (buildSegmentVersion (updatedSegment , publishRequest .getComment (), null ));
127+ }
128+ saveSegmentChangeLog (project );
129+ return SegmentMapper .INSTANCE .entityToResponse (updatedSegment );
130+ }
131+
132+ private void saveSegmentChangeLog (Project project ) {
133+ if (CollectionUtils .isNotEmpty (project .getEnvironments ())) {
134+ for (Environment environment : project .getEnvironments ()) {
135+ changeLogService .create (environment , ChangeLogType .CHANGE );
136+ }
137+ }
138+ }
139+
140+ public Page <SegmentVersionResponse > versions (String projectKey , String segmentKey ,
141+ SegmentVersionRequest versionRequest ) {
142+ Specification <SegmentVersion > spec = buildVersionsQuerySpec (projectKey , segmentKey );
143+ Page <SegmentVersion > versions = segmentVersionRepository .findAll (spec ,
144+ PageRequestUtil .toPageable (versionRequest , Sort .Direction .DESC , "version" ));
145+ return versions .map (version -> SegmentVersionMapper .INSTANCE .entityToResponse (version ));
146+ }
147+
99148 public SegmentResponse delete (String projectKey , String segmentKey ) {
100149 Project project = projectRepository .findByKey (projectKey ).orElseThrow (() ->
101150 new ResourceNotFoundException (ResourceType .PROJECT , projectKey ));
102151 if (targetingSegmentRepository .countByProjectKeyAndSegmentKey (projectKey , segmentKey ) > 0 ) {
103152 throw new IllegalArgumentException (MessageKey .USING );
104153 }
105- Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey );
154+ Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey ).orElseThrow (() ->
155+ new ResourceNotFoundException (ResourceType .SEGMENT , projectKey + "_" + segmentKey ));
106156 segment .setDeleted (true );
107157 if (CollectionUtils .isNotEmpty (project .getEnvironments ())) {
108158 for (Environment environment : project .getEnvironments ()) {
@@ -142,10 +192,25 @@ public Page<ToggleSegmentResponse> usingToggles(String projectKey, String segmen
142192 }
143193
144194 public SegmentResponse queryByKey (String projectKey , String segmentKey ) {
145- Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey );
195+ Segment segment = segmentRepository .findByProjectKeyAndKey (projectKey , segmentKey ).orElseThrow (() ->
196+ new ResourceNotFoundException (ResourceType .SEGMENT , projectKey + "_" + segmentKey ));
146197 return SegmentMapper .INSTANCE .entityToResponse (segment );
147198 }
148199
200+ private SegmentVersion buildSegmentVersion (Segment segment , String comment , Long approvalId ) {
201+ SegmentVersion segmentVersion = new SegmentVersion ();
202+ segmentVersion .setVersion (segment .getVersion ());
203+ segmentVersion .setKey (segment .getKey ());
204+ segmentVersion .setRules (segment .getRules ());
205+ segmentVersion .setComment (comment );
206+ segmentVersion .setApprovalId (approvalId );
207+ segmentVersion .setProjectKey (segment .getProjectKey ());
208+ return segmentVersion ;
209+ }
210+ private void saveSegmentVersion (SegmentVersion segmentVersion ) {
211+ segmentVersionRepository .save (segmentVersion );
212+ }
213+
149214 private Specification <Segment > buildQuerySpec (String projectKey , String keyword ) {
150215 return (root , query , cb ) -> {
151216 Predicate p3 = cb .equal (root .get ("projectKey" ), projectKey );
@@ -166,6 +231,15 @@ private Page<SegmentResponse> findPagingBySpec(Specification<Segment> spec, Page
166231 return segments .map (segment -> SegmentMapper .INSTANCE .entityToResponse (segment ));
167232 }
168233
234+
235+ private Specification <SegmentVersion > buildVersionsQuerySpec (String projectKey , String key ) {
236+ return (root , query , cb ) -> {
237+ Predicate p1 = cb .equal (root .get ("projectKey" ), projectKey );
238+ Predicate p2 = cb .equal (root .get ("key" ), key );
239+ return query .where (cb .and (p1 , p2 )).getRestriction ();
240+ };
241+ }
242+
169243 public void validateExists (String projectKey , ValidateTypeEnum type , String value ) {
170244 switch (type ) {
171245 case KEY :
0 commit comments