|
| 1 | +import Stream |
| 2 | + |
| 3 | +extension BackendMessage { |
| 4 | + struct Error { |
| 5 | + let fields: [Field] |
| 6 | + |
| 7 | + struct Field { |
| 8 | + let type: FieldType |
| 9 | + let value: String |
| 10 | + |
| 11 | + init(from stream: SubStreamReader) throws { |
| 12 | + let rawFieldType = Int(try stream.read(UInt8.self)) |
| 13 | + self.type = Field.FieldType(rawValue: rawFieldType) |
| 14 | + self.value = try stream.readCString() |
| 15 | + } |
| 16 | + |
| 17 | + enum FieldType { |
| 18 | + case severity |
| 19 | + case severityEN |
| 20 | + case code |
| 21 | + case message |
| 22 | + case detail |
| 23 | + case hint |
| 24 | + case position |
| 25 | + case internalPosition |
| 26 | + case internalQuery |
| 27 | + case `where` |
| 28 | + case schemaName |
| 29 | + case tableName |
| 30 | + case columnName |
| 31 | + case dataTypeName |
| 32 | + case constraintName |
| 33 | + case file |
| 34 | + case line |
| 35 | + case routine |
| 36 | + case unknown(Int) |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + init(from stream: SubStreamReader) throws { |
| 41 | + var fields = [Field]() |
| 42 | + while !stream.isEmpty { |
| 43 | + // end of error message |
| 44 | + guard try stream.peek() != 0 else { |
| 45 | + try stream.consume(count: 1) |
| 46 | + break |
| 47 | + } |
| 48 | + fields.append(try .init(from: stream)) |
| 49 | + } |
| 50 | + self.fields = fields |
| 51 | + } |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +extension BackendMessage.Error.Field.FieldType: RawRepresentable { |
| 56 | + enum RawType: Int { |
| 57 | + case severity = 83 // 'S' |
| 58 | + case severityEN = 86 // 'V' |
| 59 | + case code = 67 // 'C' |
| 60 | + case message = 77 // 'M' |
| 61 | + case detail = 68 // 'D' |
| 62 | + case hint = 72 // 'H' |
| 63 | + case position = 80 // 'P' |
| 64 | + case internalPosition = 112 // 'p' |
| 65 | + case internalQuery = 113 // 'q' |
| 66 | + case `where` = 87 // 'W' |
| 67 | + case schemaName = 115 // 's' |
| 68 | + case tableName = 116 // 't' |
| 69 | + case columnName = 99 // 'c' |
| 70 | + case dataTypeName = 100 // 'd' |
| 71 | + case constraintName = 110 // 'n' |
| 72 | + case file = 70 // 'F' |
| 73 | + case line = 76 // 'L' |
| 74 | + case routine = 82 // 'R' |
| 75 | + } |
| 76 | + |
| 77 | + var rawValue: Int { |
| 78 | + switch self { |
| 79 | + case .severity: return RawType.severity.rawValue |
| 80 | + case .severityEN: return RawType.severityEN.rawValue |
| 81 | + case .code: return RawType.code.rawValue |
| 82 | + case .message: return RawType.message.rawValue |
| 83 | + case .detail: return RawType.detail.rawValue |
| 84 | + case .hint: return RawType.hint.rawValue |
| 85 | + case .position: return RawType.position.rawValue |
| 86 | + case .internalPosition: return RawType.internalPosition.rawValue |
| 87 | + case .internalQuery: return RawType.internalQuery.rawValue |
| 88 | + case .where: return RawType.where.rawValue |
| 89 | + case .schemaName: return RawType.schemaName.rawValue |
| 90 | + case .tableName: return RawType.tableName.rawValue |
| 91 | + case .columnName: return RawType.columnName.rawValue |
| 92 | + case .dataTypeName: return RawType.dataTypeName.rawValue |
| 93 | + case .constraintName: return RawType.constraintName.rawValue |
| 94 | + case .file: return RawType.file.rawValue |
| 95 | + case .line: return RawType.line.rawValue |
| 96 | + case .routine: return RawType.routine.rawValue |
| 97 | + case .unknown(let value): return value |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + init(rawValue: Int) { |
| 102 | + guard let rawType = RawType(rawValue: rawValue) else { |
| 103 | + self = .unknown(rawValue) |
| 104 | + return |
| 105 | + } |
| 106 | + switch rawType { |
| 107 | + case .severity: self = .severity |
| 108 | + case .severityEN: self = .severityEN |
| 109 | + case .code: self = .code |
| 110 | + case .message: self = .message |
| 111 | + case .detail: self = .detail |
| 112 | + case .hint: self = .hint |
| 113 | + case .position: self = .position |
| 114 | + case .internalPosition: self = .internalPosition |
| 115 | + case .internalQuery: self = .internalQuery |
| 116 | + case .where: self = .where |
| 117 | + case .schemaName: self = .schemaName |
| 118 | + case .tableName: self = .tableName |
| 119 | + case .columnName: self = .columnName |
| 120 | + case .dataTypeName: self = .dataTypeName |
| 121 | + case .constraintName: self = .constraintName |
| 122 | + case .file: self = .file |
| 123 | + case .line: self = .line |
| 124 | + case .routine: self = .routine |
| 125 | + } |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +extension BackendMessage.Error.Field: CustomStringConvertible { |
| 130 | + var description: String { |
| 131 | + return "(type: \(type), \"\(value)\")" |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +extension BackendMessage.Error.Field.FieldType: CustomStringConvertible { |
| 136 | + var description: String { |
| 137 | + switch self { |
| 138 | + case .severity: return ".severity" |
| 139 | + case .severityEN: return ".severityEN" |
| 140 | + case .code: return ".code" |
| 141 | + case .message: return ".message" |
| 142 | + case .detail: return ".detail" |
| 143 | + case .hint: return ".hint" |
| 144 | + case .position: return ".position" |
| 145 | + case .internalPosition: return ".internalPosition" |
| 146 | + case .internalQuery: return ".internalQuery" |
| 147 | + case .where: return ".where" |
| 148 | + case .schemaName: return ".schemaName" |
| 149 | + case .tableName: return ".tableName" |
| 150 | + case .columnName: return ".columnName" |
| 151 | + case .dataTypeName: return ".dataTypeName" |
| 152 | + case .constraintName: return ".constraintName" |
| 153 | + case .file: return ".file" |
| 154 | + case .line: return ".line" |
| 155 | + case .routine: return ".routine" |
| 156 | + case .unknown(let value): return ".unknown(\(value))" |
| 157 | + } |
| 158 | + } |
| 159 | +} |
0 commit comments