βπ[Backend Development] increaseλ©μλ μ€νκ³Όμ λΆμβ
π CommentPath ν΄λμ€.
package kobe.board.comment.entity;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter
@ToString
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentPath {
private String path;
private static final String CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int DEPTH_CHUNK_SIZE = 5;
private static final int MAX_DEPTH = 5;
// MIN_CHUNK = "00000", MAX_CHUNK = "zzzzz"
private static final String MIN_CHUNK = String.valueOf(CHARSET.charAt(0)).repeat(DEPTH_CHUNK_SIZE);
private static final String MAX_CHUNK = String.valueOf(CHARSET.charAt(CHARSET.length() - 1)).repeat(DEPTH_CHUNK_SIZE);
public static CommentPath create(String path) {
if (isDepthOverflowed(path)) {
throw new IllegalStateException("depth overflowed");
}
CommentPath commentPath = new CommentPath();
commentPath.path = path;
return commentPath;
}
private static boolean isDepthOverflowed(String path) {
return calculateDepth(path) > MAX_DEPTH;
}
private static int calculateDepth(String path) {
// 25κ°μ λ¬Έμμ΄ / 5 = 5depth
return path.length() / DEPTH_CHUNK_SIZE;
}
// CommentPath ν΄λμ€μ pathμ depthλ₯Ό ꡬνλ λ§€μλ
public int getDepth() {
return calculateDepth(path);
}
// rootμΈμ§ νμΈνλ λ§€μλ
public boolean isRoot() {
// νμ¬μ depthκ° 1μΈμ§ νμΈν΄μ£Όλ©΄ λ¨
return calculateDepth(path) == 1;
}
// νμ¬ pathμ parentPathλ₯Ό λ°νν΄μ£Όλ λ§€μλ
public String getParentPath() {
// λ 5μλ¦¬λ§ μλΌλ΄λ©΄ λ¨
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE);
}
// νμ¬ pathμ νμ λκΈμ pathμ λ§λλ λ§€μλ
public CommentPath createChildCommentPath(String descendantsTopPath) {
if (descendantsTopPath == null) {
return CommentPath.create(path + MIN_CHUNK);
}
String childrenTopPath = findChildrenTopPath(descendantsTopPath);
return CommentPath.create(increase(childrenTopPath));
}
// 00a0z0000200000 <- descendantsTopPath
private String findChildrenTopPath(String descendantsTopPath) {
return descendantsTopPath.substring(0, (getDepth() + 1) * DEPTH_CHUNK_SIZE);
}
private String increase(String path) {
// pathμμ κ°μ₯ λ§μ§λ§ 5μ리λ₯Ό μλ₯Έ κ²
String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE);
if (isChunkOverflowed(lastChunk)) {
throw new IllegalStateException("chunk overflowed");
}
// Character setμ κΈΈμ΄
int charsetLength = CHARSET.length();
// lastChunkλ₯Ό 10μ§μλ‘ λ¨Όμ λ³ννκΈ° μν κ°μ μ μ₯
int value = 0;
for (char character : lastChunk.toCharArray()) {
value = value * charsetLength + CHARSET.indexOf(character);
System.out.println("value ====> " + value);
System.out.println("CHARSET.indexOf ====> " + CHARSET.indexOf(character));
}
value = value + 1;
String result = "";
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charsetLength) + result;
value /= charsetLength;
}
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE) + result;
}
private boolean isChunkOverflowed(String lastChunk) {
return MAX_CHUNK.equals(lastChunk);
}
}
β 1οΈβ£ μ½λ μ€ν νλ¦ νμΈ
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charsetLength) + result;
value /= charsetLength;
}
π μ½λ ν΅μ¬ μν
- valueλ₯Ό CHARSET(62μ§μ) κΈ°λ°μΌλ‘ DEPTH_CHUNK_SIZE(=5) κΈΈμ΄μ λ¬Έμμ΄λ‘ λ³ννλ κ³Όμ
- κ° λ°λ³΅μμ valueμ λ§μ§λ§ μ리λ₯Ό CHARSETμμ μ°Ύμ λ¬Έμμ΄(result)μ μΆκ°νκ³ , valueλ₯Ό 62λ‘ λλ μ λ€μ λ¬Έμλ₯Ό ꡬν¨.
β 2οΈβ£ descendantsTopPath = β00000β μΌ λ increas(β00000β)μ μ€ν κ³Όμ
π increase(β00000β) μ€ν κ³Όμ
1. lastChunk μΆμΆ
String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE)
- β00000β β lastChunk = β00000β
2. lastChunkλ₯Ό 10μ§μ(value)λ‘ λ³ν
int value = 0;
for (char character : lastChunk.toCharArray()) {
value = value * charsetLength + CHARSET.indexOf(cha)
}
- CHARSET.indexOf(β0β) = 0
- value κ° κ³μ°:
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
value = (0 * 62) + 0 = 0
- μ΅μ’ μ μΌλ‘ value = 0
3. value + 1 μ¦κ°.
value = value + 1;
- value = 0 + 1 = 1
4. valueλ₯Ό λ€μ 62μ§μ λ¬Έμμ΄λ‘ λ³ν
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charserLength) + result;
value /= charsetLength;
}
- λ°λ³΅ κ³Όμ (DEPTH_CHUNK_SIZE = 5)
i = 0: value % 62 = 1 β CHARSET[1] = '1' β result = "1"
i = 1: value /= 62 = 0 β CHARSET[0] = '0' β result = "01"
i = 2: value = 0 β CHARSET[0] = '0' β result = "001"
i = 3: value = 0 β CHARSET[0] = '0' β result = "0001"
i = 4: value = 0 β CHARSET[0] = '0' β result = "00001"
- μ΅μ’ result = β00001β