fluig-dataset
v1.0.0
Published
Angular service for consuming datasets in Fluig
Maintainers
Readme
Fluig Dataset
Angular service to query Fluig datasets with caching and a small, typed API.
Repo: github.com/gabrielgnsilva/fluig-dataset • License: MIT
Key features (nuances that matter)
- Constraint builder: single value or range; if
typeis omitted, it defaults to'MUST'. Nullish inputs are converted toNULL_VALUEto match Fluig semantics. - Stable cache keys: key =
datasetId+ normalizedDatasetOptions(sortedfieldsandconstraints), then hashed (SHA‑256, FNV‑1a fallback). - Cache & TTL:
SESSION(default) orLOCALstorage. Override per call withexpiration: 'NOCACHE' | 'SHORT' | 'MEDIUM' | 'LONG' | 'VERYLONG'. - In‑flight de‑duplication: identical concurrent requests share the same HTTP call; cache is written only once.
- Query shape:
orderByis sent asFIELD;asc|desc. Endpoint used:GET /dataset/api/v2/dataset-handle/searchviaFluigAPIService. - Error behavior: failed requests purge the cache entry for that key.
Support: Angular 19–20 only.
Prerequisites & peer deps
- Node.js which includes Node Package Manager (or whatever package manager you prefer, like Yarn or PNPM)
- Angular (>= 19.x)
- fluig-api (all HTTP requests go through this)
# install peers
pnpm add crypto-js oauth-1.0a fluig-api fluig-dataset
# or: npm i / yarn add / bun addConfiguration
Provide runtime options via the environment provider. Values are deep‑merged with defaults.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideFluigDatasetConfig } from 'fluig-dataset';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideFluigDatasetConfig({
cacheType: 'SESSION', // 'LOCAL' | 'SESSION'
expiration: {
default: 'MEDIUM', // per‑call default TTL
times: {
SHORT: 600_000, // 10 minutes
MEDIUM: 9_000_000, // 2.5 hours
LONG: 18_000_000, // 5 hours
VERYLONG: 36_000_000, // 10 hours
},
},
}),
],
};Configuration object (nuances)
Shape
interface FluigDatasetConfig { cacheType: 'LOCAL' | 'SESSION'; expiration?: { default?: 'NOCACHE' | 'SHORT' | 'MEDIUM' | 'LONG' | 'VERYLONG'; times?: { SHORT?: number; MEDIUM?: number; LONG?: number; VERYLONG?: number; }; }; }Defaults (if you provide nothing):
cacheType: 'SESSION'expiration.default: 'MEDIUM'times:SHORT=600_000,MEDIUM=9_000_000,LONG=18_000_000,VERYLONG=36_000_000(ms)
Merging:
provideFluigDatasetConfigperforms a deep merge. Partialtimesoverrides only the specified keys; the rest come from defaults.Per‑call override:
DatasetOptions.expirationbeats config defaults.'NOCACHE'disables storage for that call.Storage target is selected by
cacheType:'SESSION'→sessionStorage,'LOCAL'→localStorage.Keying: cache key =
datasetId+ normalizedDatasetOptions(sortedfields,constraintsbyfield, normalizedorderBy), then hashed (SHA‑256, FNV‑1a fallback).SSR: reads/writes Web Storage; use in browser only (or set
'NOCACHE'when rendering server‑side).
About fluig-api
- Local/dev: often uses OAuth; configure base URL + OAuth in
fluig-api. - Production: no OAuth; rely on Fluig auth (session/cookie/proxy). Tell
fluig-apinot to use OAuth in its own config.
This package never handles auth; it delegates to
FluigAPIServicefromfluig-api.
Constraints — nuances & arguments
Use createConstraint(options) to avoid shape mistakes. The API enforces XOR between value and range.
// Valid shapes
{ field: string, type?: 'MUST'|'MUST_NOT'|'SHOULD', likeSearch?: boolean, value: string|number|boolean|null|undefined }
{ field: string, type?: 'MUST'|'MUST_NOT'|'SHOULD', likeSearch?: boolean, range: { from: X|null|undefined, to?: X|null|undefined } }
// Invalid → throws: both or neither of value/rangeBehavioral details
Type default: if
typeis omitted, it defaults to'MUST'in both shapes.Single
valueshapeinitialValue = value ?? NULL_VALUEfinalValue = (type is omitted) ? NULL_VALUE : initialValue- Rationale: when you don’t care about
finalValue, omittingtypemeans the final value isNULL_VALUE(i.e., "is null").
rangeshapefrom => initialValue = from ?? NULL_VALUEto => finalValue = (to === undefined) ? from : (to ?? NULL_VALUE)- If
toisn't provided, the constraint becomes a single‑point range.
NULL_VALUE: literal___NULL___VALUE___; represents Fluignullin bothinitialValueand/orfinalValue.likeSearch: whentrue, pass your own wildcard pattern (e.g.,'Gabriel%').Sorting: constraints are sorted by
fieldduring normalization to stabilize cache keys (order‑independent).Error handling: providing both
valueandrange, or neither, throws an error.
Minimal examples
// Single exact match
this.ds.createConstraint({ field: 'active', value: true, type: 'MUST' });
// LIKE search
this.ds.createConstraint({
field: 'colleagueName',
value: 'Gabriel%',
likeSearch: true,
type: 'MUST',
});
// Range [0..3000], default type 'MUST'
this.ds.createConstraint({
field: 'userTenantId',
range: { from: 0, to: 3000 },
});
// Single value without type => finalValue becomes `NULL_VALUE`
this.ds.createConstraint({ field: 'email', value: '[email protected]' });
// Explicit range with inferred type 'MUST' (you can specify it if you need).
this.ds.createConstraint({
field: 'endDate',
range: { from: '2025-01-01', to: '2025-01-05' },
});Usage (minimal)
import { inject } from '@angular/core';
import { FluigDatasetService } from 'fluig-dataset';
interface Row {
login: string;
colleagueName: string;
}
class Example {
private readonly ds = inject(FluigDatasetService);
load() {
const constraints = [
this.ds.createConstraint({ field: 'active', value: true, type: 'MUST' }),
this.ds.createConstraint({
field: 'colleagueName',
value: 'Gabriel%',
type: 'MUST',
likeSearch: true,
}),
];
return this.ds.getDataset<Row>('colleague', {
fields: ['login', 'colleagueName'],
constraints,
orderBy: { field: 'colleagueName', direction: 'asc' },
limit: 10,
expiration: 'SHORT',
});
}
}Note:
getDataset<T>returns anObservable<Dataset<T>>. Useasyncpipe or subscribe.
Troubleshooting
Handling CORS Issues
Use fluig-api with a reverse proxy to avoid CORS issues when working with Fluig in Angular applications. This setup allows your Angular app to communicate with the Fluig backend without running into cross-origin request problems.
You can read more about this in my blog post[^1] and in the Angular documentation[^2] and in the fluig-api README^3.
[^1]: How to Fix CORS Issues with Fluig Using Reverse Proxy in Angular
[^2]: Proxying to a backend server
Contribution
PRs and issues are welcome. Follow Angular’s style guide and keep APIs standalone-friendly (inject(), signals). Conventional commits preferred.
Contact & Support
- Issues: https://github.com/gabrielgnsilva/fluig-dataset/issues
- Author: Gabriel Nascimento
- Support window: Angular 19–20
