카멜 케이스에서 스네이크로 변환하는 함수 만들기
카멜 케이스와 스네이크 케이스간 변환을 해야하는 일이 생각외로 많다.
데이터베이스의 컬럼과 서비스 로직에서 사용하는 객체간 미묘한 케이스 차이가 그 대표적 예이다.
id | email | user_type | is_subscribe
---------------------------------------------------------
1 | 1ilsang@naver.com | admin | Y
위와 같은 컬럼이 있을 때 DB 에서 값을 가져오면 user_type
, is_subscribe
와 같은 값들이 떨어진다. 물론 as
로 디비에서 카멜로 변경해서 내려줘도 되지만 여기선 바로 가져쓸 때를 가정하겠다.
이때 굳이 카멜로 변경하게 될 경우 아래와 같이 된다.
const {
id,
email,
user_type: userType,
is_subscribe: isSubscribe
} = await Models.getEmailTableById(1);
이러면 컬럼마다 매핑 해주어야 하는 불편함이 있다.
그래서 간단한 변환 함수를 만들어 보았다.
/**
* @params string
* lecture -> lecture
* lectureOption -> lecture_option
* lectureOptionType -> lecture_option_type
*
* else: throw new Error
*/
stringCamelToSnake(str) {
// string 객체가 아닌 녀석들을 걸러줍니다.
if (!str || typeof str !== 'string') throw new Error('Input type must be an [String]');
// 카멜 케이스 공식에 어긋나는 녀석들을 걸러줍니다: 영숫자로 되어 있지 않으며 대문자가 연속되는 녀석들(e.x. leCTURe, Lec, leC)
const dustPattern = str.match(/[^a-zA-Z0-9]|[A-Z][A-Z]+/g) || [];
const edgeCase = str[0].charCodeAt(0) < 97 || str[str.length - 1].charCodeAt(0) < 97;
if (dustPattern.length > 0 || edgeCase) throw new Error('Input string is not Camel case.');
const splitStringArray = [];
let prevIdx = 0;
Array.from(str).forEach((e, idx) => {
if(e.charCodeAt(0) < 97) {
const value = `${str.slice(prevIdx, idx)}_${e.toLowerCase()}`;
splitStringArray.push(value);
prevIdx = idx + 1;
}
});
// 대문자 기준으로 넣었기 때문에 마지막 대문자 이후의 나머지들을 푸쉬 해줍니다.
splitStringArray.push(str.substring(prevIdx));
// [result, _query, _items] => result_query_items
const ret = splitStringArray.join('');
return ret;
}
원래는 matchall
를 사용해 iterator
로 만들려고 했는데 노드 10에선 안된다 -_-; 그래서 걍 보편적으로 사용할 수 있게 forEach
로 돌렸다.
현재는 string
값만 변환하고 있는데 객체의 property
를 변환하고 싶다면 동일한 로직에서 Object.keys()
를 순회하면서 새로운 객체에 담아주면 된다.
그럼 이만.