Databases & Entities Memory Read-only

Entity Engine in Memory

The memory provider applies the same typed entity model and KQL execution rules to existing Klyn collections. It is useful for fixtures, reference data, deterministic tests, and applications whose authoritative state already lives in memory.

Provider Contract
CapabilityMemory provider behavior
Access modeRead-only, no-tracking repositories over existing entity lists.
StorageThe list is wrapped without copying; the repository owns no entity storage.
IdentityProvider-neutral keys are validated eagerly when the repository is created.
QueriesProvider-neutral KQL is evaluated directly over the current list content.
RelationshipsMapped eager relations and requested fetch paths are prepared before execution.
MutationEntity Engine persistence operations are not supported by this provider.
Entity and Values

Memory entities use the provider-neutral annotations from klyn.data.mapping. They do not require SQL, XML, or JSON binding annotations.

import klyn.data.mapping

@Entity
class User:

    @Id
    public property id as Int

    public property login as String
    public property connectionNumber as Int
    public property active as Boolean

    public User(
        id as Int,
        login as String,
        connectionNumber as Int,
        active as Boolean = true
    ):
        this.id = id
        this.login = login
        this.connectionNumber = connectionNumber
        this.active = active

users = [
    User(1, "alice", 4),
    User(2, "bob", 14),
    User(3, "carol", 21)
]
Repository and Factory

Register one typed MemoryRepository<T, TId> for every allowed entity type. The factory entity list remains the authoritative model and is checked against those registrations.

import klyn.data
import klyn.data.memory

userSource = MemoryRepository<User, Int>(users)
configuration = MemoryConfiguration([userSource])

try factory = EntityManagerFactory(
    configuration,
    entities=[User]
):
    assert factory.schema.exists()
    assert factory.schema.exists(User.type)

    try em = factory.createEntityManager():
        bob = em.find<User>(2)
        assert bob.login == "bob"

Construction rejects null identities and raises DuplicateIdentityException as soon as a duplicate key is found. validateBeforeRead() can repeat complete key validation after the backing list has changed.

Preferred Manager Query

When a factory and manager already define the entity model, use query(em):. The root entity identifies the registered memory repository and no alias is required when the query has a single unambiguous source.

frequentUsers = query(em):
    from User
    where active and connectionNumber > 10
    order by connectionNumber desc, login

for user in frequentUsers.toList():
    print(f"{user.login}: {user.connectionNumber}")

Query creation is lazy. Terminal operations such as toList(), count(), exists(), first(), and single() execute against the list content visible at that time.

Direct Repository Query

The explicit repository form is useful when a function should accept any compatible query source. Unlike query(em):, this form names both the source value and its alias.

def frequent(
    source as Queryable<User>,
    minimum as Int
) as Query<User>:
    return query:
        from source user
        where user.connectionNumber > minimum
        order by user.connectionNumber desc

selected = frequent(userSource, 10).toList()

Manager and repository forms lower to the same immutable query representation; only root resolution differs.

Observation Semantics
  • Creating a repository does not copy its backing list.
  • A later query observes values currently present in that list.
  • Key validation is eager at construction and explicit through validateBeforeRead().
  • Each query execution owns its cursor and must be consumed sequentially.
  • Concurrent list mutation requires an appropriate synchronized collection and application-level coordination.
No persistence ownership

The memory provider does not persist, merge, remove, or roll back entities. Modify the backing collection through its owner when mutation is required.

Relationships

Provider-neutral relationship annotations are supported. Direct entity references are retained; inverse endpoints are reconstructed from ownership metadata. Eager relationships are prepared automatically, while join fetch requests a lazy relationship for one execution.

@ManyToOne(optional=false)
public property author as User

@OneToMany(mappedBy="author")
public property articles as List<Article> = []

Every relationship target must be present in the factory entity list and have a matching registered memory repository.

Logical Schema

The memory schema is the set of registered entity repositories. exists() and validate() verify that the factory model is fully registered. There is no physical resource to create or migrate, and drop() is unsupported because ownership remains with the application.

schema = factory.schema
schema.validate()

plan = schema.diff()
assert plan.empty
Continue Learning

Return to Entity Engine KQL for the complete query syntax, or continue with the Windows GUI Library.