README.md 12 KB

@e22m4u/js-data-projection

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

Модуль использует схемы для определения правил видимости полей данных. Поддерживается вложенность, функции-фабрики, именованные схемы, области проекции и строгий режим.

Содержание

Установка

npm install @e22m4u/js-data-projection

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

ESM

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

CommonJS

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

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

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

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

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

{
  name: true, // поле name доступно
  address: {  // настройки поля address
    select: true, // поле address доступно
    schema: {     // вложенная схема
      city: true,     // поле city доступно
      zip: false      // поле zip скрыто
    }
  }
}

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

Модуль экспортирует функцию projectData для создания проекций и класс DataProjector с возможностью регистрации и применения именованных схем.

Создание проекции

Схема проекции описывает настройки видимости для каждого поля. Логические значения определяют видимость поля. Поля, отсутствующие в схеме, остаются в результате по умолчанию.

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

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

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

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

Проекция массива

Если входные данные представляют собой массив, то проекция применяется к каждому элементу рекурсивно. Структура результата соответствует исходному массиву.

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

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

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

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

Строгий режим

Строгий режим исключает из результата все поля, не описанные в схеме явно. Поведение регулируется опцией strict. Данный режим позволяет гарантировать отсутствие лишних данных в результате.

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

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

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

const result = projectData(schema, data, {
  strict: true, // <= строгий режим
});
console.log(result);
// {
//   name: 'Fedor'
// }

Вложенные схемы

Вложенные объекты обрабатываются с помощью свойства schema в настройках поля. Данное свойство позволяет определять правила видимости для вложенных структур данных.

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

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

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

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

Область проекции

Правила видимости полей могут зависеть от области проекции. Свойство scopes определяет специфичные правила для разных контекстов, передаваемых через опцию scope.

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

const schema = {
  name: true,
  password: {
    scopes: {
      input: true,   // правило для области 'input'
      output: false, // правило для области 'output'
    },
  },
};

const data = {
  name: 'Fedor',       // будет доступно, явное правило
  password: 'pass123', // будет доступно в зависимости от области
};

const inputData = projectData(schema, data, {
  scope: 'input', // <= область проекции
});
console.log(inputData);
// {
//   name: 'Fedor',
//   password: 'pass123'
// }

const outputData = projectData(schema, data, {
  scope: 'output', // <= область проекции
});
console.log(outputData);
// {
//   name: 'Fedor'
// }

Модуль экспортирует объект констант с именами часто используемых областей проекции.

import {ProjectionScope} from '@e22m4u/js-data-projection';

console.log(ProjectionScope);
// {
//   INPUT: 'input',
//   OUTPUT: 'output'
// }

projectData(schema, data, {
  scope: ProjectionScope.INPUT,
});

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

Вместо статической схемы можно передать фабричную функцию, которая вернет объект схемы. Это полезно, если схему необходимо генерировать динамически или переиспользовать логику создания схем.

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

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

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

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

Фабрики также поддерживаются во вложенных структурах. Свойство schema может принимать функцию, возвращающую схему для вложенного объекта.

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

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

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

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

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

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

Класс DataProjector позволяет сохранять схемы во внутреннем реестре для их последующего использования по имени. Это удобно для переиспользования схем в разных частях приложения.

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

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('user', data);
console.log(result);
// {
//   id: 10,
//   username: 'admin'
// }

Зарегистрированные схемы могут ссылаться друг на друга, что позволяет компоновать сложные схемы из более простых. В примере ниже схема user использует схему address как вложенную.

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

const projector = new DataProjector();

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

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

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

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

Для ручного разрешения имен используется опция resolver функции projectData. В опцию передается функция, которая принимает имя схемы и должна вернуть соответствующий ей объект схемы.

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

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

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

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

Тесты

npm run test

Лицензия

MIT