You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Swift: auto-emit `@DocumentID var id: String?` on every generated document-model struct, plus two new schema-level overrides for the Swift generator.
6
+
7
+
- The Firebase iOS SDK populates `@DocumentID` properties from the document path (and excludes them from the encoded body), so generated structs are now drop-in usable with `getDocument(as:)` / `setData(from:)` without manual edits.
8
+
- New per-document-model option `swift.documentIdProperty.name` lets you rename the auto-generated `@DocumentID` property (default: `id`). Set this when your document body already has a field whose Firestore key is `id`, since the Firebase iOS SDK refuses to decode a document where the `@DocumentID` property name matches a body wire key.
9
+
- New per-field option `swift.name` lets you rename a body property in the generated Swift output without changing its Firestore wire key. Useful for dodging Swift keywords or for ergonomics. The renderer routes the original Firestore key through a generated `CodingKeys` enum.
10
+
- The Swift generator now throws when (a) a document model has a body field whose Firestore key matches the `@DocumentID` property name (rename one or the other via the options above), or (b) two body fields resolve to the same Swift property name. Both errors include the offending field names and a concrete remediation.
11
+
12
+
This is a behavior change for Swift consumers: every generated document struct gains an `id: String?` property and an `import FirebaseFirestore` statement. Schemas with a body-side `id` field on a document model must opt in to a non-`id``@DocumentID` property name via `swift: { documentIdProperty: { name: 'documentId' } }` (or similar) on the document model to keep generating successfully.
13
+
14
+
The new options are structured as per-platform blocks (`swift: { ... }`) so future generators (Python, TypeScript, etc.) can layer in their own field-level and model-level overrides without further breaking changes.
"Overrides the Swift property name used to decode this field. Encoding is unaffected: the field is still serialized to Firestore under the schema's field name (the Swift renderer routes the original name through `CodingKeys`). Useful when the schema name collides with a Swift keyword or with an auto-generated property such as `@DocumentID var id`."
180
+
),
181
+
})
182
+
.strict()
183
+
.describe('Swift-specific overrides for an object field.');
184
+
172
185
exportconstobjectField=z
173
186
.object({
174
187
type: type,
@@ -180,6 +193,9 @@ export const objectField = z
180
193
'Whether this field is read-only. Defaults to false. This information is used by the Security Rules generator when producing validators that detect whether a read-only field has been affected by a write.'
181
194
),
182
195
docs: z.string().optional().describe('Optional documentation for the object field.'),
196
+
swift: swiftFieldOptions
197
+
.optional()
198
+
.describe('Per-platform overrides for the Swift generator. See `SwiftFieldOptions`.'),
183
199
})
184
200
.strict()
185
201
.describe('An object field.');
@@ -193,6 +209,26 @@ export const aliasModel = z
193
209
.strict()
194
210
.describe('An alias model');
195
211
212
+
exportconstswiftDocumentModelOptions=z
213
+
.object({
214
+
documentIdProperty: z
215
+
.object({
216
+
name: z
217
+
.string()
218
+
.min(1)
219
+
.describe(
220
+
"The Swift property name for the auto-generated `@DocumentID`-annotated field. Defaults to `id`. Set this to a non-`id` value (e.g. `documentId`) when the schema's document body has a field whose Firestore key is also `id`, since the Firebase iOS SDK refuses to decode a document where the `@DocumentID` property name matches an existing body field's key."
221
+
),
222
+
})
223
+
.strict()
224
+
.optional()
225
+
.describe(
226
+
"Configuration for the auto-generated `@DocumentID`-annotated property that the Swift generator emits on every document-model struct. The Firebase iOS SDK populates this property from the document's path on read and excludes it from the encoded body on write."
227
+
),
228
+
})
229
+
.strict()
230
+
.describe('Swift-specific overrides for a document model.');
231
+
196
232
exportconstdocumentModel=z
197
233
.object({
198
234
model: z.literal('document').describe(`A literal field indicating that this is a 'document' model.`),
@@ -204,6 +240,9 @@ export const documentModel = z
204
240
.describe(
205
241
`An exact or generic path to the document. Must be a string consisting of path segments separated by a '/' (slash). Each segment can either be a literal ID or a generic ID of the collection or document. A literal ID is a plain string, such as 'users', while a generic ID must be enclosed in curly braces (e.g. '{userId}').`
206
242
),
243
+
swift: swiftDocumentModelOptions
244
+
.optional()
245
+
.describe('Per-platform overrides for the Swift generator. See `SwiftDocumentModelOptions`.'),
constformattedSources=sources.map(n=>(n==='@DocumentID' ? n : `'${n}'`)).join(', ');
25
+
constremediation=involvesDocumentId
26
+
? `Either rename the auto-generated \`@DocumentID\` property by adding \`swift: { documentIdProperty: { name: '<unique-name>' } }\` to the document model, or rename the conflicting field${fieldSources.length>1 ? 's' : ''} by setting \`swift: { name: '<unique-name>' }\` on ${fieldSources.length>1 ? 'one of them' : 'it'}.`
27
+
: `Disambiguate one of them by setting \`swift: { name: '<unique-name>' }\` on the field in your schema definition.`;
28
+
constcauseBlurb=involvesDocumentId
29
+
? `In the generated Swift struct, ${fieldSources.map(n=>`field '${n}'`).join(' and ')} would have the same property name as the auto-generated \`@DocumentID\` property, which Swift does not allow. `
30
+
: '';
31
+
super(
32
+
`Two or more properties on model '${modelName}' resolve to the same Swift property name '${propertyName}'. Conflicting source(s): ${formattedSources}. ${causeBlurb}${remediation}`
`Document model '${modelName}' declares a body field named '${fieldName}', whose Firestore key matches the auto-generated \`@DocumentID\` property name '${documentIdPropertyName}'. The Firebase iOS SDK refuses to decode such documents because the path-derived id and the body field would clash on the same wire key. Rename the \`@DocumentID\` property by adding \`swift: { documentIdProperty: { name: '<unique-name>' } }\` to the document model in your schema definition (e.g. \`name: 'documentId'\`). The body field then keeps its current Firestore key and Swift name.`
0 commit comments