Files
daily-notification-plugin/ios/Plugin/NotificationConfigDAO.swift
Jose Olarte III 1bfd87a0e4 fix(ios): resolve build errors and add missing configureNativeFetcher method
Fixed Swift compilation errors preventing iOS build:
- Added explicit self capture [self] in closures in DailyNotificationReactivationManager
- Removed invalid BGTaskScheduler.shared.registeredTaskIdentifiers API call
- Fixed initialization order in DailyNotificationModel (verifyEntities after container init)

Added missing configureNativeFetcher method to iOS plugin:
- Implemented method matching Android functionality
- Stores configuration in UserDefaults for persistence
- Registered method in pluginMethods array
- Supports both jwtToken and jwtSecret parameters for compatibility

This resolves the runtime error "configureNativeFetcher is not a function"
that was preventing the test app from configuring the plugin.
2025-12-11 16:44:18 +08:00

412 lines
13 KiB
Swift

/**
* NotificationConfigDAO.swift
*
* Data Access Object (DAO) for NotificationConfig Core Data entity
* Provides CRUD operations and query helpers for notification configuration
*
* @author Matthew Raymer
* @version 1.0.0
* @created 2025-12-08
*/
import Foundation
import CoreData
/**
* Extension providing DAO methods for NotificationConfig entity
*
* This extension adds CRUD operations and query helpers to the
* auto-generated NotificationConfig Core Data class.
*/
extension NotificationConfig {
// MARK: - Constants
private static let TAG = "DNP-NOTIFICATION-CONFIG-DAO"
// MARK: - Create/Insert Methods
/**
* Create a new NotificationConfig entity in the given context
*
* @param context Core Data managed object context
* @param id Unique configuration identifier
* @param timesafariDid TimeSafari device ID
* @param configType Type of configuration
* @param configKey Configuration key
* @param configValue Configuration value (string representation)
* @param configDataType Data type of value (e.g., "string", "int", "bool", "json")
* @param isEncrypted Whether value is encrypted
* @param encryptionKeyId Encryption key identifier
* @param ttlSeconds Time-to-live in seconds
* @param isActive Whether configuration is active
* @param metadata Additional metadata (JSON string)
* @return Created NotificationConfig entity
*/
static func create(
in context: NSManagedObjectContext,
id: String,
timesafariDid: String? = nil,
configType: String? = nil,
configKey: String? = nil,
configValue: String? = nil,
configDataType: String? = nil,
isEncrypted: Bool = false,
encryptionKeyId: String? = nil,
ttlSeconds: Int64 = 604800, // 7 days default
isActive: Bool = true,
metadata: String? = nil
) -> NotificationConfig {
let entity = NotificationConfig(context: context)
let now = Date()
entity.id = id
entity.timesafariDid = timesafariDid
entity.configType = configType
entity.configKey = configKey
entity.configValue = configValue
entity.configDataType = configDataType
entity.isEncrypted = isEncrypted
entity.encryptionKeyId = encryptionKeyId
entity.createdAt = now
entity.updatedAt = now
entity.ttlSeconds = ttlSeconds
entity.isActive = isActive
entity.metadata = metadata
print("\(Self.TAG): Created NotificationConfig with id: \(id)")
return entity
}
/**
* Create from dictionary representation
*
* @param context Core Data managed object context
* @param dict Dictionary with configuration data
* @return Created NotificationConfig entity or nil
*/
static func create(
in context: NSManagedObjectContext,
from dict: [String: Any]
) -> NotificationConfig? {
guard let id = dict["id"] as? String else {
print("\(Self.TAG): Missing required 'id' field")
return nil
}
// Convert createdAt/updatedAt if present
let createdAt: Date
if let createdMillis = dict["createdAt"] as? Int64 {
createdAt = DailyNotificationDataConversions.dateFromEpochMillis(createdMillis)
} else if let createdDate = dict["createdAt"] as? Date {
createdAt = createdDate
} else {
createdAt = Date()
}
let updatedAt: Date
if let updatedMillis = dict["updatedAt"] as? Int64 {
updatedAt = DailyNotificationDataConversions.dateFromEpochMillis(updatedMillis)
} else if let updatedDate = dict["updatedAt"] as? Date {
updatedAt = updatedDate
} else {
updatedAt = Date()
}
let entity = NotificationConfig(context: context)
entity.id = id
entity.timesafariDid = dict["timesafariDid"] as? String
entity.configType = dict["configType"] as? String
entity.configKey = dict["configKey"] as? String
entity.configValue = dict["configValue"] as? String
entity.configDataType = dict["configDataType"] as? String
entity.isEncrypted = dict["isEncrypted"] as? Bool ?? false
entity.encryptionKeyId = dict["encryptionKeyId"] as? String
entity.createdAt = createdAt
entity.updatedAt = updatedAt
entity.ttlSeconds = dict["ttlSeconds"] as? Int64 ?? 604800
entity.isActive = dict["isActive"] as? Bool ?? true
entity.metadata = dict["metadata"] as? String
return entity
}
// MARK: - Read/Query Methods
/**
* Fetch NotificationConfig by ID
*
* @param context Core Data managed object context
* @param id Configuration ID
* @return NotificationConfig entity or nil
*/
static func fetch(
by id: String,
in context: NSManagedObjectContext
) -> NotificationConfig? {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(format: "id == %@", id)
request.fetchLimit = 1
do {
let results = try context.fetch(request)
return results.first
} catch {
print("\(Self.TAG): Error fetching by id: \(error.localizedDescription)")
return nil
}
}
/**
* Fetch NotificationConfig by key (configKey)
*
* @param context Core Data managed object context
* @param configKey Configuration key
* @return NotificationConfig entity or nil
*/
static func fetchByConfigKey(
_ configKey: String,
in context: NSManagedObjectContext
) -> NotificationConfig? {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(format: "configKey == %@", configKey)
request.fetchLimit = 1
do {
let results = try context.fetch(request)
return results.first
} catch {
print("\(Self.TAG): Error fetching by configKey: \(error.localizedDescription)")
return nil
}
}
/**
* Fetch all NotificationConfig entities
*
* @param context Core Data managed object context
* @return Array of NotificationConfig entities
*/
static func fetchAll(
in context: NSManagedObjectContext
) -> [NotificationConfig] {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
do {
return try context.fetch(request)
} catch {
print("\(Self.TAG): Error fetching all: \(error.localizedDescription)")
return []
}
}
/**
* Query by timesafariDid
*
* @param context Core Data managed object context
* @param timesafariDid TimeSafari device ID
* @return Array of NotificationConfig entities
*/
static func queryByTimesafariDid(
_ timesafariDid: String,
in context: NSManagedObjectContext
) -> [NotificationConfig] {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(format: "timesafariDid == %@", timesafariDid)
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
do {
return try context.fetch(request)
} catch {
print("\(Self.TAG): Error querying by timesafariDid: \(error.localizedDescription)")
return []
}
}
/**
* Query by configType
*
* @param context Core Data managed object context
* @param configType Configuration type
* @return Array of NotificationConfig entities
*/
static func queryByConfigType(
_ configType: String,
in context: NSManagedObjectContext
) -> [NotificationConfig] {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(format: "configType == %@", configType)
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
do {
return try context.fetch(request)
} catch {
print("\(Self.TAG): Error querying by configType: \(error.localizedDescription)")
return []
}
}
/**
* Query active configurations only
*
* @param context Core Data managed object context
* @return Array of active NotificationConfig entities
*/
static func queryActive(
in context: NSManagedObjectContext
) -> [NotificationConfig] {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(format: "isActive == YES")
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
do {
return try context.fetch(request)
} catch {
print("\(Self.TAG): Error querying active: \(error.localizedDescription)")
return []
}
}
/**
* Query by configType and isActive
*
* @param context Core Data managed object context
* @param configType Configuration type
* @param isActive Whether configuration is active
* @return Array of NotificationConfig entities
*/
static func query(
by configType: String,
isActive: Bool,
in context: NSManagedObjectContext
) -> [NotificationConfig] {
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
request.predicate = NSPredicate(
format: "configType == %@ AND isActive == %@",
configType,
NSNumber(value: isActive)
)
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
do {
return try context.fetch(request)
} catch {
print("\(Self.TAG): Error querying by configType and isActive: \(error.localizedDescription)")
return []
}
}
// MARK: - Update Methods
/**
* Update configuration value
*
* @param value New configuration value
*/
func updateValue(_ value: String?) {
self.configValue = value
self.updatedAt = Date()
}
/**
* Activate or deactivate configuration
*
* @param active Whether configuration should be active
*/
func setActive(_ active: Bool) {
self.isActive = active
self.updatedAt = Date()
}
/**
* Update this entity's updatedAt timestamp
*/
func touch() {
self.updatedAt = Date()
}
// MARK: - Delete Methods
/**
* Delete NotificationConfig by ID
*
* @param context Core Data managed object context
* @param id Configuration ID
* @return true if deleted, false otherwise
*/
static func delete(
by id: String,
in context: NSManagedObjectContext
) -> Bool {
guard let entity = fetch(by: id, in: context) else {
return false
}
context.delete(entity)
do {
try context.save()
print("\(Self.TAG): Deleted NotificationConfig with id: \(id)")
return true
} catch {
print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
context.rollback()
return false
}
}
/**
* Delete NotificationConfig by configKey
*
* @param context Core Data managed object context
* @param configKey Configuration key
* @return true if deleted, false otherwise
*/
static func deleteByConfigKey(
_ configKey: String,
in context: NSManagedObjectContext
) -> Bool {
guard let entity = fetchByConfigKey(configKey, in: context) else {
return false
}
context.delete(entity)
do {
try context.save()
print("\(Self.TAG): Deleted NotificationConfig with configKey: \(configKey)")
return true
} catch {
print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
context.rollback()
return false
}
}
/**
* Delete all NotificationConfig entities
*
* @param context Core Data managed object context
* @return Number of entities deleted
*/
static func deleteAll(
in context: NSManagedObjectContext
) -> Int {
let request: NSFetchRequest<NSFetchRequestResult> = NotificationConfig.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do {
let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
try context.save()
let count = result?.result as? Int ?? 0
print("\(Self.TAG): Deleted \(count) NotificationConfig entities")
return count
} catch {
print("\(Self.TAG): Error deleting all: \(error.localizedDescription)")
context.rollback()
return 0
}
}
}