@rvoh/dream 2.37.0 → 2.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/dist/cjs/src/dream-app/index.js +6 -0
  2. package/dist/cjs/src/serializer/DreamSerializer.js +23 -0
  3. package/dist/cjs/src/serializer/ObjectSerializer.js +22 -0
  4. package/dist/cjs/src/serializer/SerializerRenderer.js +34 -59
  5. package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +46 -17
  6. package/dist/cjs/src/serializer/builders/ObjectSerializerBuilder.js +44 -17
  7. package/dist/cjs/src/serializer/helpers/nullFlattenedSerializerKeys.js +233 -0
  8. package/dist/cjs/src/serializer/helpers/serializersForAssociatedClass.js +4 -3
  9. package/dist/esm/src/dream-app/index.js +6 -0
  10. package/dist/esm/src/serializer/DreamSerializer.js +23 -0
  11. package/dist/esm/src/serializer/ObjectSerializer.js +22 -0
  12. package/dist/esm/src/serializer/SerializerRenderer.js +34 -59
  13. package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +46 -17
  14. package/dist/esm/src/serializer/builders/ObjectSerializerBuilder.js +44 -17
  15. package/dist/esm/src/serializer/helpers/nullFlattenedSerializerKeys.js +233 -0
  16. package/dist/esm/src/serializer/helpers/serializersForAssociatedClass.js +4 -3
  17. package/dist/types/src/dream-app/index.d.ts +6 -0
  18. package/dist/types/src/serializer/DreamSerializer.d.ts +23 -0
  19. package/dist/types/src/serializer/ObjectSerializer.d.ts +22 -0
  20. package/dist/types/src/serializer/SerializerRenderer.d.ts +1 -13
  21. package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +49 -19
  22. package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +47 -19
  23. package/dist/types/src/serializer/helpers/nullFlattenedSerializerKeys.d.ts +85 -0
  24. package/dist/types/src/serializer/helpers/serializersForAssociatedClass.d.ts +4 -3
  25. package/docs/classes/db.DreamMigrationHelpers.html +11 -11
  26. package/docs/classes/db.KyselyQueryDriver.html +49 -49
  27. package/docs/classes/db.PostgresQueryDriver.html +49 -49
  28. package/docs/classes/db.QueryDriverBase.html +49 -49
  29. package/docs/classes/errors.CannotSaveMissingDream.html +2 -2
  30. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  31. package/docs/classes/errors.ColumnOverflow.html +3 -3
  32. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  33. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  34. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  35. package/docs/classes/errors.DecryptionError.html +2 -2
  36. package/docs/classes/errors.DecryptionParseError.html +2 -2
  37. package/docs/classes/errors.DecryptionRotationError.html +3 -3
  38. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  39. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  40. package/docs/classes/errors.InvalidClockTime.html +2 -2
  41. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  42. package/docs/classes/errors.InvalidDateTime.html +2 -2
  43. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  44. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  45. package/docs/classes/errors.NotNullViolation.html +3 -3
  46. package/docs/classes/errors.RecordNotFound.html +3 -3
  47. package/docs/classes/errors.SortableScopeDidNotStabilize.html +3 -3
  48. package/docs/classes/errors.SortableScopeLockWaitTimedOut.html +3 -3
  49. package/docs/classes/errors.ValidationError.html +3 -3
  50. package/docs/classes/index.CalendarDate.html +33 -33
  51. package/docs/classes/index.ClockTime.html +32 -32
  52. package/docs/classes/index.ClockTimeTz.html +35 -35
  53. package/docs/classes/index.DateTime.html +86 -86
  54. package/docs/classes/index.Decorators.html +19 -19
  55. package/docs/classes/index.Dream.html +125 -125
  56. package/docs/classes/index.DreamApp.html +11 -11
  57. package/docs/classes/index.DreamTransaction.html +3 -3
  58. package/docs/classes/index.Env.html +5 -5
  59. package/docs/classes/index.Query.html +65 -65
  60. package/docs/classes/system.CliFileWriter.html +4 -4
  61. package/docs/classes/system.DreamBin.html +3 -3
  62. package/docs/classes/system.DreamCLI.html +7 -7
  63. package/docs/classes/system.DreamImporter.html +2 -2
  64. package/docs/classes/system.DreamLogos.html +2 -2
  65. package/docs/classes/system.DreamSerializerBuilder.html +57 -28
  66. package/docs/classes/system.ObjectSerializerBuilder.html +55 -27
  67. package/docs/classes/system.PathHelpers.html +3 -3
  68. package/docs/classes/utils.Encrypt.html +4 -4
  69. package/docs/classes/utils.Range.html +2 -2
  70. package/docs/functions/db.closeAllDbConnections.html +1 -1
  71. package/docs/functions/db.dreamDbConnections.html +1 -1
  72. package/docs/functions/db.untypedDb.html +1 -1
  73. package/docs/functions/db.validateColumn.html +1 -1
  74. package/docs/functions/db.validateTable.html +1 -1
  75. package/docs/functions/errors.pgErrorType.html +1 -1
  76. package/docs/functions/index.DreamSerializer.html +18 -1
  77. package/docs/functions/index.ObjectSerializer.html +17 -1
  78. package/docs/functions/index.ReplicaSafe.html +1 -1
  79. package/docs/functions/index.STI.html +1 -1
  80. package/docs/functions/index.SoftDelete.html +1 -1
  81. package/docs/functions/utils.camelize.html +1 -1
  82. package/docs/functions/utils.capitalize.html +1 -1
  83. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  84. package/docs/functions/utils.compact.html +1 -1
  85. package/docs/functions/utils.groupBy.html +1 -1
  86. package/docs/functions/utils.hyphenize.html +1 -1
  87. package/docs/functions/utils.intersection.html +1 -1
  88. package/docs/functions/utils.isEmpty.html +1 -1
  89. package/docs/functions/utils.normalizeUnicode.html +1 -1
  90. package/docs/functions/utils.pascalize.html +1 -1
  91. package/docs/functions/utils.percent.html +1 -1
  92. package/docs/functions/utils.range.html +1 -1
  93. package/docs/functions/utils.round.html +1 -1
  94. package/docs/functions/utils.sanitizeString.html +1 -1
  95. package/docs/functions/utils.snakeify.html +1 -1
  96. package/docs/functions/utils.sort.html +1 -1
  97. package/docs/functions/utils.sortBy.html +1 -1
  98. package/docs/functions/utils.sortObjectByKey.html +1 -1
  99. package/docs/functions/utils.sortObjectByValue.html +1 -1
  100. package/docs/functions/utils.uncapitalize.html +1 -1
  101. package/docs/functions/utils.uniq.html +1 -1
  102. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  103. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  104. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  105. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  106. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  107. package/docs/interfaces/types.DecoratorContext.html +2 -2
  108. package/docs/interfaces/types.DecryptCallbacks.html +2 -2
  109. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  110. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  111. package/docs/interfaces/types.DreamDbConfig.html +6 -6
  112. package/docs/interfaces/types.DurationObject.html +2 -2
  113. package/docs/interfaces/types.EncryptOptions.html +2 -2
  114. package/docs/interfaces/types.EncryptionLegacyKeyUsedEvent.html +4 -4
  115. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  116. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  117. package/docs/interfaces/types.IntrospectedColumn.html +7 -7
  118. package/docs/interfaces/types.IntrospectedDatabase.html +2 -2
  119. package/docs/interfaces/types.IntrospectedEnum.html +2 -2
  120. package/docs/interfaces/types.IntrospectedTable.html +5 -5
  121. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  122. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  123. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  124. package/docs/types/openapi.OpenapiFormats.html +1 -1
  125. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  126. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  127. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  128. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  129. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  130. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  131. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  132. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  133. package/docs/types/openapi.OpenapiSchemaCombinatorFields.html +1 -1
  134. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  135. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
  136. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
  137. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
  138. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  139. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  140. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  141. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  142. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  143. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  144. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  145. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  154. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  155. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  156. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  157. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  158. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  159. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  160. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  161. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  162. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  163. package/docs/types/types.CalendarDateObject.html +1 -1
  164. package/docs/types/types.Camelized.html +1 -1
  165. package/docs/types/types.ClockTimeObject.html +1 -1
  166. package/docs/types/types.DbConnectionType.html +1 -1
  167. package/docs/types/types.DbTypes.html +1 -1
  168. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  169. package/docs/types/types.DreamAttributes.html +1 -1
  170. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  171. package/docs/types/types.DreamClassColumn.html +1 -1
  172. package/docs/types/types.DreamColumn.html +1 -1
  173. package/docs/types/types.DreamColumnNames.html +1 -1
  174. package/docs/types/types.DreamLogLevel.html +1 -1
  175. package/docs/types/types.DreamLogger.html +2 -2
  176. package/docs/types/types.DreamModelSerializerType.html +1 -1
  177. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  178. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  179. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  180. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  181. package/docs/types/types.DreamSerializable.html +1 -1
  182. package/docs/types/types.DreamSerializableArray.html +1 -1
  183. package/docs/types/types.DreamSerializerKey.html +1 -1
  184. package/docs/types/types.DreamSerializers.html +1 -1
  185. package/docs/types/types.DreamVirtualColumns.html +1 -1
  186. package/docs/types/types.DurationUnit.html +1 -1
  187. package/docs/types/types.EncryptAlgorithm.html +1 -1
  188. package/docs/types/types.HasManyStatement.html +1 -1
  189. package/docs/types/types.HasOneStatement.html +1 -1
  190. package/docs/types/types.Hyphenized.html +1 -1
  191. package/docs/types/types.IntrospectedValueType.html +1 -1
  192. package/docs/types/types.Pascalized.html +1 -1
  193. package/docs/types/types.PrimaryKeyType.html +1 -1
  194. package/docs/types/types.RoundingPrecision.html +1 -1
  195. package/docs/types/types.SerializerCasing.html +1 -1
  196. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  197. package/docs/types/types.Snakeified.html +1 -1
  198. package/docs/types/types.StrictInterface.html +1 -1
  199. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  200. package/docs/types/types.UpdateableProperties.html +1 -1
  201. package/docs/types/types.ValidationType.html +1 -1
  202. package/docs/types/types.ViewModel.html +2 -2
  203. package/docs/types/types.ViewModelClass.html +1 -1
  204. package/docs/types/types.WeekdayName.html +1 -1
  205. package/docs/types/types.WhereStatementForDream.html +1 -1
  206. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  207. package/docs/variables/index.DreamConst.html +1 -1
  208. package/docs/variables/index.ops.html +1 -1
  209. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  210. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  211. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  212. package/docs/variables/system.primaryKeyTypes.html +1 -1
  213. package/package.json +1 -1
@@ -14,6 +14,7 @@ import standardizeFullyQualifiedModelName from '../helpers/standardizeFullyQuali
14
14
  import expandStiClasses from '../helpers/sti/expandStiClasses.js';
15
15
  import inferSerializerFromDreamOrViewModel, { inferSerializersFromDreamClassOrViewModelClass } from '../serializer/helpers/inferSerializerFromDreamOrViewModel.js';
16
16
  import isDreamSerializer from '../serializer/helpers/isDreamSerializer.js';
17
+ import { flattenedOpenapiVariants, nullFlattenedOpenapiKeys, nullFlattenedOpenapiKeysOfOtherVariants, nullFlattenedSerializerKeys, nullFlattenedSerializerKeysOfOtherVariants } from '../serializer/helpers/nullFlattenedSerializerKeys.js';
17
18
  import serializerNameFromFullyQualifiedModelName from '../serializer/helpers/serializerNameFromFullyQualifiedModelName.js';
18
19
  import { DbConnectionType, LegacyCompatiblePrimaryKeyType } from '../types/db.js';
19
20
  import { DreamModelSerializerType, SimpleObjectSerializerType } from '../types/serializer.js';
@@ -67,6 +68,11 @@ export default class DreamApp {
67
68
  inferSerializerFromDreamOrViewModel: typeof inferSerializerFromDreamOrViewModel;
68
69
  inferSerializersFromDreamClassOrViewModelClass: typeof inferSerializersFromDreamClassOrViewModelClass;
69
70
  isDreamSerializer: typeof isDreamSerializer;
71
+ nullFlattenedSerializerKeys: typeof nullFlattenedSerializerKeys;
72
+ nullFlattenedSerializerKeysOfOtherVariants: typeof nullFlattenedSerializerKeysOfOtherVariants;
73
+ nullFlattenedOpenapiKeys: typeof nullFlattenedOpenapiKeys;
74
+ nullFlattenedOpenapiKeysOfOtherVariants: typeof nullFlattenedOpenapiKeysOfOtherVariants;
75
+ flattenedOpenapiVariants: typeof flattenedOpenapiVariants;
70
76
  serializerNameFromFullyQualifiedModelName: typeof serializerNameFromFullyQualifiedModelName;
71
77
  autogeneratedFileDisclaimer: typeof autogeneratedFileDisclaimer;
72
78
  };
@@ -1,3 +1,26 @@
1
1
  import Dream from '../Dream.js';
2
2
  import DreamSerializerBuilder from './builders/DreamSerializerBuilder.js';
3
+ /**
4
+ * Builds a serializer for a Dream model. A serializer is a function that takes the
5
+ * data to render and declares the keys to render it with:
6
+ *
7
+ * ```typescript
8
+ * export const UserSerializer = (user: User) =>
9
+ * DreamSerializer(User, user).attribute('email').rendersMany('posts')
10
+ * ```
11
+ *
12
+ * A serializer must not read its data while being built: what it declares may not
13
+ * depend on its data. Dream and Psychic build it without data to read its shape (the
14
+ * OpenAPI schema, and the keys a flattened association or `customAttribute` that uses
15
+ * it renders as `null` where its value does not supply them), so a serializer that
16
+ * reads its data while being built throws when a flattened association or
17
+ * `customAttribute` that uses it is rendered. Read the data inside a `customAttribute`
18
+ * callback, which runs only when the serializer renders, not while it is built.
19
+ *
20
+ * @param dreamClass - The Dream model class the serializer renders
21
+ * @param data - The Dream instance to render
22
+ * @param passthroughData - Data available to this serializer and passed down to the serializers
23
+ * it renders
24
+ * @returns The serializer builder for method chaining
25
+ */
3
26
  export default function DreamSerializer<DreamClass extends typeof Dream, DataType extends Dream | null, PassthroughDataType extends object | undefined = undefined>(dreamClass: DreamClass, data: DataType, passthroughData?: PassthroughDataType): DreamSerializerBuilder<DreamClass, DataType, PassthroughDataType, Exclude<DataType, null>>;
@@ -1,2 +1,24 @@
1
1
  import ObjectSerializerBuilder from './builders/ObjectSerializerBuilder.js';
2
+ /**
3
+ * Builds a serializer for a plain object or view model. A serializer is a function
4
+ * that takes the data to render and declares the keys to render it with:
5
+ *
6
+ * ```typescript
7
+ * export const AddressSerializer = (address: Address) =>
8
+ * ObjectSerializer(address).attribute('city', { openapi: 'string' })
9
+ * ```
10
+ *
11
+ * A serializer must not read its data while being built: what it declares may not
12
+ * depend on its data. Dream and Psychic build it without data to read its shape (the
13
+ * OpenAPI schema, and the keys a flattened association or `customAttribute` that uses
14
+ * it renders as `null` where its value does not supply them), so a serializer that
15
+ * reads its data while being built throws when a flattened association or
16
+ * `customAttribute` that uses it is rendered. Read the data inside a `customAttribute`
17
+ * callback, which runs only when the serializer renders, not while it is built.
18
+ *
19
+ * @param data - The object to render
20
+ * @param passthroughData - Data available to this serializer and passed down to the serializers
21
+ * it renders
22
+ * @returns The serializer builder for method chaining
23
+ */
2
24
  export default function ObjectSerializer<DataType extends object | null, PassthroughDataType extends object | undefined = undefined>(data: DataType, passthroughData?: PassthroughDataType): ObjectSerializerBuilder<DataType, PassthroughDataType, Exclude<DataType, null>>;
@@ -10,18 +10,6 @@ export default class SerializerRenderer {
10
10
  private renderOpts;
11
11
  constructor(serializerBuilder: DreamSerializerBuilder<any, any> | ObjectSerializerBuilder<any, any> | null | undefined, passthroughData?: object, { casing }?: SerializerRendererOpts);
12
12
  render(): Record<string, any> | null;
13
- /**
14
- * The keys a flattened `rendersOne` adds to the parent's payload when its associated object is
15
- * null: each key any of `serializers` declares, set to `null`. There are several serializers when
16
- * the association is a polymorphic BelongsTo, one for each target class, or when the associated
17
- * class is an STI base, one for each child, and their keys are unioned.
18
- *
19
- * Each serializer is built with `undefined` data to read its declarations, as Psychic's OpenAPI
20
- * generation and `preloadFor` build it, and nothing is rendered: no attribute callback runs and
21
- * no association of the missing object is read. A flattened `rendersOne` it declares adds its
22
- * own serializers' keys the same way. A flattened `customAttribute` adds none, since only its
23
- * callback knows its keys.
24
- */
25
- private nullFlattenedAttributes;
13
+ private setCaseOfDefinedKeys;
26
14
  private setCase;
27
15
  }
@@ -141,15 +141,29 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
141
141
  * - `openapi` - (required) OpenAPI schema definition for the computed value
142
142
  * - `flatten` - When `true`, spreads the returned object's properties directly into the
143
143
  * parent serialized output instead of nesting them under `name`. The `openapi` option
144
- * then describes the whole returned object, not each property, because Psychic adds it
145
- * to the parent's schema as an `allOf` branch: either an object schema with full
146
- * property bodies (`type: 'object'`, `properties`, and `required` listing the keys that
147
- * are always present), or `{ $serializer: SomeSerializer }` when the callback returns
148
- * what that serializer renders. A serializer ref with `many: true` does not type-check
149
- * here, since a list has no properties to spread. A `null` or `undefined` return adds no
150
- * keys. Attributes render in declaration order, so a key the returned object shares with
151
- * another attribute takes the value of whichever is declared later; under the `allOf`,
152
- * that value must match both schemas
144
+ * then describes the whole returned object, not each property: either an object schema
145
+ * with full property bodies (`type: 'object'`, `properties`, and `required` listing the
146
+ * keys that are always present), or `{ $serializer: SomeSerializer }` when the callback
147
+ * returns what that serializer renders. A serializer ref with `many: true` does not
148
+ * type-check here, since a list has no properties to spread. Whatever the callback
149
+ * returns, each key any shape of the `openapi` requires renders, as `null` wherever the
150
+ * value does not supply it (a returned plain object's key set to `undefined` does not
151
+ * supply it): a key an object shape lists in its `required` array, a key a `$serializer` or
152
+ * `$serializable` ref's serializer declares without `required: false` (for an STI base,
153
+ * any child's serializer), and each such key of any `allOf`, `anyOf` or `oneOf` member. So
154
+ * a `null` return, a serializer built over `null` or `undefined` data, or an `undefined`
155
+ * return without `required: false` renders each of them as `null`, and a present value
156
+ * renders its own keys over them, so a key another shape requires renders as `null` even
157
+ * when the value's own shape leaves it optional; the payload always includes the same
158
+ * keys whichever shape the value takes and whether it is null. An optional key no shape
159
+ * requires stays absent unless the value supplies it, and an `undefined` return with
160
+ * `required: false` adds no keys.
161
+ * Every key it adds follows the render's casing like the parent's own keys: a returned
162
+ * plain object's top-level keys and the `openapi`'s `properties` keys are cased (so
163
+ * `casing: 'snake'` renders `phoneNumber` as `phone_number`, present or `null`), while
164
+ * nested values render as returned. Attributes render in declaration order, so a key the
165
+ * returned object shares with another attribute takes the value of whichever is declared
166
+ * later, and that value must match both the attribute's declaration and the `openapi`'s
153
167
  * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
154
168
  * when omitted, attributes are required by default
155
169
  * @returns The serializer builder for method chaining
@@ -191,14 +205,29 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
191
205
  * declaration order, so when the parent and the association share a key (e.g., `id`),
192
206
  * whichever is declared later wins: the association's value replaces an attribute declared
193
207
  * before the `rendersOne`, and an attribute declared after it replaces the association's.
194
- * When the association is `null`, every key its serializer declares renders as `null`
195
- * (for a polymorphic `BelongsTo`, every key the serializer of any of its target classes
196
- * declares, and for an association to an STI base, every key the serializer of any of its
197
- * STI children declares), in the same order (so an `id` declared before the `rendersOne` becomes
198
- * `null`); nothing in that serializer is rendered, so its custom attribute callbacks do
199
- * not run, and a flattened `customAttribute` in it adds no keys. Psychic adds the association's OpenAPI
200
- * schema to the parent's as an `allOf` branch, so a shared key's value must match both
201
- * schemas, whichever declaration wins
208
+ * Each key its serializer requires always renders, as `null` wherever the association
209
+ * does not supply it: an attribute, delegatedAttribute or customAttribute declared without
210
+ * `required: false`, and every non-flattened `rendersOne` and `rendersMany` (for a
211
+ * polymorphic `BelongsTo`, each key the serializer of any of its target classes requires,
212
+ * and for an association to an STI base, each key the serializer of any of its STI children
213
+ * requires), in the same order (so an `id` declared before the `rendersOne` becomes `null`
214
+ * when the association is `null`). A flattened `customAttribute` in that serializer adds the
215
+ * keys its `openapi` requires: a key an object shape lists in its `required` array, a key a
216
+ * `$serializer` or `$serializable` ref's serializer declares without `required: false`, and
217
+ * each such key of an `allOf`, `anyOf` or `oneOf` member; a ref with `many: true` adds none,
218
+ * and a flattened `customAttribute` declared with `required: false` adds none. When the
219
+ * association is `null`, each of these keys renders as `null` and nothing in its serializer
220
+ * is rendered, so its custom attribute callbacks do not run. When it is present, the held
221
+ * object's serializer renders its own keys over them, so a key another STI child's or
222
+ * target's serializer requires renders as `null` where the held one's serializer does not
223
+ * render it, including a key that serializer declares with `required: false`; the payload
224
+ * always includes the same keys whichever is held and, for an association or a property
225
+ * given a `serializer` or `viewModelClass` option, whether it is `null` (a `null` property
226
+ * that is not an association and has neither option renders none of these keys, since no
227
+ * serializer is known for it). A key declared with `required: false` that no serializer
228
+ * requires stays absent unless it renders. The association's OpenAPI schema describes the
229
+ * parent's payload too, so a shared key's value must match both the parent's declaration
230
+ * and the association's, whichever declaration wins
202
231
  * - `optional` - When `true`, allows the association to be null/missing without causing
203
232
  * an `OpenapiResponseValidationFailure` during Psychic controller unit specs. By default,
204
233
  * `rendersOne` expects the association to be present (mirroring the `optional` option on
@@ -254,8 +283,9 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
254
283
  * If `true`, the rendered association's attributes are merged directly into
255
284
  * the parent object instead of being nested under the association key. A key
256
285
  * the parent shares with the association takes the value of whichever is
257
- * declared later, and when the association is `null`, every key its serializer
258
- * declares renders as `null`. See the `flatten` option of `rendersOne`.
286
+ * declared later, and each key its serializer requires renders, as `null`
287
+ * wherever the association does not supply it. See the `flatten` option of
288
+ * `rendersOne`.
259
289
  */
260
290
  flatten?: boolean;
261
291
  /**
@@ -134,15 +134,29 @@ export default class ObjectSerializerBuilder<MaybeNullDataType extends object |
134
134
  * - `openapi` - (required) OpenAPI schema definition for the computed value
135
135
  * - `flatten` - When `true`, spreads the returned object's properties directly into the
136
136
  * parent serialized output instead of nesting them under `name`. The `openapi` option
137
- * then describes the whole returned object, not each property, because Psychic adds it
138
- * to the parent's schema as an `allOf` branch: either an object schema with full
139
- * property bodies (`type: 'object'`, `properties`, and `required` listing the keys that
140
- * are always present), or `{ $serializer: SomeSerializer }` when the callback returns
141
- * what that serializer renders. A serializer ref with `many: true` does not type-check
142
- * here, since a list has no properties to spread. A `null` or `undefined` return adds no
143
- * keys. Attributes render in declaration order, so a key the returned object shares with
144
- * another attribute takes the value of whichever is declared later; under the `allOf`,
145
- * that value must match both schemas
137
+ * then describes the whole returned object, not each property: either an object schema
138
+ * with full property bodies (`type: 'object'`, `properties`, and `required` listing the
139
+ * keys that are always present), or `{ $serializer: SomeSerializer }` when the callback
140
+ * returns what that serializer renders. A serializer ref with `many: true` does not
141
+ * type-check here, since a list has no properties to spread. Whatever the callback
142
+ * returns, each key any shape of the `openapi` requires renders, as `null` wherever the
143
+ * value does not supply it (a returned plain object's key set to `undefined` does not
144
+ * supply it): a key an object shape lists in its `required` array, a key a `$serializer` or
145
+ * `$serializable` ref's serializer declares without `required: false` (for an STI base,
146
+ * any child's serializer), and each such key of any `allOf`, `anyOf` or `oneOf` member. So
147
+ * a `null` return, a serializer built over `null` or `undefined` data, or an `undefined`
148
+ * return without `required: false` renders each of them as `null`, and a present value
149
+ * renders its own keys over them, so a key another shape requires renders as `null` even
150
+ * when the value's own shape leaves it optional; the payload always includes the same
151
+ * keys whichever shape the value takes and whether it is null. An optional key no shape
152
+ * requires stays absent unless the value supplies it, and an `undefined` return with
153
+ * `required: false` adds no keys.
154
+ * Every key it adds follows the render's casing like the parent's own keys: a returned
155
+ * plain object's top-level keys and the `openapi`'s `properties` keys are cased (so
156
+ * `casing: 'snake'` renders `phoneNumber` as `phone_number`, present or `null`), while
157
+ * nested values render as returned. Attributes render in declaration order, so a key the
158
+ * returned object shares with another attribute takes the value of whichever is declared
159
+ * later, and that value must match both the attribute's declaration and the `openapi`'s
146
160
  * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
147
161
  * when omitted, attributes are required by default
148
162
  * @returns The serializer builder for method chaining
@@ -184,14 +198,27 @@ export default class ObjectSerializerBuilder<MaybeNullDataType extends object |
184
198
  * declaration order, so when the parent and the association share a key (e.g., `id`),
185
199
  * whichever is declared later wins: the association's value replaces an attribute declared
186
200
  * before the `rendersOne`, and an attribute declared after it replaces the association's.
187
- * When the association is `null`, every key its serializer declares renders as `null`
188
- * (for a polymorphic `BelongsTo`, every key the serializer of any of its target classes
189
- * declares, and for an association to an STI base, every key the serializer of any of its
190
- * STI children declares), in the same order (so an `id` declared before the `rendersOne` becomes
191
- * `null`); nothing in that serializer is rendered, so its custom attribute callbacks do
192
- * not run, and a flattened `customAttribute` in it adds no keys. Psychic adds the association's OpenAPI
193
- * schema to the parent's as an `allOf` branch, so a shared key's value must match both
194
- * schemas, whichever declaration wins
201
+ * Each key its serializer requires always renders, as `null` wherever the association
202
+ * does not supply it: an attribute, delegatedAttribute or customAttribute declared without
203
+ * `required: false`, and every non-flattened `rendersOne` and `rendersMany` (for a
204
+ * polymorphic `BelongsTo`, each key the serializer of any of its target classes requires,
205
+ * and for an association to an STI base, each key the serializer of any of its STI children
206
+ * requires), in the same order (so an `id` declared before the `rendersOne` becomes `null`
207
+ * when the association is `null`). A flattened `customAttribute` in that serializer adds the
208
+ * keys its `openapi` requires: a key an object shape lists in its `required` array, a key a
209
+ * `$serializer` or `$serializable` ref's serializer declares without `required: false`, and
210
+ * each such key of an `allOf`, `anyOf` or `oneOf` member; a ref with `many: true` adds none,
211
+ * and a flattened `customAttribute` declared with `required: false` adds none. When the
212
+ * association is `null`, each of these keys renders as `null` and nothing in its serializer
213
+ * is rendered, so its custom attribute callbacks do not run. When it is present, the held
214
+ * object's serializer renders its own keys over them, so a key another STI child's or
215
+ * target's serializer requires renders as `null` where the held one's serializer does not
216
+ * render it, including a key that serializer declares with `required: false`; the payload
217
+ * always includes the same keys whichever is held and whether the association is `null`. A
218
+ * key declared with `required: false` that no serializer requires stays absent unless it
219
+ * renders. The association's OpenAPI schema describes the parent's payload too, so a shared
220
+ * key's value must match both the parent's declaration and the association's, whichever
221
+ * declaration wins
195
222
  * - `optional` - When `true`, allows the association to be null/missing without causing
196
223
  * an `OpenapiResponseValidationFailure` during Psychic controller unit specs. By default,
197
224
  * `rendersOne` expects the association to be present (mirroring the `optional` option on
@@ -249,8 +276,9 @@ export default class ObjectSerializerBuilder<MaybeNullDataType extends object |
249
276
  * If `true`, the rendered association's attributes are merged directly into
250
277
  * the parent object instead of being nested under the association key. A key
251
278
  * the parent shares with the association takes the value of whichever is
252
- * declared later, and when the association is `null`, every key its serializer
253
- * declares renders as `null`. See the `flatten` option of `rendersOne`.
279
+ * declared later, and each key its serializer requires renders, as `null`
280
+ * wherever the association does not supply it. See the `flatten` option of
281
+ * `rendersOne`.
254
282
  */
255
283
  flatten?: boolean;
256
284
  /**
@@ -0,0 +1,85 @@
1
+ import { OpenapiSchemaBodyShorthand, OpenapiShorthandPrimitiveTypes } from '../../types/openapi.js';
2
+ import { DreamModelSerializerType, SerializerCasing, SimpleObjectSerializerType } from '../../types/serializer.js';
3
+ export interface NullFlattenedSerializerKeysOptions {
4
+ casing?: SerializerCasing;
5
+ passthroughData?: object;
6
+ }
7
+ /**
8
+ * The keys a flattened `rendersOne` always adds to the parent's payload, returned as an object
9
+ * with each key set to `null`, ready to spread into the parent's payload (`Object.keys` of it for
10
+ * the key names alone): each key one of `serializers` requires. When the associated object is
11
+ * null, these are the keys it renders; when it is present, the rendered serializer's own keys
12
+ * render over them, so each of these it leaves out stays `null` and the payload always includes
13
+ * these keys, whichever serializer renders and whether the object is null. As a property read on
14
+ * an empty object is `undefined`, a null value carries no key it may omit: an attribute,
15
+ * delegatedAttribute or customAttribute declared with `required: false` adds no key unless another
16
+ * of `serializers` requires it. Every key is cased per `casing`, as the renderer cases it. There
17
+ * are several serializers when the association is a polymorphic BelongsTo, one for each target
18
+ * class, or when the associated class is an STI base, one for each child, and their required keys
19
+ * are unioned.
20
+ *
21
+ * Each serializer is built with `undefined` data to read its declarations, as Psychic's OpenAPI
22
+ * generation and `preloadFor` build it, and nothing is rendered: no attribute callback runs and
23
+ * no association of the missing object is read. A non-flattened `rendersOne` or a `rendersMany`
24
+ * always adds its key. A flattened `rendersOne` it declares adds its own serializers' required keys
25
+ * the same way. A flattened `customAttribute` adds the keys its `openapi` requires: each key of
26
+ * its `properties` that the shape's `required` array lists, the required keys of the serializer a
27
+ * `$serializer` ref names or of every serializer a `$serializable` ref resolves to (one per child
28
+ * for an STI base), walked the same way, and the union of the keys every member of an `allOf`,
29
+ * `anyOf` or `oneOf` requires, with each key an object shape's own `required` array lists beside
30
+ * its members; one declared with `required: false` adds none. A ref with `many: true` adds none,
31
+ * since a list has no keys to spread. A serializer reached again within its own walk, as when one
32
+ * flattens itself, adds nothing, so the walk always terminates; one reached again along another
33
+ * path is walked again, so each path adds its keys and their requirements.
34
+ *
35
+ * `passthroughData` is handed to each serializer as it is built, as when rendering; outside a
36
+ * render it may be left out.
37
+ */
38
+ export declare function nullFlattenedSerializerKeys(serializers: (DreamModelSerializerType | SimpleObjectSerializerType)[], options?: NullFlattenedSerializerKeysOptions): Record<string, null>;
39
+ /**
40
+ * The keys a flattened `customAttribute` with this `openapi` always adds to the parent's payload,
41
+ * each set to `null`: each key any shape of `openapi` requires, walked as
42
+ * `nullFlattenedSerializerKeys` walks a flattened `customAttribute` and cased per `casing`. When
43
+ * its callback returns null (or `undefined` without `required: false`), or a serializer built over
44
+ * null data, these are the keys it renders; when it returns any other value, that value's own keys
45
+ * render over them, so each of these the value leaves out, or a returned plain object sets to
46
+ * `undefined`, stays `null`. With `required: false`, a callback that returns `undefined` adds none
47
+ * of them.
48
+ */
49
+ export declare function nullFlattenedOpenapiKeys(openapi: OpenapiSchemaBodyShorthand | OpenapiShorthandPrimitiveTypes, options?: NullFlattenedSerializerKeysOptions): Record<string, null>;
50
+ /**
51
+ * The keys only the other variants of a flattened `rendersOne` contribute to its payload, each set
52
+ * to `null`: each key one of `serializers` (every serializer the association may render with)
53
+ * requires that `renderedSerializer` does not declare at all. A key `renderedSerializer` declares
54
+ * is left out even when it declares it with `required: false` and another serializer requires it;
55
+ * the renderer fills that key with `null` too, since it renders every key
56
+ * `nullFlattenedSerializerKeys` returns beneath the rendered serializer's own keys.
57
+ */
58
+ export declare function nullFlattenedSerializerKeysOfOtherVariants(serializers: (DreamModelSerializerType | SimpleObjectSerializerType)[], renderedSerializer: DreamModelSerializerType | SimpleObjectSerializerType, options?: NullFlattenedSerializerKeysOptions): Record<string, null>;
59
+ /**
60
+ * The keys only the other variants of a flattened `customAttribute` with this `openapi` contribute
61
+ * to its payload, each set to `null`: each key a variant of `openapi` requires that
62
+ * `renderedVariant` does not declare. `renderedVariant` is any `openapi` shorthand: one member of
63
+ * an `anyOf` or `oneOf`, or `{ $serializer: childSerializer }` for one child of a `$serializable`
64
+ * ref to an STI base. A key requires its value when an object shape's `required` array lists it,
65
+ * whether the shape's own `properties` declare it or a member of its `allOf`, `anyOf` or `oneOf`
66
+ * does, or when a serializer declares it without `required: false`. A key `renderedVariant`
67
+ * declares is left out even when it is optional there and another variant requires it; the
68
+ * renderer fills that key with `null` too, since it renders every key `nullFlattenedOpenapiKeys`
69
+ * returns beneath the value's own keys.
70
+ */
71
+ export declare function nullFlattenedOpenapiKeysOfOtherVariants(openapi: OpenapiSchemaBodyShorthand | OpenapiShorthandPrimitiveTypes, renderedVariant: OpenapiSchemaBodyShorthand | OpenapiShorthandPrimitiveTypes, options?: NullFlattenedSerializerKeysOptions): Record<string, null>;
72
+ /**
73
+ * Lists the single shapes a value of a flattened `customAttribute` with this `openapi` may take,
74
+ * which a consumer can union into one description of the flattened payload: a `$serializer` ref to
75
+ * each serializer a `$serializable` ref resolves to (one per child for an STI base), or the members
76
+ * of an `anyOf` or `oneOf` (an `anyOf`'s members listed before a sibling `oneOf`'s, not paired with
77
+ * them), each member that itself has several shapes (a nested `anyOf` or `oneOf`, or a
78
+ * `$serializable` ref to an STI base) contributing those shapes in its place. An `allOf` beside
79
+ * the `anyOf` or `oneOf` describes every value, so each shape is that `allOf` with the shape added
80
+ * to its members. Anything else (a single shape, a ref with `many: true`, or a primitive) has no
81
+ * variants and returns an empty list. Each shape may be passed back as the `renderedVariant` of
82
+ * `nullFlattenedOpenapiKeysOfOtherVariants`. The renderer does not read a value's shape from this
83
+ * list: whatever shape the value takes, it renders every key `nullFlattenedOpenapiKeys` returns.
84
+ */
85
+ export declare function flattenedOpenapiVariants(openapi: OpenapiSchemaBodyShorthand | OpenapiShorthandPrimitiveTypes): OpenapiSchemaBodyShorthand[];
@@ -1,9 +1,10 @@
1
1
  import Dream from '../../Dream.js';
2
2
  import { DreamModelSerializerType, InternalAnyRendersOneOrManyOpts, SimpleObjectSerializerType } from '../../types/serializer.js';
3
3
  /**
4
- * Only used when flatten: true, and the associated object is null, in which case there is no
5
- * object to resolve a serializer from, but the renderer still needs the serializers whose keys it
6
- * renders as null in the parent's payload.
4
+ * Used by every flattened rendersOne render, whether the associated object is present or null: it
5
+ * lists every serializer the association may render with, whose required keys the renderer renders
6
+ * as null in the parent's payload, beneath the present object's own keys or alone when the object
7
+ * is null, where there is no object to resolve a serializer from.
7
8
  *
8
9
  * Resolves, in order, to the `serializer` option, the serializers of the `dreamClass` or
9
10
  * `viewModelClass` option, or the serializers of each class `parentClass` declares the association