JavaScript модуль для создания проекции данных

e22m4u 21b5cbc987 refactor: removes scopes 1 неделя назад
.husky 22b5a33b5f chore: initial commit 1 месяц назад
dist 21b5cbc987 refactor: removes scopes 1 неделя назад
src 21b5cbc987 refactor: removes scopes 1 неделя назад
.c8rc 22b5a33b5f chore: initial commit 1 месяц назад
.commitlintrc 22b5a33b5f chore: initial commit 1 месяц назад
.editorconfig 22b5a33b5f chore: initial commit 1 месяц назад
.gitignore 22b5a33b5f chore: initial commit 1 месяц назад
.mocharc.json 6f15ecb1a5 refactor: improve linting 1 месяц назад
.prettierrc 22b5a33b5f chore: initial commit 1 месяц назад
LICENSE 22b5a33b5f chore: initial commit 1 месяц назад
README.md 21b5cbc987 refactor: removes scopes 1 неделя назад
build-cjs.js 22b5a33b5f chore: initial commit 1 месяц назад
eslint.config.js e9e531963f refactor: updates eslint rules 2 недель назад
package.json a06df7e047 chore: bumps version to 0.1.4 2 недель назад
tsconfig.json f7227f5222 feat: add types 4 недель назад

README.md

@e22m4u/js-data-projector

JavaScript модуль для создания проекции данных на основе декларативных схем.

Содержание

Установка

npm install @e22m4u/js-data-projector

Модуль поддерживает ESM и CommonJS стандарты.

ESM

import {projectData} from '@e22m4u/js-data-projector';

CommonJS

const {projectData} = require('@e22m4u/js-data-projector');

Схема проекции

Определение правил видимости полей.

{
  foo: true, // поле доступно
  bar: false // поле скрыто
}

Определение вложенной схемы.

{
  name: true, // поле "name" доступно
  address: {  // поле "address" доступно
    city: true,  // поле "address.city" доступно
    zip: false   // поле "address.zip" скрыто
  }
}

Определение вложенной именованной схемы.

{
  name: true,        // поле "name" доступно
  contact: 'address' // поле "contact" доступно
  // поле "contact" использует вложенную схему "address"
}

Использование

Ниже приводятся примеры использования данного модуля.

Применение схемы

Создание проекции данных с помощью схемы.

import {projectData} from '@e22m4u/js-data-projector';

const schema = {
  name: true,
  password: false,
};

const data = {
  name: 'Fedor',       // допускается, явное правило
  password: 'pass123', // исключается, явное правило
  extra: 10,           // исключается в режиме по умолчанию
};

const result = projectData(data, schema);
console.log(result);
// {
//   name: 'Fedor'
// }

Применение схемы к массиву объектов.

import {projectData} from '@e22m4u/js-data-projector';

const schema = {
  id: true,
  secret: false,
};

const data = [
  {id: 1, secret: 'A'},
  {id: 2, secret: 'B'},
];

const result = projectData(data, schema);
console.log(result);
// [
//   {id: 1},
//   {id: 2}
// ]

Применение вложенной схемы для сложной структуры данных.

import {projectData} from '@e22m4u/js-data-projector';

const schema = {
  id: false,
  name: true,
  // вложенная схема
  city: {
    id: false,
    name: true,
  },
};

const data = {
  id: 10, // исключается, явное правило
  name: 'Fedor',
  city: {
    id: 20, // исключается, явное правило
    name: 'Moscow',
  },
};

const result = projectData(data, schema);
console.log(result);
// {
//   name: 'Fedor',
//   city: {
//     name: 'Moscow',
//   }
// }

Неуказанные поля

Допуск полей не указанных в схеме проекции.

import {projectData} from '@e22m4u/js-data-projector';

const schema = {
  name: true,
  password: false,
};

const data = {
  name: 'Fedor',       // допускается, явное правило
  password: 'pass123', // исключается, явное правило
  extra: 10,           // допускается в режиме "keepUnknown"
};

const result = projectData(data, schema, {
  keepUnknown: true, // <= допуск неуказанных полей
});
console.log(result);
// {
//   name: 'Fedor',
//   extra: 10
// }

Переопределение параметра keepUnknown схемой проекции.

import {projectData} from '@e22m4u/js-data-projector';

const schema = {
  $keepUnknown: true, // <= допускать неуказанные поля
  name: true,
  password: false,
  // in-line параметр "$keepUnknown" определяет режим только
  // для текущего уровня вложенности, и если данная схема
  // объекта имеет вложенные схемы, то на них переопределение
  // не влияет
};

const data = {
  name: 'Fedor',       // допускается, явное правило
  password: 'pass123', // исключается, явное правило
  extra: 10,           // допускается, in-line параметр "$keepUnknown"
};

const result = projectData(data, schema, {
  keepUnknown: false, // <= допуск неуказанных полей запрещен
});
console.log(result);
// {
//   name: 'Fedor',
//   extra: 10
// }

Фабричные функции

Использование фабрики вместо объекта схемы.

import {projectData} from '@e22m4u/js-data-projector';

// фабрика возвращает объект схемы
const getSchema = () => {
  return {
    id: true,
    hiddenField: false,
  };
};

const data = {
  id: 1,
  hiddenField: 'secret',
};

// передача функции вместо объекта
const result = projectData(data, getSchema);
console.log(result);
// {
//   id: 1
// }

Использование фабрики во вложенной схеме.

import {projectData} from '@e22m4u/js-data-projector';

// фабрика для вложенных данных
const getAddressSchema = () => {
  return {
    city: true,
    zip: false,
  };
};

const userSchema = {
  name: true,
  address: getAddressSchema, // <= использование фабрики
};

const data = {
  name: 'Fedor',
  address: {
    city: 'Moscow',
    zip: 123456,
  },
};

const result = projectData(data, userSchema);
console.log(result);
// {
//   name: 'Fedor',
//   address: {
//     city: 'Moscow'
//   }
// }

Установка аргументов вызова фабричных функций.

import {projectData} from '@e22m4u/js-data-projector';

// объект "logger" будет передан
// в параметры фабрики,
const logger = {
  log: (message) => console.log(message),
};

// фабрика использует "logger"
const getSchema = (logger) => {
  logger.log('Factory was invoked!');
  return {name: true, secret: false};
};

const data = {
  name: 'John',
  secret: 'john123',
};

const result = projectData(data, getSchema, {
  factoryArgs: [logger], // <= передача "logger" в фабрику
});
// Factory was invoked!
console.log(result);
// {
//   name: 'John',
// }

Доступ к сервис-контейнеру внутри фабрики.

import {ServiceContainer} from '@e22m4u/js-service';
import {DataProjector} from '@e22m4u/js-data-projector';

// сервис-контейнер доступен только
// при использовании DataProjector
const projector = new DataProjector();

// сервис-контейнер передается
// первым аргументом фабрики
const getSchema = (container) => {
  console.log(container instanceof ServiceContainer); // true
  return {name: true, secret: false};
}

const data = {
  name: 'John',
  secret: 'john123',
};

const result = projector.project(data, getSchema);
console.log(result);
// {
//   name: 'John',
// }

Именованные схемы

Регистрация и применение именованной схемы.

import {DataProjector} from '@e22m4u/js-data-projector';

const projector = new DataProjector();

// регистрация схемы
projector.defineSchema({
  name: 'user', // <= имя схемы
  schema: {
    id: true,
    username: true,
    email: false,
  },
});

const data = {
  id: 10,
  username: 'admin',
  email: 'admin@example.com',
};

// проекция данных по зарегистрированному имени
const result = projector.project(data, 'user');
console.log(result);
// {
//   id: 10,
//   username: 'admin'
// }

Использование вложенных именованных схем.

import {DataProjector} from '@e22m4u/js-data-projector';

const projector = new DataProjector();

// регистрация схемы "address"
projector.defineSchema({
  name: 'address',
  schema: {
    city: true,
    zip: false,
  },
});

// регистрация схемы "user"
projector.defineSchema({
  name: 'user',
  schema: {
    name: true,
    address: 'address', // <= имя вложенной схемы
  },
});

const data = {
  name: 'Fedor',
  address: {
    city: 'Moscow',
    zip: 123456,
  },
};

const result = projector.project(data, 'user');
console.log(result);
// {
//   name: 'Fedor',
//   address: {
//     city: 'Moscow'
//   }
// }

Регистрация псевдонима именованной схемы.

import {DataProjector} from '@e22m4u/js-data-projector';

const projector = new DataProjector();

// регистрация основной схемы
projector.defineSchema({
  name: 'user',
  schema: {
    id: true,
    name: true,
    email: false,
  },
});

// регистрация псевдонима
projector.defineSchema({
  name: 'author', // имя псевдонима
  schema: 'user', // <= имя основной схемы
});

const data = {
  id: 10,
  name: 'Fedor',
  email: 'fedor@example.com',
};

// проекция данных по имени псевдонима
const result = projector.project(data, 'author');
console.log(result);
// {
//   id: 10,
//   name: 'Fedor'
// }

Использование фабрики при регистрации именованной схемы.

import {DataProjector} from '@e22m4u/js-data-projector';

const projector = new DataProjector();

// создание фабрики
const getUserSchema = () => {
  return {
    id: true,
    name: true,
    email: false,
  };
};

// регистрация схемы
projector.defineSchema({
  name: 'user',
  schema: getUserSchema, // <= фабрика вместо схемы
});

const data = {
  id: 10,
  name: 'Fedor',
  email: 'fedor@example.com',
};

const result = projector.project(data, 'user');
console.log(result);
// {
//   id: 10,
//   name: 'Fedor'
// }

Реализация пользовательской функции разрешения имен.

import {projectData} from '@e22m4u/js-data-projector';

// функция разрешения имен
const nameResolver = name => {
  if (name === 'user') {
    return {id: true, name: true, password: false};
  }
  throw new Error(`Schema "${name}" is not found!`);
};

const data = {
  id: 1,
  name: 'Fedor',
  password: 'pass123',
};

const result = projectData(
  data,
  'user', // <= вместо схемы передается имя
  {nameResolver}, // <= разрешающая функция
);
console.log(result);
// {
//   id: 1,
//   name: 'Fedor'
// }

Тесты

npm run test

Лицензия

MIT