-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathFMPLayoutInfo.swift
118 lines (105 loc) · 3.06 KB
/
FMPLayoutInfo.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//
// FMPLayoutInfo.swift
// PerfectFileMaker
//
// Created by Kyle Jessup on 2016-08-17.
// Copyright (C) 2016 PerfectlySoft, Inc.
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the Perfect.org open source project
//
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors
// Licensed under Apache License v2.0
//
// See http://perfect.org/licensing.html for license information
//
//===----------------------------------------------------------------------===//
//
import PerfectXML
/// One of the possible FileMaker field types.
public enum FMPFieldType {
/// A text field.
case text
/// A numeric field.
case number
/// A container field.
case container
/// A date field.
case date
/// A time field.
case time
/// A timestamp field.
case timestamp
init(_ type: String) {
switch type {
case "number":
self = .number
case "container":
self = .container
case "date":
self = .date
case "time":
self = .time
case "timestamp":
self = .timestamp
default:
self = .text
}
}
}
/// A FileMaker field definition. Indicates a field name and type.
public struct FMPFieldDefinition {
/// The field name.
public let name: String
/// The field type.
public let type: FMPFieldType
init(node: XElement) {
self.name = node.getAttribute(name: "name") ?? ""
self.type = FMPFieldType(node.getAttribute(name: "result") ?? "text")
}
}
/// Represents either an individual field definition or a related (portal) definition.
public enum FMPMetaDataItem {
/// An individual field.
case fieldDefinition(FMPFieldDefinition)
/// A related set. Indicates the portal name and its contained fields.
case relatedSetDefinition(String, [FMPFieldDefinition])
init(node: XElement) {
if node.nodeName == fmrsRelatedSetDefinition {
self = .relatedSetDefinition(node.getAttribute(name: "table") ?? "", node.childElements.map { FMPFieldDefinition(node: $0) })
} else {
self = .fieldDefinition(FMPFieldDefinition(node: node))
}
}
}
/// Represents meta-information about a particular layout.
public struct FMPLayoutInfo {
/// Each field or related set as a list.
public let fields: [FMPMetaDataItem]
/// Each field or related set keyed by name.
public let fieldsByName: [String:FMPFieldType]
init(node: XElement) {
self.fields = node.childElements.map { FMPMetaDataItem(node: $0) }
func flattenOne(item: FMPMetaDataItem) -> [(String, FMPFieldType)] {
switch item {
case .fieldDefinition(let def):
return [(def.name, def.type)]
case .relatedSetDefinition(let table, let fields):
return soFlat(prefix: table, fields: fields)
}
}
func soFlat(fields: [FMPMetaDataItem]) -> [(String, FMPFieldType)] {
return fields.flatMap { flattenOne(item: $0) }
}
func soFlat(prefix: String, fields: [FMPFieldDefinition]) -> [(String, FMPFieldType)] {
return fields.map { ($0.name, $0.type) }
}
let flattened = soFlat(fields: self.fields)
var ret = [String:FMPFieldType]()
for (n, v) in flattened {
ret[n] = v
}
self.fieldsByName = ret
}
}