-
-
Notifications
You must be signed in to change notification settings - Fork 506
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Alexander Filimonov
committed
Apr 19, 2024
1 parent
5a5cd06
commit 37749b5
Showing
10 changed files
with
251 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../ios_app_with_coredata/CoreData/Unversioned.xcdatamodeld/Unversioned.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
fixtures/ios_app_with_coredata/CoreData/Users.xcdatamodeld/1.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
fixtures/ios_app_with_coredata/CoreData/Users.xcdatamodeld/2.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
fixtures/ios_app_with_coredata/CoreData/UsersAutoDetect.xcdatamodeld/1.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...ures/ios_app_with_coredata/CoreData/UsersAutoDetect.xcdatamodeld/2.5.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
fixtures/ios_app_with_coredata/CoreData/UsersAutoDetect.xcdatamodeld/2.xcdatamodel/contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
fixtures/ios_app_with_coredata/Tuist/ResourceSynthesizers/CoreData.stencil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
// swiftlint:disable all | ||
// swiftlint:disable superfluous_disable_command implicit_return | ||
// swiftlint:disable sorted_imports | ||
import CoreData | ||
import Foundation | ||
{% for import in param.extraImports %} | ||
import {{ import }} | ||
{% empty %} | ||
{# If extraImports is a single String instead of an array, `for` considers it empty but we still have to check if there's a single String value #} | ||
{%- if param.extraImports %} | ||
import {{ param.extraImports }} | ||
{% endif %} | ||
{% endfor %} | ||
|
||
// swiftlint:disable attributes file_length vertical_whitespace_closing_braces | ||
// swiftlint:disable identifier_name line_length type_body_length | ||
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %} | ||
|
||
{% for model in models %} | ||
{% for name, entity in model.entities %} | ||
{% set superclass %}{{ model.entities[entity.superEntity].className|default:"NSManagedObject" }}{% endset %} | ||
{% set entityClassName %}{{ entity.className|default:"NSManagedObject" }}{% endset %} | ||
{% set hasChildren %}{% for aName,anEntity in model.entities where anEntity.superEntity == name %}1{% endfor %}{% endset %} | ||
// MARK: - {{ entity.name }} | ||
|
||
{% if not entity.shouldGenerateCode %} | ||
// Note: '{{ entity.name }}' has codegen enabled for Xcode, skipping code generation. | ||
|
||
{% elif entityClassName|contains:"." %} | ||
// Warning: '{{ entityClassName }}' cannot be a valid type name, skipping code generation. | ||
|
||
{% else %} | ||
{% if param.generateObjcName %} | ||
@objc({{ entityClassName }}) | ||
{% endif %} | ||
{{ accessModifier }} {%+ if not entity.isAbstract and not hasChildren %}final {%+ endif %}class {{ entityClassName }}: {{ superclass }} { | ||
{% set override %}{% if superclass != "NSManagedObject" %}override {%+ endif %}{% endset %} | ||
{{ override }}{{ accessModifier }} class var entityName: String { | ||
return "{{ entity.name }}" | ||
} | ||
|
||
{{ override }}{{ accessModifier }} class func entity(in managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? { | ||
return NSEntityDescription.entity(forEntityName: entityName, in: managedObjectContext) | ||
} | ||
|
||
@available(*, deprecated, renamed: "makeFetchRequest", message: "To avoid collisions with the less concrete method in `NSManagedObject`, please use `makeFetchRequest()` instead.") | ||
@nonobjc {{ accessModifier }} class func fetchRequest() -> NSFetchRequest<{{ entityClassName }}> { | ||
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName) | ||
} | ||
|
||
@nonobjc {{ accessModifier }} class func makeFetchRequest() -> NSFetchRequest<{{ entityClassName }}> { | ||
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName) | ||
} | ||
|
||
// swiftlint:disable discouraged_optional_boolean discouraged_optional_collection implicit_getter | ||
{% for attribute in entity.attributes %} | ||
{% if attribute.userInfo.RawType %} | ||
{% set rawType attribute.userInfo.RawType %} | ||
{% set unwrapOptional attribute.userInfo.unwrapOptional %} | ||
{{ accessModifier }} var {{ attribute.name }}: {{ rawType }}{% if not unwrapOptional %}?{% endif %} { | ||
get { | ||
let key = "{{ attribute.name }}" | ||
willAccessValue(forKey: key) | ||
defer { didAccessValue(forKey: key) } | ||
|
||
guard let value = primitiveValue(forKey: key) as? {{ rawType }}.RawValue else { | ||
{%+ if unwrapOptional %}fatalError("Could not convert value for key '\(key)' to type '{{ rawType }}.RawValue'"){% else %}return nil{% endif +%} | ||
} | ||
{% if attribute.userInfo.nonOptionalInit or not unwrapOptional %} | ||
return {{ rawType }}(rawValue: value) | ||
{% else %} | ||
guard let result = {{ rawType }}(rawValue: value) else { | ||
fatalError("Could not convert value for key '\(key)' to type '{{ rawType }}'") | ||
} | ||
return result | ||
{% endif %} | ||
} | ||
{% if not attribute.isDerived %} | ||
set { | ||
let key = "{{ attribute.name }}" | ||
willChangeValue(forKey: key) | ||
defer { didChangeValue(forKey: key) } | ||
|
||
setPrimitiveValue(newValue{% if not unwrapOptional %}?{% endif %}.rawValue, forKey: key) | ||
} | ||
{% endif %} | ||
} | ||
{% elif attribute.usesScalarValueType and attribute.isOptional %} | ||
{{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}? { | ||
get { | ||
let key = "{{ attribute.name }}" | ||
willAccessValue(forKey: key) | ||
defer { didAccessValue(forKey: key) } | ||
|
||
return primitiveValue(forKey: key) as? {{ attribute.typeName }} | ||
} | ||
{% if not attribute.isDerived %} | ||
set { | ||
let key = "{{ attribute.name }}" | ||
willChangeValue(forKey: key) | ||
defer { didChangeValue(forKey: key) } | ||
|
||
setPrimitiveValue(newValue, forKey: key) | ||
} | ||
{% endif %} | ||
} | ||
{% elif attribute.isDerived %} | ||
{{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}{% if attribute.isOptional %}?{% endif %} { | ||
let key = "{{ attribute.name }}" | ||
willAccessValue(forKey: key) | ||
defer { didAccessValue(forKey: key) } | ||
|
||
{% if attribute.isOptional %} | ||
return primitiveValue(forKey: key) as? {{ attribute.typeName }} | ||
{% else %} | ||
guard let value = primitiveValue(forKey: key) as? {{ attribute.typeName }} else { | ||
fatalError("Could not convert value for key '\(key)' to type '{{ attribute.typeName }}'") | ||
} | ||
return value | ||
{% endif %} | ||
} | ||
{% else %} | ||
@NSManaged {{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}{% if attribute.isOptional %}?{% endif +%} | ||
{% endif %} | ||
{% endfor %} | ||
{% for relationship in entity.relationships %} | ||
{% if relationship.isToMany %} | ||
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {%+ if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}>{% endif %}{% if relationship.isOptional %}?{% endif +%} | ||
{% else %} | ||
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% if relationship.isOptional %}?{% endif +%} | ||
{% endif %} | ||
{% endfor %} | ||
{% for fetchedProperty in entity.fetchedProperties %} | ||
@NSManaged {{ accessModifier }} var {{ fetchedProperty.name }}: [{{ model.entities[fetchedProperty.fetchRequest.entity].className|default:"NSManagedObject" }}] | ||
{% endfor %} | ||
// swiftlint:enable discouraged_optional_boolean discouraged_optional_collection implicit_getter | ||
} | ||
|
||
{% for relationship in entity.relationships where relationship.isToMany %} | ||
{% set destinationEntityClassName %}{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% endset %} | ||
{% set collectionClassName %}{% if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ destinationEntityClassName }}>{% endif %}{% endset %} | ||
{% set relationshipName %}{{ relationship.name | upperFirstLetter }}{% endset %} | ||
// MARK: Relationship {{ relationshipName }} | ||
|
||
extension {{ entityClassName }} { | ||
{% if relationship.isOrdered %} | ||
@objc(insertObject:in{{ relationshipName }}AtIndex:) | ||
@NSManaged public func insertInto{{ relationshipName }}(_ value: {{ destinationEntityClassName }}, at idx: Int) | ||
|
||
@objc(removeObjectFrom{{ relationshipName }}AtIndex:) | ||
@NSManaged public func removeFrom{{ relationshipName }}(at idx: Int) | ||
|
||
@objc(insert{{ relationshipName }}:atIndexes:) | ||
@NSManaged public func insertInto{{ relationshipName }}(_ values: [{{ destinationEntityClassName }}], at indexes: NSIndexSet) | ||
|
||
@objc(remove{{ relationshipName }}AtIndexes:) | ||
@NSManaged public func removeFrom{{ relationshipName }}(at indexes: NSIndexSet) | ||
|
||
@objc(replaceObjectIn{{ relationshipName }}AtIndex:withObject:) | ||
@NSManaged public func replace{{ relationshipName }}(at idx: Int, with value: {{ destinationEntityClassName }}) | ||
|
||
@objc(replace{{ relationshipName }}AtIndexes:with{{ relationshipName }}:) | ||
@NSManaged public func replace{{ relationshipName }}(at indexes: NSIndexSet, with values: [{{ destinationEntityClassName }}]) | ||
|
||
{% endif %} | ||
@objc(add{{ relationshipName }}Object:) | ||
@NSManaged public func addTo{{ relationshipName }}(_ value: {{ destinationEntityClassName }}) | ||
|
||
@objc(remove{{ relationshipName }}Object:) | ||
@NSManaged public func removeFrom{{ relationshipName }}(_ value: {{ destinationEntityClassName }}) | ||
|
||
@objc(add{{ relationshipName }}:) | ||
@NSManaged public func addTo{{ relationshipName }}(_ values: {{ collectionClassName }}) | ||
|
||
@objc(remove{{ relationshipName }}:) | ||
@NSManaged public func removeFrom{{ relationshipName }}(_ values: {{ collectionClassName }}) | ||
} | ||
|
||
{% endfor %} | ||
{% if model.fetchRequests[entity.name].count > 0 %} | ||
// MARK: Fetch Requests | ||
|
||
extension {{ entityClassName }} { | ||
{% for fetchRequest in model.fetchRequests[entity.name] %} | ||
{% set resultTypeName -%} | ||
{%- if fetchRequest.resultType == "Object" -%} | ||
{{ entityClassName }} | ||
{%- elif fetchRequest.resultType == "Object ID" -%} | ||
NSManagedObjectID | ||
{%- elif fetchRequest.resultType == "Dictionary" -%} | ||
[String: Any] | ||
{%- endif -%} | ||
{%- endset %} | ||
class func fetch{{ fetchRequest.name | upperFirstLetter }}(managedObjectContext: NSManagedObjectContext | ||
{%- for variableName, variableType in fetchRequest.substitutionVariables -%} | ||
, {{ variableName | lowerFirstWord }}: {{ variableType }} | ||
{%- endfor -%} | ||
) throws -> [{{ resultTypeName }}] { | ||
guard let persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator else { | ||
fatalError("Managed object context has no persistent store coordinator for getting fetch request templates") | ||
} | ||
let model = persistentStoreCoordinator.managedObjectModel | ||
let substitutionVariables: [String: Any] = [ | ||
{% for variableName, variableType in fetchRequest.substitutionVariables %} | ||
"{{ variableName }}": {{ variableName | lowerFirstWord }}{{ "," if not forloop.last }} | ||
{% empty %} | ||
: | ||
{% endfor %} | ||
] | ||
|
||
guard let fetchRequest = model.fetchRequestFromTemplate(withName: "{{ fetchRequest.name }}", substitutionVariables: substitutionVariables) else { | ||
fatalError("No fetch request template named '{{ fetchRequest.name }}' found.") | ||
} | ||
|
||
guard let result = try managedObjectContext.fetch(fetchRequest) as? [{{ resultTypeName }}] else { | ||
fatalError("Unable to cast fetch result to correct result type.") | ||
} | ||
|
||
return result | ||
} | ||
|
||
{% endfor %} | ||
} | ||
|
||
{% endif %} | ||
{% endif %} | ||
{% endfor %} | ||
{% endfor %} | ||
// swiftlint:enable identifier_name line_length type_body_length |