Skip to content

Commit 2cb57bc

Browse files
committed
Init
0 parents  commit 2cb57bc

25 files changed

Lines changed: 1783 additions & 0 deletions

.gitignore

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Created by https://www.toptal.com/developers/gitignore/api/swift
2+
# Edit at https://www.toptal.com/developers/gitignore?templates=swift
3+
4+
### Swift ###
5+
# Xcode
6+
#
7+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8+
9+
## User settings
10+
xcuserdata/
11+
12+
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
13+
*.xcscmblueprint
14+
*.xccheckout
15+
16+
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
17+
build/
18+
DerivedData/
19+
*.moved-aside
20+
*.pbxuser
21+
!default.pbxuser
22+
*.mode1v3
23+
!default.mode1v3
24+
*.mode2v3
25+
!default.mode2v3
26+
*.perspectivev3
27+
!default.perspectivev3
28+
29+
## Obj-C/Swift specific
30+
*.hmap
31+
32+
## App packaging
33+
*.ipa
34+
*.dSYM.zip
35+
*.dSYM
36+
37+
## Playgrounds
38+
timeline.xctimeline
39+
playground.xcworkspace
40+
41+
# Swift Package Manager
42+
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
43+
# Packages/
44+
# Package.pins
45+
# Package.resolved
46+
# *.xcodeproj
47+
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
48+
# hence it is not needed unless you have added a package configuration file to your project
49+
# .swiftpm
50+
51+
.build/
52+
53+
# CocoaPods
54+
# We recommend against adding the Pods directory to your .gitignore. However
55+
# you should judge for yourself, the pros and cons are mentioned at:
56+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
57+
# Pods/
58+
# Add this line if you want to avoid checking in source code from the Xcode workspace
59+
# *.xcworkspace
60+
61+
# Carthage
62+
# Add this line if you want to avoid checking in source code from Carthage dependencies.
63+
# Carthage/Checkouts
64+
65+
Carthage/Build/
66+
67+
# Accio dependency management
68+
Dependencies/
69+
.accio/
70+
71+
# fastlane
72+
# It is recommended to not store the screenshots in the git repo.
73+
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
74+
# For more information about the recommended setup visit:
75+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
76+
77+
fastlane/report.xml
78+
fastlane/Preview.html
79+
fastlane/screenshots/**/*.png
80+
fastlane/test_output
81+
82+
# Code Injection
83+
# After new code Injection tools there's a generated folder /iOSInjectionProject
84+
# https://github.com/johnno1962/injectionforxcode
85+
86+
iOSInjectionProject/
87+
.DS_Store
88+
.swiftpm
89+
# End of https://www.toptal.com/developers/gitignore/api/swift

Package.resolved

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// swift-tools-version: 6.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import CompilerPluginSupport
5+
import PackageDescription
6+
7+
let package = Package(
8+
name: "Normalization",
9+
platforms: [
10+
.macOS(.v11),
11+
.iOS(.v13),
12+
.tvOS(.v13),
13+
.watchOS(.v6),
14+
],
15+
products: [
16+
// Products define the executables and libraries a package produces, making them visible to other packages.
17+
.library(
18+
name: "Normalization",
19+
targets: ["Normalization"])
20+
],
21+
dependencies: [
22+
.package(url: "https://github.com/apple/swift-collections", from: "1.1.0"),
23+
.package(url: "https://github.com/VergeGroup/TypedComparator", from: "1.0.0"),
24+
.package(url: "https://github.com/VergeGroup/TypedIdentifier", from: "2.0.2"),
25+
.package(url: "https://github.com/apple/swift-syntax.git", from: "600.0.0"),
26+
.package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.2.1"),
27+
],
28+
targets: [
29+
.macro(
30+
name: "NormalizationMacrosPlugin",
31+
dependencies: [
32+
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
33+
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
34+
]
35+
),
36+
.target(
37+
name: "Normalization",
38+
dependencies: [
39+
"NormalizationMacrosPlugin",
40+
.product(name: "TypedIdentifier", package: "TypedIdentifier"),
41+
.product(name: "TypedComparator", package: "TypedComparator"),
42+
.product(name: "HashTreeCollections", package: "swift-collections"),
43+
]
44+
),
45+
.testTarget(
46+
name: "NormalizationMacrosTests",
47+
dependencies: [
48+
"NormalizationMacrosPlugin",
49+
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
50+
.product(name: "MacroTesting", package: "swift-macro-testing"),
51+
]
52+
),
53+
.testTarget(
54+
name: "NormalizationTests",
55+
dependencies: [
56+
"Normalization"
57+
]
58+
),
59+
],
60+
swiftLanguageModes: [.v6]
61+
)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# ``VergeNormalization``
2+
3+
## Overview
4+
5+
State management plays a crucial role in building efficient and maintainable applications. One of the essential aspects of state management is organizing the data in a way that simplifies its manipulation and usage. This is where normalization becomes vital.
6+
7+
Normalization is the process of structuring data in a way that eliminates redundancy and ensures data consistency. It is essential in state-management libraries because it significantly reduces the computational complexity of operations and makes it easier to manage the state.
8+
9+
Docs:
10+
- [VergeNormalization](https://swiftpackageindex.com/VergeGroup/swift-Verge/main/documentation/vergenormalization)
11+
- [VergeNormalizationDerived](https://swiftpackageindex.com/VergeGroup/swift-Verge/main/documentation/vergenormalizationderived)
12+
13+
Let's take a look at an example to illustrate the difference between normalized and denormalized data structures.
14+
15+
**Denormalized data structure:**
16+
17+
18+
```yaml
19+
posts:
20+
- id: 1
21+
title: "Post 1"
22+
author:
23+
id: 1
24+
name: "Alice"
25+
- id: 2
26+
title: "Post 2"
27+
author:
28+
id: 1
29+
name: "Alice"
30+
- id: 3
31+
title: "Post 3"
32+
author:
33+
id: 2
34+
name: "Bob"
35+
```
36+
37+
In the denormalized structure, author data is duplicated in each post, which can lead to inconsistencies and make it harder to manage the state.
38+
39+
**Normalized data structure:**
40+
41+
42+
```yaml
43+
entities:
44+
authors:
45+
1:
46+
id: 1
47+
name: "Alice"
48+
2:
49+
id: 2
50+
name: "Bob"
51+
posts:
52+
1:
53+
id: 1
54+
title: "Post 1"
55+
authorId: 1
56+
2:
57+
id: 2
58+
title: "Post 2"
59+
authorId: 1
60+
3:
61+
id: 3
62+
title: "Post 3"
63+
authorId: 2
64+
```
65+
66+
In the normalized structure, author data is stored separately from posts, eliminating data redundancy and ensuring data consistency. The relationship between posts and authors is represented by the `authorId` field in the posts.
67+
68+
VergeORM is designed to handle normalization in state-management libraries effectively. By leveraging VergeORM, you can simplify your state management, reduce the computational complexity of operations, and improve the overall performance and maintainability of your application.
69+
70+
**Defining Entities**
71+
72+
Here's an example of how to define the `Book` and `Author` entities:
73+
74+
```swift
75+
struct Book: EntityType {
76+
77+
typealias TypedIdentifierRawValue = String
78+
79+
var typedID: TypedID {
80+
.init(rawID)
81+
}
82+
83+
let rawID: String
84+
var name: String = "initial"
85+
let authorID: Author.EntityID
86+
}
87+
88+
struct Author: EntityType {
89+
90+
typealias TypedIdentifierRawValue = String
91+
92+
var typedID: TypedID {
93+
.init(rawID)
94+
}
95+
96+
let rawID: String
97+
var name: String = ""
98+
}
99+
```
100+
101+
**Defining Database Schema**
102+
103+
To store the entities in the state, you need to define the database schema:
104+
105+
```swift
106+
@NormalizedStorage
107+
struct Database {
108+
109+
@Table
110+
var books: Tables.Hash<Book> = .init()
111+
112+
@Table
113+
var authors: Tables.Hash<Book> = .init()
114+
}
115+
```
116+
117+
**Embedding the Database in State**
118+
119+
Embed the `Database` in your application's state:
120+
121+
```swift
122+
struct RootState: StateType {
123+
var database: Database = .init()
124+
}
125+
```
126+
127+
**Storing and Querying Entities**
128+
129+
Here's an example of how to store and query entities using a `store` property
130+
131+
```swift
132+
// Storing entities
133+
store.commit {
134+
$0.database.performBatchUpdates { context in
135+
let authors = (0..<10).map { i in
136+
Author(rawID: "\(i)")
137+
}
138+
let result = context.modifying.author.insert(authors)
139+
}
140+
}
141+
142+
// Querying entities
143+
let book = store.state.database.db.book.find(by: .init("1"))
144+
let author = store.state.database.db.author.find(by: .init("1"))
145+
```
146+
147+
In this example, we use `store.commit` to perform batch updates on the database. We insert a new set of authors into the `author` entity table. Then, we use `store.state.database.db` to query the `book` and `author` entities by their identifiers.
148+
149+
By using VergeNormalization, you can efficiently manage your application state with a normalized data structure, which simplifies your state management, reduces the computational complexity of operations, and improves the overall performance and maintainability of your application.
150+
151+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@_exported import TypedIdentifier
2+
3+
public protocol EntityType: TypedIdentifiable, Equatable, Sendable {
4+
}
5+
6+
extension EntityType {
7+
public var entityID: TypedID {
8+
return typedID
9+
}
10+
}

0 commit comments

Comments
 (0)