Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuawright11 committed Jun 23, 2024
1 parent 5ca1f94 commit b1ec1aa
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 192 deletions.
2 changes: 1 addition & 1 deletion Alchemy/Database/Rune/Model/ModelStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public final class ModelStorage<M: Model>: Codable, Equatable {

// 1. encode encodable relationships
for (key, relationship) in relationships {
if let relationship = relationship as? Encodable, let name = key.name {
if let relationship = relationship as? Encodable, let name = key.key {
try container.encode(AnyEncodable(relationship), forKey: .key(name))
}
}
Expand Down
4 changes: 2 additions & 2 deletions Alchemy/Database/Rune/Relations/EagerLoadable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ public protocol EagerLoadable<From, To> {
}

public struct CacheKey: Hashable {
public let name: String?
public let key: String?
public let value: String
}

extension EagerLoadable {
public var cacheKey: CacheKey {
CacheKey(name: nil, value: "\(Self.self)")
CacheKey(key: nil, value: "\(Self.self)")
}

public var isLoaded: Bool {
Expand Down
8 changes: 4 additions & 4 deletions Alchemy/Database/Rune/Relations/Relationship.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class Relationship<From: Model, To: OneOrMany>: Query<To.M>, EagerLoadabl
var throughs: [Through]

/// Relationships will be encoded at this key.
var name: String? = nil
var key: String? = nil

public override var sql: SQL {
sql(for: [from])
Expand All @@ -29,7 +29,7 @@ public class Relationship<From: Model, To: OneOrMany>: Query<To.M>, EagerLoadabl
let key = "\(Self.self)_\(fromKey)_\(toKey)"
let throughKeys = throughs.map { "\($0.table)_\($0.from)_\($0.to)" }
let whereKeys = wheres.map { "\($0.hashValue)" }
return CacheKey(name: name, value: ([key] + throughKeys + whereKeys).joined(separator: ":"))
return CacheKey(key: key, value: ([key] + throughKeys + whereKeys).joined(separator: ":"))
}

public init(db: Database, from: From, fromKey: SQLKey, toKey: SQLKey) {
Expand Down Expand Up @@ -91,8 +91,8 @@ public class Relationship<From: Model, To: OneOrMany>: Query<To.M>, EagerLoadabl
return value
}

public func named(_ name: String) -> Self {
self.name = name
public func key(_ key: String) -> Self {
self.key = key
return self
}
}
104 changes: 104 additions & 0 deletions AlchemyPlugin/Sources/Helpers/Model.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import SwiftSyntax

struct Model {
struct Property {
/// either let or var
let keyword: String
let name: String
let type: String?
let defaultValue: String?
let isStored: Bool
}

/// The type's access level - public, private, etc
let accessLevel: String?
/// The type name
let name: String
/// The type's properties
let properties: [Property]

/// The type's stored properties
var storedProperties: [Property] {
properties.filter(\.isStored)
}

var storedPropertiesExceptId: [Property] {
storedProperties.filter { $0.name != "id" }
}

var idProperty: Property? {
storedProperties.filter { $0.name == "id" }.first
}
}

extension Model {
static func parse(syntax: DeclSyntaxProtocol) throws -> Model {
guard let `struct` = syntax.as(StructDeclSyntax.self) else {
throw AlchemyMacroError("For now, @Model can only be applied to a struct")
}

return Model(
accessLevel: `struct`.accessLevel,
name: `struct`.structName,
properties: try `struct`.instanceMembers.map(Model.Property.parse)
)
}
}

extension Model.Property {
static func parse(variable: VariableDeclSyntax) throws -> Model.Property {
let patternBindings = variable.bindings.compactMap { PatternBindingSyntax.init($0) }
let keyword = variable.bindingSpecifier.text

guard let patternBinding = patternBindings.first else {
throw AlchemyMacroError("Property had no pattern bindings")
}

guard let identifierPattern = patternBinding.pattern.as(IdentifierPatternSyntax.self) else {
throw AlchemyMacroError("Unable to detect property name")
}

let name = "\(identifierPattern.identifier.text)"
let type = patternBinding.typeAnnotation?.type.trimmedDescription
let defaultValue = patternBinding.initializer.map { "\($0.value.trimmed)" }
let isStored = patternBinding.accessorBlock == nil

return Model.Property(
keyword: keyword,
name: name,
type: type,
defaultValue: defaultValue,
isStored: isStored
)
}
}

extension DeclGroupSyntax {
fileprivate var accessLevel: String? {
modifiers.first?.trimmedDescription
}

var functions: [FunctionDeclSyntax] {
memberBlock.members.compactMap { $0.decl.as(FunctionDeclSyntax.self) }
}

var initializers: [InitializerDeclSyntax] {
memberBlock.members.compactMap { $0.decl.as(InitializerDeclSyntax.self) }
}

var variables: [VariableDeclSyntax] {
memberBlock.members.compactMap { $0.decl.as(VariableDeclSyntax.self) }
}

fileprivate var instanceMembers: [VariableDeclSyntax] {
variables
.filter { !$0.isStatic }
.filter { $0.attributes.isEmpty }
}
}

extension StructDeclSyntax {
fileprivate var structName: String {
name.text
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ extension String {
var capitalizeFirst: String {
prefix(1).capitalized + dropFirst()
}

var lowercaseFirst: String {
prefix(1).lowercased() + dropFirst()
}
}

extension Collection {
Expand Down
19 changes: 19 additions & 0 deletions AlchemyPlugin/Sources/Helpers/SwiftSyntax+Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftSyntax

extension VariableDeclSyntax {
var isStatic: Bool {
modifiers.contains { $0.name.trimmedDescription == "static" }
}

var name: String {
bindings.compactMap {
$0.pattern.as(IdentifierPatternSyntax.self)?.identifier.trimmedDescription
}.first ?? "unknown"
}

var type: String {
bindings.compactMap {
$0.typeAnnotation?.type.trimmedDescription
}.first ?? "unknown"
}
}
2 changes: 1 addition & 1 deletion AlchemyPlugin/Sources/Macros/IDMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct IDMacro: AccessorMacro {
throw AlchemyMacroError("@ID can only be applied to a stored property.")
}

let property = try Resource.Property.parse(variable: variable)
let property = try Model.Property.parse(variable: variable)
guard property.keyword == "var" else {
throw AlchemyMacroError("Property 'id' must be a var.")
}
Expand Down
7 changes: 3 additions & 4 deletions AlchemyPlugin/Sources/Macros/JobMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ struct JobMacro: PeerMacro {
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
guard
let function = declaration.as(FunctionDeclSyntax.self),
function.isStatic
let function = declaration.as(FunctionDeclSyntax.self)
// function.isStatic
else {
throw AlchemyMacroError("@Job can only be applied to static functions")
throw AlchemyMacroError("@Job can only be applied to functions")
}

let name = function.name.text
return [
Declaration("struct $\(name): Job, Codable") {

for parameter in function.parameters {
"let \(parameter.name): \(parameter.type)"
}
Expand Down
Loading

0 comments on commit b1ec1aa

Please sign in to comment.