-
Notifications
You must be signed in to change notification settings - Fork 0
Data Management
Data management in CCM is based on datastore accessors that abstract the underlying storage mechanism and provide a unified interface for reading, writing, and querying datasets.
The ccmjs framework provides two closely related API functions:
| Function | Result | Typical Usage |
|---|---|---|
ccm.store(config) |
Datastore accessor | Continuous interaction with a datastore (read/write multiple datasets) |
ccm.get(config, query) |
Dataset(s) | One-time data retrieval |
Example:
const store = await ccm.store({ name: "tasks" });
const tasks = await store.get({ done: false });Equivalent one-time access:
const tasks = await ccm.get({ name: "tasks" }, { done: false });A datastore accessor encapsulates the underlying storage mechanism and exposes a consistent API for interacting with datasets. Depending on the configuration, data may be stored in memory, persistently in the browser, or on a remote server. Because all datastore implementations share the same API, components remain independent of how and where data is stored.
Creates a datastore accessor that provides unified access to datasets.
ccm.store() initializes a datastore based on the provided configuration and returns an accessor object exposing methods for reading, writing, and querying datasets.
ccm.store( [config] ) → Promise<Datastore>| Parameter | Type | Description |
|---|---|---|
config |
Object (optional) |
Datastore configuration that determines how and where datasets are stored. |
The behavior of ccm.store() is determined by the provided configuration.
Depending on the configuration, the framework automatically selects the appropriate datastore implementation:
| Condition | Store Type |
|---|---|
no name
|
InMemoryStore |
name but no url
|
OfflineStore |
name and url
|
RemoteStore |
Used when no name is provided.
| Option | Type | Description |
|---|---|---|
datasets |
Object | dataset[] |
Initial datasets. May be provided as { key: dataset } map or array of datasets. |
Used when name is provided but no url.
| Option | Type | Description |
|---|---|---|
name |
string |
Name of the object store inside IndexedDB. |
Used when both name and url are provided.
| Option | Type | Description |
|---|---|---|
url |
string |
Server endpoint used for datastore communication. |
name |
string |
Name of the collection inside remote database. |
db |
string |
Optional database identifier if the server supports multiple databases. |
observe |
Object |
Query that defines which datasets should be observed. |
onchange |
function |
Callback triggered when observed datasets change. |
user |
Object |
User component instance used for authentication. |
Returns a Promise that resolves to a datastore accessor.
The returned accessor provides the following methods:
store.get( key_or_query )
store.set( dataset )
store.del( key )
store.count( query )
store.clear()All methods return Promises.
<!DOCTYPE html>
<html>
<head>
<script src="https://ccmjs.github.io/framework/ccm.js"></script>
<script>
(async () => {
const store = await ccm.store({
datasets: [
{ key: "a", value: 1 },
{ key: "b", value: 2 }
]
});
const data = await store.get("a");
console.log(data);
})();
</script>
</head>
</html>Console output:
{ key: "a", value: 1 }
ccm.store() is the primary entry point for data access in CCM.
It creates a datastore accessor that encapsulates the underlying storage mechanism and exposes a uniform API for interacting with datasets.
Depending on the configuration, CCM automatically selects one of the following datastore implementations:
- InMemoryStore – volatile storage in a JavaScript object
- OfflineStore – persistent storage in the browser via IndexedDB
- RemoteStore – persistent storage on a remote server
All implementations expose the same datastore API.
- If no configuration is provided, an InMemoryStore is created.
- Datastore accessors are lightweight and can be created multiple times.
- Components interact only with the datastore API and remain independent of the storage implementation.
A dataset is a plain JavaScript object containing a unique key.
Example:
{
"key": "task1",
"title": "Buy milk",
"done": false
}The key uniquely identifies a dataset within a datastore.
Apart from the key, datasets may contain arbitrary properties.
CCM does not enforce a predefined schema.
All datastore accessors expose the same asynchronous API for interacting with datasets.
Reads one or multiple datasets.
store.get( key_or_query )If a key is provided, the corresponding dataset is returned.
const dataset = await store.get("task1");If a query object is provided, all matching datasets are returned.
const tasks = await store.get({ done: false });If no dataset exists for the given key, the result is:
null
Queries used with get() follow a simple object-based matching model.
Example:
{ done: false, priority: "high" }This query returns all datasets whose properties match the provided values.
All datastore implementations in CCM guarantee support for a portable subset of query functionality based on simple equality matching with plain JavaScript objects.
Example:
{ status: "open" }This portable query subset works consistently across all datastore implementations:
InMemoryStoreOfflineStoreRemoteStore
Some datastore implementations may support more advanced query capabilities.
For example, a remote datastore backed by MongoDB may allow the full MongoDB query language.
Example (MongoDB-style query):
{ age: { $gt: 18 } }However, such advanced queries are not guaranteed to be portable across different datastore implementations.
To ensure that components remain datastore-independent and reusable, it is recommended to rely only on the portable query subset unless a specific datastore implementation is intentionally required.
Creates or updates a dataset.
store.set( dataset )Example:
await store.set({
key: "task1",
title: "Buy milk"
});If no key is provided, a key is generated automatically.
Deletes a dataset.
store.del( key )Example:
await store.del("task1");The operation resolves to the deleted dataset or null.
Counts datasets matching a query.
store.count( query )Example:
const total = await store.count({ done: false });Removes all datasets from the datastore.
store.clear()Example:
await store.clear();The datastore implementation used by ccm.store() depends on the provided configuration.
CCM supports three storage layers.
Datasets are stored in a JavaScript object within the current runtime environment.
Characteristics:
- volatile storage
- fastest access
- data is lost when the page reloads
Typical use cases:
- temporary application state
- development and testing
- default datasets in configurations
Datasets are stored persistently in the browser using IndexedDB.
Characteristics:
- persistent across page reloads
- entirely client-side
- no server required
Typical use cases:
- offline-capable applications
- local user data
- client-side caching
Datasets are stored on a remote server.
Characteristics:
- persistent server-side storage
- shared across multiple clients
- optional authentication
- optional realtime updates via WebSocket
Typical use cases:
- multi-user applications
- shared application data
- collaborative tools
Reads one or more datasets from a datastore.
ccm.get() creates a datastore accessor internally and immediately performs a get() operation.
ccm.get( [config], [key_or_query] [, projection] [, options] ) → Promise<Dataset | Dataset[]>| Parameter | Type | Description |
|---|---|---|
config |
Object |
Datastore configuration. Same options as in ccm.store(). |
key_or_query |
string | Object |
Dataset key or query object. |
projection |
Object |
Optional projection describing which fields should be returned. |
options |
Object |
Optional query options (for example sorting or limits for remote stores). |
Returns a Promise that resolves to:
Dataset
or
Dataset[]
depending on whether a key or query was provided.
If a dataset does not exist, the result is:
null
const dataset = await ccm.get(
{ name: "tasks", url: "/api" },
"task1"
);Example result:
{ key: "task1", title: "Buy milk" }
Query example:
const tasks = await ccm.get(
{ name: "tasks", url: "/api" },
{ done: false }
);ccm.get() is a convenience function for retrieving datasets.
Internally it performs the following steps:
ccm.store(config)
↓
store.get(key_or_query)
This function is especially useful when data should be read only once and no further datastore interaction is required.
It is also commonly used inside component configurations to declare data dependencies.
-
ccm.get()always creates a temporary datastore accessor internally. - For repeated operations on the same datastore,
ccm.store()should be used instead.
CCM allows components to declare data-related dependencies directly in their configuration. These dependencies are resolved automatically during instance creation.
Two types of data dependencies exist:
- Datastore dependencies – provide a datastore accessor
- Dataset dependencies – load datasets directly
A component can declare a dependency on a datastore accessor using ccm.store().
Example:
config: {
store: [ "ccm.store", { name: "tasks", url: "/api" } ]
}During instance creation, CCM resolves this dependency and injects a datastore accessor into the configuration.
The component can then interact with the datastore programmatically:
const tasks = await this.store.get({ done: false });
await this.store.set({ key: "task1", done: true });This is useful when a component needs continuous access to a datastore, for example to perform multiple read or write operations.
If only datasets are required, they can be loaded directly using ccm.get().
Example:
config: {
tasks: [ "ccm.get", { name: "tasks", url: "/api" }, { done: false } ]
}During instance creation, CCM automatically resolves this dependency and injects the retrieved datasets into the component configuration.
This allows components to declare required data declaratively, without manual loading logic.