· 5 years ago · May 11, 2020, 01:10 PM
1import Foundation
2import Vapor
3import Fluent
4
5// MARK: - Language Model
6
7final class Language: Model, Content {
8
9 // MARK: Constants
10
11 static let schema = #"languages"#
12
13 // MARK: Properties
14
15 @ID(key: .id)
16 var id: UUID?
17
18 @Field(key: .name)
19 var name: String
20
21 @Field(key: .code)
22 var code: String
23
24 @Siblings(
25 through: SiteLanguage.self,
26 from: \.$language,
27 to: \.$site
28 )
29 var sites: [Site]
30
31 @Timestamp(
32 key: .createdAt,
33 on: .create
34 )
35 var createdAt: Date?
36
37 // MARK: Initializers
38
39 init() {}
40
41 init(
42 id: UUID? = nil,
43 name: String,
44 code: String
45 ) {
46 self.id = id
47 self.name = name
48 self.code = code
49 }
50
51}
52
53// MARK: - Site Model
54
55final class Site: Model, Content {
56
57 // MARK: Constants
58
59 static let schema = #"sites"#
60
61 // MARK: Properties
62
63 @ID(key: .id)
64 var id: UUID?
65
66 @Field(key: .name)
67 var name: String
68
69 @Field(key: .summary)
70 var summary: String
71
72 @Field(key: .url)
73 var url: String
74
75 @Field(key: .yearStart)
76 var yearStart: Int
77
78 @Field(key: .yearEnd)
79 var yearEnd: Int?
80
81 @Field(key: .idGA)
82 var idGA: String
83
84 @Field(key: .idGTM)
85 var idGTM: String
86
87 @Siblings(
88 through: SiteLanguage.self,
89 from: \.$site,
90 to: \.$language
91 )
92 var languages: [Language]
93
94 @Timestamp(
95 key: .createdAt,
96 on: .create
97 )
98 var createdAt: Date?
99
100 @Timestamp(
101 key: .updatedAt,
102 on: .update
103 )
104 var updatedAt: Date?
105
106 // MARK: Initializers
107
108 init() {}
109
110 init(
111 id: UUID? = nil,
112 name: String,
113 summary: String,
114 url: String,
115 yearStart: Int,
116 yearEnd: Int? = nil,
117 idGA: String,
118 idGTM: String
119 ) {
120 self.id = id
121 self.name = name
122 self.summary = summary
123 self.url = url
124 self.yearStart = yearStart
125 self.yearEnd = yearEnd
126 self.idGA = idGA
127 self.idGTM = idGTM
128 }
129
130}
131
132// MARK: - SiteLanguage Model
133
134final class SiteLanguage: Model, Content {
135
136 // MARK: Constants
137
138 static var schema = #"sites_languages"#
139
140 // MARK: Properties
141
142 @ID(key: .id)
143 var id: UUID?
144
145 @Parent(key: .idSite)
146 var site: Site
147
148 @Parent(key: .idLanguage)
149 var language: Language
150
151 @Timestamp(
152 key: .createdAt,
153 on: .create
154 )
155 var createdAt: Date?
156
157 // MARK: Initializers
158
159 init() {}
160
161 init(
162 id: UUID? = nil,
163 idSite: UUID,
164 idLanguage: UUID
165 ) {
166 self.id = id
167 self.$site.id = idSite
168 self.$language.id = idLanguage
169 }
170
171}
172
173// MARK: - CreateLanguage migration
174
175struct CreateLanguage: Migration {
176
177 // MARK: Functions
178
179 func prepare(
180 on database: Database
181 ) -> EventLoopFuture<Void> {
182 database
183 .schema(Language.schema)
184 .id()
185 .field(
186 .name,
187 .string,
188 .required
189 )
190 .field(
191 .code,
192 .string,
193 .required
194 )
195 .field(
196 .createdAt,
197 .datetime
198 )
199 .unique(on: .name)
200 .unique(on: .code)
201 .create()
202 }
203
204 func revert(
205 on database: Database
206 ) -> EventLoopFuture<Void> {
207 database
208 .schema(Language.schema)
209 .delete()
210 }
211
212}
213
214// MARK: - CreateSite migration
215
216struct CreateSite: Migration {
217
218 // MARK: Functions
219
220 func prepare(
221 on database: Database
222 ) -> EventLoopFuture<Void> {
223 database
224 .schema(Site.schema)
225 .id()
226 .field(
227 .name,
228 .string,
229 .required
230 )
231 .field(
232 .summary,
233 .string,
234 .required
235 )
236 .field(
237 .url,
238 .string,
239 .required
240 )
241 .field(
242 .yearStart,
243 .int,
244 .required
245 )
246 .field(
247 .yearEnd,
248 .int
249 )
250 .field(
251 .idGA,
252 .string,
253 .required
254 )
255 .field(
256 .idGTM,
257 .string,
258 .required
259 )
260 .field(
261 .createdAt,
262 .datetime
263 )
264 .field(
265 .updatedAt,
266 .datetime
267 )
268 .unique(on: .name)
269 .create()
270 }
271
272 func revert(
273 on database: Database
274 ) -> EventLoopFuture<Void> {
275 database
276 .schema(Site.schema)
277 .delete()
278 }
279
280}
281
282// MARK: - CreateSiteLanguage migration
283
284struct CreateSiteLanguage: Migration {
285
286 // MARK: Functions
287
288 func prepare(
289 on database: Database
290 ) -> EventLoopFuture<Void> {
291 database
292 .schema(SiteLanguage.schema)
293 .id()
294 .field(
295 .idSite,
296 .uuid,
297 .required
298 )
299 .field(
300 .idLanguage,
301 .uuid,
302 .required
303 )
304 .field(
305 .createdAt,
306 .datetime
307 )
308 .foreignKey(
309 .idSite,
310 references: Site.schema,
311 .id,
312 onDelete: .cascade,
313 onUpdate: .cascade
314 )
315 .foreignKey(
316 .idLanguage,
317 references: Language.schema,
318 .id,
319 onDelete: .cascade,
320 onUpdate: .cascade
321 )
322 .create()
323 }
324
325 func revert(
326 on database: Database
327 ) -> EventLoopFuture<Void> {
328 database
329 .schema(SiteLanguage.schema)
330 .delete()
331 }
332
333}
334
335// MARK: - LanguageController controller
336
337struct LanguageController: RouteCollection {
338
339 // MARK: Functions
340
341 func boot(
342 routes: RoutesBuilder
343 ) throws {
344 let group = routes.grouped(.languages)
345
346 group.get(use: index)
347 group.get(
348 .idLanguage,
349 use: get
350 )
351 }
352
353}
354
355// MARK: - Helpers
356
357private extension LanguageController {
358
359 // MARK: Functions
360
361 func index(
362 _ request: Request
363 ) throws -> EventLoopFuture<[Language]> {
364 Language
365 .query(on: request.db)
366 .with(\.$pages) { page in
367 page.with(\.$language)
368 page.with(\.$site)
369 }
370 .with(\.$sites) { sites in
371 sites.with(\.$languages)
372 }
373 .sort(
374 .name,
375 .ascending
376 )
377 .all()
378 }
379
380 func get(
381 _ request: Request
382 ) throws -> EventLoopFuture<Language> {
383 let idLanguage = try parameter(
384 named: .idLanguage,
385 as: UUID.self,
386 on: request
387 )
388
389 return Language
390 .query(on: request.db)
391 .filter(
392 .id,
393 .equal,
394 idLanguage
395 )
396 .with(\.$sites) {
397 $0.with(\.$languages)
398 }
399 .first()
400 .unwrap(or: Abort(.notFound))
401 }
402
403}
404
405// MARK: - RouteCollection extension
406
407extension RouteCollection {
408
409 // MARK: Functions
410
411 func parameter<T: LosslessStringConvertible>(
412 named name: String,
413 as type: T.Type,
414 on request: Request
415 ) throws -> T {
416 guard let value = request
417 .parameters
418 .get(
419 name,
420 as: T.self
421 ) else {
422 throw Abort(.badRequest)
423 }
424
425 return value
426 }
427
428 func findItem<T: Model>(
429 of type: T.Type,
430 named name: String,
431 on request: Request
432 ) throws -> EventLoopFuture<Optional<T>.WrappedType> {
433 let id = try parameter(
434 named: name,
435 as: UUID.self,
436 on: request
437 )
438
439 return T
440 .find(
441 id as? T.IDValue,
442 on: request.db
443 )
444 .unwrap(or: Abort(.notFound))
445 }
446
447}
448
449
450// MARK: - Common keys
451
452extension FieldKey {
453
454 static var name: Self { .string(#"name"#) }
455 static var createdAt: Self { .string(#"created_at"#) }
456 static var updatedAt: Self { .string(#"updated_at"#) }
457
458}
459
460// MARK: - Language keys
461
462extension FieldKey {
463
464 static var code: Self { .string(#"code"#) }
465
466}
467
468// MARK: - Site keys
469
470extension FieldKey {
471
472 static var summary: Self { .string(#"summary"#) }
473 static var url: Self { .string(#"url"#) }
474 static var yearStart: Self { .string(#"year_start"#) }
475 static var yearEnd: Self { .string(#"year_end"#) }
476 static var idGA: Self { .string(#"id_ga"#) }
477 static var idGTM: Self { .string(#"id_gtm"#) }
478
479}
480
481// MARK: - SiteLanguage keys
482
483extension FieldKey {
484
485 static var idSite: Self { .string(#"id_site"#) }
486 static var idLanguage: Self { .string(#"id_language"#) }
487
488}
489
490// MARK: - Resources
491
492extension PathComponent {
493
494 static var api: Self { .constant(#"api"#) }
495 static var languages: Self { .constant(#"languages"#) }
496 static var sites: Self { .constant(#"sites"#) }
497
498}
499
500// MARK: - Parameters
501
502extension PathComponent {
503
504 static var idSite: Self { .parameter(#"id_site"#) }
505 static var idLanguage: Self { .parameter(#"id_language"#) }
506
507}
508
509// MARK: - Parameter Names
510
511extension String {
512
513 static var idSite: Self { #"id_site"# }
514 static var idLanguage: Self { #"id_language"# }
515
516}