Skip to content

Commit

Permalink
Merge pull request #9764 from marmelab/data-generator-types
Browse files Browse the repository at this point in the history
Add better types to data-generator
  • Loading branch information
fzaninotto committed Apr 18, 2024
2 parents 86ed378 + b99db24 commit b59afe0
Show file tree
Hide file tree
Showing 20 changed files with 489 additions and 279 deletions.
6 changes: 0 additions & 6 deletions Makefile
Expand Up @@ -27,18 +27,12 @@ run-tutorial: ## run the tutorial example
run-demo: ## run the ecommerce example
@yarn run-demo

run-demo-watch: ## run the ecommerce example and watch changes in ra dependencies
@yarn run-demo-watch

build-demo: ## compile the ecommerce example to static js
@yarn build-demo

run-graphql-demo: ## run the ecommerce example with a graphql backend
@yarn run-graphql-demo

run-graphql-demo-watch: ## run the ecommerce example with a graphql backend and watch changes in ra dependencies
@yarn run-graphql-demo-watch

run-crm: ## run the crm example
@yarn run-crm

Expand Down
7 changes: 6 additions & 1 deletion examples/data-generator/src/categories.ts
@@ -1,4 +1,4 @@
export default () => [
export const generateCategories = (): Category[] => [
{ id: 0, name: 'animals' },
{ id: 1, name: 'beard' },
{ id: 2, name: 'business' },
Expand All @@ -13,3 +13,8 @@ export default () => [
{ id: 11, name: 'travel' },
{ id: 12, name: 'water' },
];

export type Category = {
id: number;
name: string;
};
32 changes: 27 additions & 5 deletions examples/data-generator/src/commands.ts
Expand Up @@ -7,8 +7,9 @@ import {
weightedArrayElement,
weightedBoolean,
} from './utils';
import type { Db } from './types';

export default (db, { serializeDate }) => {
export const generateCommands = (db: Db): Command[] => {
const today = new Date();
const aMonthAgo = subDays(today, 30);
const realCustomers = db.customers.filter(customer => customer.has_ordered);
Expand Down Expand Up @@ -38,17 +39,17 @@ export default (db, { serializeDate }) => {
const taxes = parseFloat(
((total_ex_taxes + delivery_fees) * tax_rate).toFixed(2)
);
const customer = random.arrayElement<any>(realCustomers);
const customer = random.arrayElement(realCustomers);
const date = randomDate(customer.first_seen, customer.last_seen);

const status =
const status: CommandStatus =
isAfter(date, aMonthAgo) && random.boolean()
? 'ordered'
: weightedArrayElement(['delivered', 'cancelled'], [10, 1]);
return {
id,
reference: random.alphaNumeric(6).toUpperCase(),
date: serializeDate ? date.toISOString() : date,
date: date.toISOString(),
customer_id: customer.id,
basket: basket,
total_ex_taxes: total_ex_taxes,
Expand All @@ -58,8 +59,29 @@ export default (db, { serializeDate }) => {
total: parseFloat(
(total_ex_taxes + delivery_fees + taxes).toFixed(2)
),
status: status,
status,
returned: status === 'delivered' ? weightedBoolean(10) : false,
};
});
};

export type Command = {
id: number;
reference: string;
date: string;
customer_id: number;
basket: BasketItem[];
total_ex_taxes: number;
delivery_fees: number;
tax_rate: number;
taxes: number;
total: number;
status: CommandStatus;
returned: boolean;
};

export type CommandStatus = 'ordered' | 'delivered' | 'cancelled';
export type BasketItem = {
product_id: number;
quantity: number;
};
30 changes: 25 additions & 5 deletions examples/data-generator/src/customers.ts
Expand Up @@ -2,7 +2,7 @@ import { date, name, internet, address } from 'faker/locale/en';

import { randomDate, weightedBoolean } from './utils';

export default (db, { serializeDate }) => {
export const generateCustomers = (): Customer[] => {
// This is the total number of people pictures available. We only use those pictures for actual customers
const maxCustomers = 223;
let numberOfCustomers = 0;
Expand Down Expand Up @@ -36,10 +36,9 @@ export default (db, { serializeDate }) => {
city: has_ordered ? address.city() : null,
stateAbbr: has_ordered ? address.stateAbbr() : null,
avatar,
birthday:
serializeDate && birthday ? birthday.toISOString() : birthday,
first_seen: serializeDate ? first_seen.toISOString() : first_seen,
last_seen: serializeDate ? last_seen.toISOString() : last_seen,
birthday: birthday ? birthday.toISOString() : null,
first_seen: first_seen.toISOString(),
last_seen: last_seen.toISOString(),
has_ordered: has_ordered,
latest_purchase: null, // finalize
has_newsletter: has_ordered ? weightedBoolean(30) : true,
Expand All @@ -49,3 +48,24 @@ export default (db, { serializeDate }) => {
};
});
};

export type Customer = {
id: number;
first_name: string;
last_name: string;
email: string;
address: string;
zipcode: string;
city: string;
stateAbbr: string;
avatar: string;
birthday: string | null;
first_seen: string;
last_seen: string;
has_ordered: boolean;
latest_purchase: string;
has_newsletter: boolean;
groups: string[];
nb_commands: number;
total_spent: number;
};
21 changes: 20 additions & 1 deletion examples/data-generator/src/finalize.ts
@@ -1,6 +1,7 @@
import { Db } from './types';
import { weightedBoolean } from './utils';

export default function (db) {
export default function (db: Db) {
// set latest purchase date
db.commands.forEach(command => {
let customer = db.customers[command.customer_id];
Expand Down Expand Up @@ -100,3 +101,21 @@ export default function (db) {
},
];
}

export type Settings = {
id: number;
configuration: {
url: string;
mail: {
sender: string;
transport: {
service: string;
auth: {
user: string;
pass: string;
};
};
};
file_type_whiltelist: string[];
};
}[];
45 changes: 24 additions & 21 deletions examples/data-generator/src/index.ts
@@ -1,31 +1,34 @@
import { RaRecord } from 'ra-core';

import generateCustomers from './customers';
import generateCategories from './categories';
import generateProducts from './products';
import generateCommands from './commands';
import generateInvoices from './invoices';
import generateReviews from './reviews';
import { generateCustomers, Customer } from './customers';
import { generateCategories, Category } from './categories';
import { generateProducts, Product } from './products';
import { generateCommands, Command, BasketItem } from './commands';
import { generateInvoices, Invoice } from './invoices';
import { generateReviews, Review } from './reviews';
import finalize from './finalize';
import { Db } from './types';

export interface Db {
customers: RaRecord[];
categories: RaRecord[];
products: RaRecord[];
commands: RaRecord[];
invoices: RaRecord[];
reviews: RaRecord[];
}

export default (options = { serializeDate: true }): Db => {
const generateData = (): Db => {
const db = {} as Db;
db.customers = generateCustomers(db, options);
db.customers = generateCustomers();
db.categories = generateCategories();
db.products = generateProducts(db);
db.commands = generateCommands(db, options);
db.commands = generateCommands(db);
db.invoices = generateInvoices(db);
db.reviews = generateReviews(db, options);
db.reviews = generateReviews(db);
finalize(db);

return db;
};

export default generateData;

export type {
BasketItem,
Category,
Command,
Customer,
Db,
Invoice,
Product,
Review,
};
16 changes: 15 additions & 1 deletion examples/data-generator/src/invoices.ts
@@ -1,4 +1,6 @@
export default db => {
import type { Db } from './types';

export const generateInvoices = (db: Db): Invoice[] => {
let id = 0;

return (
Expand All @@ -19,3 +21,15 @@ export default db => {
}))
);
};

export type Invoice = {
id: number;
date: string;
command_id: number;
customer_id: number;
total_ex_taxes: number;
delivery_fees: number;
tax_rate: number;
taxes: number;
total: number;
};
17 changes: 16 additions & 1 deletion examples/data-generator/src/products.ts
@@ -1,6 +1,7 @@
import { random, lorem } from 'faker/locale/en';

import { randomFloat, weightedBoolean } from './utils';
import type { Db } from './types';

const productReferences = {
animals: [
Expand Down Expand Up @@ -162,7 +163,7 @@ const productReferences = {
],
};

export default db => {
export const generateProducts = (db: Db): Product[] => {
let id = 0;

return db.categories.reduce(
Expand Down Expand Up @@ -205,3 +206,17 @@ export default db => {
[]
);
};

export type Product = {
id: number;
category_id: number;
reference: string;
width: number;
height: number;
price: number;
thumbnail: string;
image: string;
description: string;
stock: number;
sales: number;
};
16 changes: 14 additions & 2 deletions examples/data-generator/src/reviews.ts
Expand Up @@ -2,8 +2,9 @@ import { random, lorem } from 'faker/locale/en';
import { subDays, isAfter } from 'date-fns';

import { randomDate, weightedArrayElement, weightedBoolean } from './utils';
import type { Db } from './types';

export default (db, { serializeDate }) => {
export const generateReviews = (db: Db): Review[] => {
const today = new Date();
const aMonthAgo = subDays(today, 30);

Expand Down Expand Up @@ -34,7 +35,7 @@ export default (db, { serializeDate }) => {

return {
id: id++,
date: serializeDate ? date.toISOString() : date,
date: date.toISOString(),
status: status,
command_id: command.id,
product_id: product.product_id,
Expand All @@ -52,3 +53,14 @@ export default (db, { serializeDate }) => {
[]
);
};

export type Review = {
id: number;
date: string;
status: 'accepted' | 'rejected' | 'pending';
command_id: number;
product_id: number;
customer_id: number;
rating: number;
comment: string;
};
17 changes: 17 additions & 0 deletions examples/data-generator/src/types.ts
@@ -0,0 +1,17 @@
import type { Customer } from './customers';
import type { Category } from './categories';
import type { Product } from './products';
import type { Command } from './commands';
import type { Invoice } from './invoices';
import type { Review } from './reviews';
import { Settings } from './finalize';

export interface Db {
customers: Customer[];
categories: Category[];
products: Product[];
commands: Command[];
invoices: Invoice[];
reviews: Review[];
settings: Settings;
}
17 changes: 14 additions & 3 deletions examples/data-generator/src/utils.ts
@@ -1,6 +1,6 @@
import faker from 'faker/locale/en';

export const weightedArrayElement = (values, weights) =>
export const weightedArrayElement = <T>(values: T[], weights): T =>
faker.random.arrayElement(
values.reduce(
(acc, value, index) =>
Expand All @@ -12,12 +12,23 @@ export const weightedArrayElement = (values, weights) =>
export const weightedBoolean = likelyhood =>
faker.random.number(99) < likelyhood;

export const randomDate = (minDate?: Date, maxDate?: Date) => {
export const randomDate = (
minDate?: Date | string,
maxDate?: Date | string
) => {
const minTs =
minDate instanceof Date
? minDate.getTime()
: typeof minDate === 'string'
? new Date(minDate).getTime()
: Date.now() - 5 * 365 * 24 * 60 * 60 * 1000; // 5 years
const maxTs = maxDate instanceof Date ? maxDate.getTime() : Date.now();
const maxTs =
maxDate instanceof Date
? maxDate.getTime()
: typeof maxDate === 'string'
? new Date(maxDate).getTime()
: Date.now();

const range = maxTs - minTs;
const randomRange = faker.random.number({ max: range });
// move it more towards today to account for traffic increase
Expand Down
2 changes: 1 addition & 1 deletion examples/demo/package.json
Expand Up @@ -18,7 +18,7 @@
"graphql": "^15.6.0",
"graphql-tag": "^2.12.6",
"inflection": "~1.12.0",
"json-graphql-server": "~2.3.0",
"json-graphql-server": "~3.0.1",
"prop-types": "^15.8.1",
"query-string": "^7.1.1",
"ra-data-fakerest": "^5.0.0-alpha.0",
Expand Down
1 change: 0 additions & 1 deletion examples/demo/src/data-generator-retail.d.ts

This file was deleted.

2 changes: 1 addition & 1 deletion examples/demo/src/fakeServer/graphql.ts
Expand Up @@ -3,7 +3,7 @@ import generateData from 'data-generator-retail';
import fetchMock from 'fetch-mock';

export default () => {
const data = generateData({ serializeDate: false });
const data = generateData();
const restServer = JsonGraphqlServer({ data });
const handler = restServer.getHandler();
const handlerWithLogs = (url: string, opts: any) =>
Expand Down

0 comments on commit b59afe0

Please sign in to comment.