Vapor버전 4.0을 기준으로 작성된 게시글입니다!
데이터베이스를 사용하다보면
테이블에 새로운 컬럼을 추가할 때가 있거나 삭제할 때가 있어요
그럴때 수정을 데이터베이스에서 안하고 vapor에서 Fluent를 이용해서 코드로 할 수 있다고 하네요!
Create
이미 존재하는 이름이 있는 경우 에러를 발생 시킬 우려가 있어요
ignoreExisting을 이용해서 이미있다면 무시할 수 있도록 해주세요
database.schema("planets")
.id()
.field("name", .string, .required)
.create()
planets테이블을 만들껀데
id
name
의 컬럼을 만들어 주는 거고
이때 name은 String타입으로 무조건 값이 필요한 속성으로 만든거에요
Field를 만들때
required - nil 불가능
references - 외래키
identifier - primary key
조건이 있구요
Update
이미 적용된 코드가 있다면 그 코드를 포함한 아래의 코드 모두 적용되지 않아요
즉, 변경사항이 있어야만 코드가 동작한다는 소리에요
// 기존 planets 테이블에 'size'라는 필드하나추가하는 코드
db.schema("planets")
.field("size", .int)
.update()
// 실패코드
// id가 이미 있으므로 실행되지않음
db.schema("planets")
.id()
.field("size", .int)
.update()
여기서 주의해야할 헷갈리는 개념이 있는데
updateField와 field가 있어요
updateField는 필드의 데이터타입을 변경할 때 사용
field는 스키마를 추가할때 사용
을 지켜줘야해요
Delete
스키마(테이블)을 삭제하는코드와
스키마의 필드만 삭제하는 코드로 구분해서 사용해요
// 스키마 삭제(db table삭제)
db.schema("planets").delete()
// 필드삭제(해당이름의 컬럼 삭제)
db.schema("planets")
.deleteField("age")
.update()
Unique
중복된 값을 허용하지 않는 필드를 만들때 사용해요
db.schema("planets")
.updateField("name", .string)
.unique(on: "name")
.update()
JsonType
커스텀 구조체타입에 Codable 프로토콜을 준수하면 필드타입으로 사용할 수 있어요
타입을 지정할땐 dictionary타입으로만 사용하면되요
이미 있는 자료형인경우는 dictionary(of: 자료형타입)을 사용하면되구요
마찬가지로 배열도 저장할 수 있어요
db.schema("planets")
.updateField("name", .string)
.field("arr", .array(of: .string))
.field("dic", .dictionary(of: .int))
.field("type", .dictionary)
.update()
모두 json타입으로 생성된걸 볼 수 있어요
Enum
열거형 타입도 디비에 저장할 수 있어요
db.enum("planet_type")
.case("one")
.case("two")
.case("three")
.create()
one, two, three라는 케이스를 만들고
db.enum("planet_type").read().flatMap { type in
db.schema("planets")
.field("enumType", type, .required)
.update()
}
planet_type에 해당하는 열거형을 read()를 이용해서 읽어오면
등록한 케이스인 one, two, three를 다 읽어오고
enumType이라는 필드에 해당 타입을 지정해주는거에요
이렇게 스키마를 변경할 때
마이그레이션이라는 기능을 지원해줘요
마이그레이션이란
간단하게 디비의 변경사항들을 기록해놓는 역할이라고 생각하면되요
변경할 사항들을 구현하고
실패시 행동할 사항을 구현해요
Migration 프로토콜을 채택해준 구조체를 만들어주고
struct GalaxyMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
database.schema("galaxies")
.field("age", .int)
.update()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database.schema("galaxies").delete()
}
}
prepare에 변경될 사항
revert에 실패시 되돌릴 사항을 적어주고
코드에 방금만드 구조체를 이용해서 마이그레이션을 추가해주세요
app.migrations.add(GalaxyMigration())
저같은경우는
디비를 접속하는 부분에 추가를 해줬어요
private func setUpMySQL(_ app: Application) throws {
app.databases.use(
.mysql(
hostname: "localhost",
username: "root",
password: "",
database: "vapor",
tlsConfiguration: .forClient(certificateVerification: .none)
), as: .mysql)
app.migrations.add(GalaxyMigration())
}
터미널로 가서
// 마이그레이션시
vapor run migrate
// 되돌리기시
vapor run migrate --revert
원하는 명령어를 실행하면
해당 코드가 실행된것을 볼 수 있어요
이때 생각하는 헷갈린점이 있어요
처음에 스키마를 생성하는 코드와
마이그레이션 코드는 무엇이다를까...?!
구조체를 이용해서 한다는거 빼고는 코드는 같아요
func prepare(on database: Database) -> EventLoopFuture<Void> {
database.schema("galaxies")
.field("age", .int)
.update()
}
database.schema("galaxies")
.field("age", .int)
.update()
이 코드만 실행시켜도 동작은 같거든요
마이그레이션으로 얻을 수 있는 이득에는
생성하거나 수정하는 코드를 그냥하지않고 마이그레이션 코드에 담아서 안전하게 할 수 있는 장점이 있다고
생각되네요!
'iyOmSd > Title: Vapor' 카테고리의 다른 글
[Vapor] MySQL 연동 및 데이터 CRUD (Fluent) (0) | 2021.03.06 |
---|---|
[Vapor] Validation 유효성검사 (0) | 2021.03.06 |
[Vapor] Routing (경로 설정, Data받아오기) (0) | 2021.03.06 |
[Vapor] 프로젝트 기본설정 및 설치 (2) | 2021.03.06 |