@neupgroup/mapper 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,66 +1,37 @@
1
- # Neup.Mapper (Library)
2
-
3
- Neup.Mapper is now a small, framework-agnostic TypeScript library focused on two things:
4
-
5
- - Database connectivity via adapter pattern (bring your own driver)
6
- - HTTP API access via adapter pattern (bring your own client)
7
-
8
- ## Install
9
-
10
- This project is currently private. Build locally:
11
-
12
- ```
13
- npm install
14
- npm run build
15
- ```
16
-
17
- Artifacts are emitted to `dist/`.
18
-
19
- ## Usage
20
-
21
- ### Database
22
-
23
- ```
24
- import { createDb, IDbAdapter } from "neup-mapper";
25
-
26
- const adapter: IDbAdapter = {
27
- async connect(config) {
28
- // initialize your driver, e.g., pg, mysql2, sqlite, etc.
29
- },
30
- async query(sql, params) {
31
- // delegate to your driver
32
- return [];
33
- },
34
- async close() {
35
- // close driver resources
36
- },
37
- };
38
-
39
- const db = createDb(adapter);
40
- await db.connect({ host: "localhost" });
41
- const rows = await db.query("SELECT 1");
42
- await db.close();
43
- ```
44
-
45
- ### API
46
-
47
- ```
48
- import { createApiClient, IApiAdapter } from "neup-mapper";
49
-
50
- const http: IApiAdapter = {
51
- async request(req) {
52
- // use fetch/axios/undici, return { status, headers, data }
53
- return { status: 200, data: { ok: true } };
54
- },
55
- };
56
-
57
- const api = createApiClient("https://api.example.com", http, { Authorization: "Bearer token" });
58
- const res = await api.get("/users");
59
- ```
60
-
61
- ## Layout
62
-
63
- - Source files live at the project root: `index.ts`, `db.ts`, `api.ts`.
64
- - Build emits to `dist/` with `index.js` and `index.d.ts` for consumers.
65
- - No React/Next.js UI is included; the project is library-only.
66
- - Add any DB driver or HTTP client as dependencies in your own app.
1
+ # @neupgroup/mapper
2
+
3
+ Core library for Neup.Mapper. Provides simple schema registration utilities that can be expanded over time.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @neupgroup/mapper
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import Mapper from '@neupgroup/mapper';
15
+
16
+ const mapper = new Mapper();
17
+
18
+ mapper.register({
19
+ name: 'User',
20
+ fields: [
21
+ { name: 'id', type: 'string' },
22
+ { name: 'email', type: 'string' },
23
+ { name: 'createdAt', type: 'date' },
24
+ ],
25
+ });
26
+
27
+ console.log(mapper.list());
28
+ ```
29
+
30
+ ## Build
31
+
32
+ ```bash
33
+ npx tsc -p ./tsconfig.json
34
+ ```
35
+
36
+ Outputs are generated to `dist/` with type declarations.
37
+
@@ -0,0 +1,27 @@
1
+ import { z } from 'genkit';
2
+ export declare const AIOperationSuggestionInputSchema: z.ZodObject<{
3
+ operationDescription: z.ZodString;
4
+ databaseType: z.ZodString;
5
+ schema: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ databaseType: string;
8
+ operationDescription: string;
9
+ schema: string;
10
+ }, {
11
+ databaseType: string;
12
+ operationDescription: string;
13
+ schema: string;
14
+ }>;
15
+ export type AIOperationSuggestionInput = z.infer<typeof AIOperationSuggestionInputSchema>;
16
+ export declare const AIOperationSuggestionOutputSchema: z.ZodObject<{
17
+ suggestedCode: z.ZodString;
18
+ rationale: z.ZodString;
19
+ }, "strip", z.ZodTypeAny, {
20
+ rationale: string;
21
+ suggestedCode: string;
22
+ }, {
23
+ rationale: string;
24
+ suggestedCode: string;
25
+ }>;
26
+ export type AIOperationSuggestionOutput = z.infer<typeof AIOperationSuggestionOutputSchema>;
27
+ export declare function createSuggestOperation(ai: any): (input: AIOperationSuggestionInput) => Promise<any>;
@@ -0,0 +1,46 @@
1
+ import { z } from 'genkit';
2
+ export const AIOperationSuggestionInputSchema = z.object({
3
+ operationDescription: z
4
+ .string()
5
+ .describe('A detailed description of the operation to be performed.'),
6
+ databaseType: z
7
+ .string()
8
+ .describe('The type of database (e.g., MongoDB, Firestore, SQL).'),
9
+ schema: z.string().describe('The JSON schema of the data structure.'),
10
+ });
11
+ export const AIOperationSuggestionOutputSchema = z.object({
12
+ suggestedCode: z
13
+ .string()
14
+ .describe('The suggested code for the operation, as a string.'),
15
+ rationale: z
16
+ .string()
17
+ .describe('Explanation of why the suggested code is optimal.'),
18
+ });
19
+ export function createSuggestOperation(ai) {
20
+ const aiOperationSuggestionPrompt = ai.definePrompt({
21
+ name: 'aiOperationSuggestionPrompt',
22
+ input: { schema: AIOperationSuggestionInputSchema },
23
+ output: { schema: AIOperationSuggestionOutputSchema },
24
+ prompt: `You are an expert database engineer. Given a description of a database operation, a database type, and a data schema, you will generate the code to perform that operation. The operation can be for inserting, fetching, or updating data.
25
+
26
+ Operation Description: {{{operationDescription}}}
27
+ Database Type: {{{databaseType}}}
28
+ Schema: {{{schema}}}
29
+
30
+ Generate the code for the specified database type. Provide a rationale for the generated code.
31
+
32
+ Return the suggested code as a string, and include the rationale.
33
+ `,
34
+ });
35
+ const aiOperationSuggestionFlow = ai.defineFlow({
36
+ name: 'aiOperationSuggestionFlow',
37
+ inputSchema: AIOperationSuggestionInputSchema,
38
+ outputSchema: AIOperationSuggestionOutputSchema,
39
+ }, async (input) => {
40
+ const { output } = await aiOperationSuggestionPrompt(input);
41
+ return output;
42
+ });
43
+ return async function suggestOperation(input) {
44
+ return aiOperationSuggestionFlow(input);
45
+ };
46
+ }
@@ -0,0 +1,24 @@
1
+ import { z } from 'genkit';
2
+ export declare const AISchemaSuggestionInputSchema: z.ZodObject<{
3
+ dataDescription: z.ZodString;
4
+ databaseType: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ dataDescription: string;
7
+ databaseType: string;
8
+ }, {
9
+ dataDescription: string;
10
+ databaseType: string;
11
+ }>;
12
+ export type AISchemaSuggestionInput = z.infer<typeof AISchemaSuggestionInputSchema>;
13
+ export declare const AISchemaSuggestionOutputSchema: z.ZodObject<{
14
+ suggestedSchema: z.ZodString;
15
+ rationale: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ suggestedSchema: string;
18
+ rationale: string;
19
+ }, {
20
+ suggestedSchema: string;
21
+ rationale: string;
22
+ }>;
23
+ export type AISchemaSuggestionOutput = z.infer<typeof AISchemaSuggestionOutputSchema>;
24
+ export declare function createSuggestSchema(ai: any): (input: AISchemaSuggestionInput) => Promise<any>;
@@ -0,0 +1,46 @@
1
+ import { z } from 'genkit';
2
+ export const AISchemaSuggestionInputSchema = z.object({
3
+ dataDescription: z
4
+ .string()
5
+ .describe('A detailed description of the data that the schema should represent.'),
6
+ databaseType: z
7
+ .string()
8
+ .describe('The type of database for which the schema is being created (e.g., MongoDB, Firestore, SQL).'),
9
+ });
10
+ export const AISchemaSuggestionOutputSchema = z.object({
11
+ suggestedSchema: z
12
+ .string()
13
+ .describe('The suggested schema structure, formatted as a JSON string, tailored for the specified database type.'),
14
+ rationale: z
15
+ .string()
16
+ .describe('Explanation of why the suggested schema is optimal for the given data description and database type.'),
17
+ });
18
+ export function createSuggestSchema(ai) {
19
+ const aiSchemaSuggestionPrompt = ai.definePrompt({
20
+ name: 'aiSchemaSuggestionPrompt',
21
+ input: { schema: AISchemaSuggestionInputSchema },
22
+ output: { schema: AISchemaSuggestionOutputSchema },
23
+ prompt: `You are an expert database architect. Given a description of data and a database type, you will suggest an optimal schema structure.
24
+
25
+ Data Description: {{{dataDescription}}}
26
+ Database Type: {{{databaseType}}}
27
+
28
+ Consider the characteristics and constraints of the specified database type when formulating the schema.
29
+
30
+ Return the suggested schema as a JSON string, and include a rationale explaining why the schema is optimal.
31
+
32
+ Ensure that the suggested schema is valid and can be directly used with the specified database.
33
+ `,
34
+ });
35
+ const aiSchemaSuggestionFlow = ai.defineFlow({
36
+ name: 'aiSchemaSuggestionFlow',
37
+ inputSchema: AISchemaSuggestionInputSchema,
38
+ outputSchema: AISchemaSuggestionOutputSchema,
39
+ }, async (input) => {
40
+ const { output } = await aiSchemaSuggestionPrompt(input);
41
+ return output;
42
+ });
43
+ return async function suggestSchema(input) {
44
+ return aiSchemaSuggestionFlow(input);
45
+ };
46
+ }
@@ -0,0 +1,88 @@
1
+ import type { DbAdapter, QueryOptions } from './orm';
2
+ export type ColumnType = 'string' | 'number' | 'boolean' | 'date' | 'int';
3
+ export type ConnectionType = 'mysql' | 'sql' | 'firestore' | 'mongodb' | 'api';
4
+ export interface Field {
5
+ name: string;
6
+ type: ColumnType;
7
+ editable?: boolean;
8
+ autoIncrement?: boolean;
9
+ nullable?: boolean;
10
+ defaultValue?: unknown;
11
+ }
12
+ export interface SchemaDef {
13
+ name: string;
14
+ connectionName: string;
15
+ collectionName: string;
16
+ fields: Field[];
17
+ allowUndefinedFields?: boolean;
18
+ }
19
+ interface ConnectionConfig {
20
+ name: string;
21
+ type: ConnectionType;
22
+ key: Record<string, any>;
23
+ }
24
+ declare class ConnectionBuilder {
25
+ private manager;
26
+ private name;
27
+ private type;
28
+ constructor(manager: Connections, name: string, type: ConnectionType);
29
+ key(config: Record<string, any>): Connections;
30
+ }
31
+ export declare class Connections {
32
+ private connections;
33
+ private adapters;
34
+ create(name: string, type: ConnectionType): ConnectionBuilder;
35
+ register(config: ConnectionConfig): this;
36
+ attachAdapter(name: string, adapter: DbAdapter): this;
37
+ get(name: string): ConnectionConfig | undefined;
38
+ getAdapter(name: string): DbAdapter | undefined;
39
+ list(): ConnectionConfig[];
40
+ }
41
+ declare class SchemaBuilder {
42
+ private manager;
43
+ private name;
44
+ private connectionName?;
45
+ private collectionName?;
46
+ private fields;
47
+ private allowUndefinedFields;
48
+ constructor(manager: SchemaManager, name: string);
49
+ use(options: {
50
+ connection: string;
51
+ collection: string;
52
+ }): this;
53
+ setStructure(structure: Record<string, string> | Field[]): SchemaManager;
54
+ }
55
+ declare class SchemaQuery {
56
+ private manager;
57
+ private def;
58
+ private filters;
59
+ private rawWhere;
60
+ private pendingUpdate;
61
+ constructor(manager: SchemaManager, def: SchemaDef);
62
+ where(fieldOrPair: string | [string, any], value?: any, operator?: string): this;
63
+ whereComplex(raw: string): this;
64
+ private buildOptions;
65
+ to(update: Record<string, any>): this;
66
+ get(): Promise<Record<string, any>[]>;
67
+ getOne(): Promise<Record<string, any> | null>;
68
+ add(data: Record<string, any>): Promise<string>;
69
+ delete(): Promise<void>;
70
+ deleteOne(): Promise<void>;
71
+ update(): Promise<void>;
72
+ updateOne(): Promise<void>;
73
+ }
74
+ export declare class SchemaManager {
75
+ private connections;
76
+ private schemas;
77
+ constructor(connections: Connections);
78
+ create(name: string): SchemaBuilder;
79
+ register(def: SchemaDef): this;
80
+ use(name: string): SchemaQuery;
81
+ getAdapter(connectionName: string): DbAdapter | undefined;
82
+ list(): SchemaDef[];
83
+ }
84
+ export declare function connection(): Connections;
85
+ export declare function schema(conns?: Connections): SchemaManager;
86
+ export declare const schemas: SchemaManager;
87
+ export { createOrm } from './orm';
88
+ export type { DbAdapter, QueryOptions };
package/dist/index.js ADDED
@@ -0,0 +1,278 @@
1
+ class AdapterRegistry {
2
+ constructor() {
3
+ this.adaptersByConnection = new Map();
4
+ }
5
+ attach(connectionName, adapter) {
6
+ this.adaptersByConnection.set(connectionName, adapter);
7
+ }
8
+ get(connectionName) {
9
+ return this.adaptersByConnection.get(connectionName);
10
+ }
11
+ }
12
+ class ConnectionBuilder {
13
+ constructor(manager, name, type) {
14
+ this.manager = manager;
15
+ this.name = name;
16
+ this.type = type;
17
+ }
18
+ key(config) {
19
+ this.manager.register({ name: this.name, type: this.type, key: config });
20
+ return this.manager;
21
+ }
22
+ }
23
+ export class Connections {
24
+ constructor() {
25
+ this.connections = new Map();
26
+ this.adapters = new AdapterRegistry();
27
+ }
28
+ create(name, type) {
29
+ if (this.connections.has(name)) {
30
+ throw new Error(`Connection with name '${name}' already exists`);
31
+ }
32
+ return new ConnectionBuilder(this, name, type);
33
+ }
34
+ register(config) {
35
+ if (this.connections.has(config.name)) {
36
+ throw new Error(`Connection with name '${config.name}' already exists`);
37
+ }
38
+ this.connections.set(config.name, config);
39
+ return this;
40
+ }
41
+ attachAdapter(name, adapter) {
42
+ if (!this.connections.has(name)) {
43
+ throw new Error(`Cannot attach adapter: unknown connection '${name}'`);
44
+ }
45
+ this.adapters.attach(name, adapter);
46
+ return this;
47
+ }
48
+ get(name) {
49
+ return this.connections.get(name);
50
+ }
51
+ getAdapter(name) {
52
+ return this.adapters.get(name);
53
+ }
54
+ list() {
55
+ return Array.from(this.connections.values());
56
+ }
57
+ }
58
+ function parseDescriptorStructure(struct) {
59
+ let allowUndefinedFields = false;
60
+ const fields = [];
61
+ for (const [key, descriptor] of Object.entries(struct)) {
62
+ if (key === '?field') {
63
+ // Presence of '?field' enables accepting fields not defined in the schema
64
+ allowUndefinedFields = true;
65
+ continue;
66
+ }
67
+ const tokens = descriptor.split(/\s+/).map(t => t.trim().toLowerCase()).filter(Boolean);
68
+ const field = {
69
+ name: key,
70
+ type: tokens.find(t => ['string', 'number', 'boolean', 'date', 'int'].includes(t)) || 'string',
71
+ editable: tokens.includes('editable'),
72
+ autoIncrement: tokens.includes('auto_increment') || tokens.includes('autoincrement'),
73
+ };
74
+ fields.push(field);
75
+ }
76
+ return { fields, allowUndefinedFields };
77
+ }
78
+ class SchemaBuilder {
79
+ constructor(manager, name) {
80
+ this.manager = manager;
81
+ this.name = name;
82
+ this.fields = [];
83
+ this.allowUndefinedFields = false;
84
+ }
85
+ use(options) {
86
+ this.connectionName = options.connection;
87
+ this.collectionName = options.collection;
88
+ return this;
89
+ }
90
+ setStructure(structure) {
91
+ if (Array.isArray(structure)) {
92
+ this.fields = structure;
93
+ this.allowUndefinedFields = false;
94
+ }
95
+ else {
96
+ const parsed = parseDescriptorStructure(structure);
97
+ this.fields = parsed.fields;
98
+ this.allowUndefinedFields = parsed.allowUndefinedFields;
99
+ }
100
+ // Finalize schema registration
101
+ if (!this.connectionName || !this.collectionName) {
102
+ throw new Error('Schema.use({ connection, collection }) must be set before setStructure');
103
+ }
104
+ this.manager.register({
105
+ name: this.name,
106
+ connectionName: this.connectionName,
107
+ collectionName: this.collectionName,
108
+ fields: this.fields,
109
+ allowUndefinedFields: this.allowUndefinedFields,
110
+ });
111
+ return this.manager;
112
+ }
113
+ }
114
+ class SchemaQuery {
115
+ constructor(manager, def) {
116
+ this.manager = manager;
117
+ this.def = def;
118
+ this.filters = [];
119
+ this.rawWhere = null;
120
+ this.pendingUpdate = null;
121
+ }
122
+ // where('field','value', operator?) or where([field, value])
123
+ where(fieldOrPair, value, operator) {
124
+ if (Array.isArray(fieldOrPair)) {
125
+ const [field, v] = fieldOrPair;
126
+ this.filters.push({ field, operator: '=', value: v });
127
+ }
128
+ else {
129
+ const field = fieldOrPair;
130
+ this.filters.push({ field, operator: operator !== null && operator !== void 0 ? operator : '=', value });
131
+ }
132
+ return this;
133
+ }
134
+ // Accept a raw complex where clause string
135
+ whereComplex(raw) {
136
+ this.rawWhere = raw;
137
+ return this;
138
+ }
139
+ buildOptions() {
140
+ return {
141
+ collectionName: this.def.collectionName,
142
+ filters: this.filters.map(f => ({ field: f.field, operator: f.operator, value: f.value })),
143
+ limit: null,
144
+ offset: null,
145
+ sortBy: null,
146
+ fields: this.def.fields.map(f => f.name),
147
+ rawWhere: this.rawWhere,
148
+ };
149
+ }
150
+ to(update) {
151
+ this.pendingUpdate = update;
152
+ return this;
153
+ }
154
+ async get() {
155
+ const adapter = this.manager.getAdapter(this.def.connectionName);
156
+ if (!adapter)
157
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
158
+ const options = this.buildOptions();
159
+ const docs = adapter.get ? await adapter.get(options) : await adapter.getDocuments(options);
160
+ return docs;
161
+ }
162
+ async getOne() {
163
+ var _a;
164
+ const adapter = this.manager.getAdapter(this.def.connectionName);
165
+ if (!adapter)
166
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
167
+ const options = this.buildOptions();
168
+ if (adapter.getOne) {
169
+ const one = await adapter.getOne(options);
170
+ return (_a = one) !== null && _a !== void 0 ? _a : null;
171
+ }
172
+ const results = adapter.get ? await adapter.get(options) : await adapter.getDocuments(options);
173
+ return results[0] || null;
174
+ }
175
+ async add(data) {
176
+ const adapter = this.manager.getAdapter(this.def.connectionName);
177
+ if (!adapter)
178
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
179
+ if (!this.def.allowUndefinedFields) {
180
+ const allowed = new Set(this.def.fields.map(f => f.name));
181
+ data = Object.fromEntries(Object.entries(data).filter(([k]) => allowed.has(k)));
182
+ }
183
+ return adapter.addDocument(this.def.collectionName, data);
184
+ }
185
+ async delete() {
186
+ const adapter = this.manager.getAdapter(this.def.connectionName);
187
+ if (!adapter)
188
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
189
+ const docs = await this.get();
190
+ // Expect each doc has an 'id' field
191
+ for (const d of docs) {
192
+ const id = d.id;
193
+ if (!id)
194
+ throw new Error('Document missing id; cannot delete');
195
+ await adapter.deleteDocument(this.def.collectionName, id);
196
+ }
197
+ }
198
+ async deleteOne() {
199
+ const one = await this.getOne();
200
+ if (!one)
201
+ return;
202
+ const adapter = this.manager.getAdapter(this.def.connectionName);
203
+ if (!adapter)
204
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
205
+ const id = one.id;
206
+ if (!id)
207
+ throw new Error('Document missing id; cannot deleteOne');
208
+ await adapter.deleteDocument(this.def.collectionName, id);
209
+ }
210
+ async update() {
211
+ const adapter = this.manager.getAdapter(this.def.connectionName);
212
+ if (!adapter)
213
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
214
+ if (!this.pendingUpdate)
215
+ throw new Error('No update payload set; call to({ ... }) first');
216
+ const docs = await this.get();
217
+ for (const d of docs) {
218
+ const id = d.id;
219
+ if (!id)
220
+ throw new Error('Document missing id; cannot update');
221
+ await adapter.updateDocument(this.def.collectionName, id, this.pendingUpdate);
222
+ }
223
+ }
224
+ async updateOne() {
225
+ const adapter = this.manager.getAdapter(this.def.connectionName);
226
+ if (!adapter)
227
+ throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
228
+ if (!this.pendingUpdate)
229
+ throw new Error('No update payload set; call to({ ... }) first');
230
+ const one = await this.getOne();
231
+ if (!one)
232
+ return;
233
+ const id = one.id;
234
+ if (!id)
235
+ throw new Error('Document missing id; cannot updateOne');
236
+ await adapter.updateDocument(this.def.collectionName, id, this.pendingUpdate);
237
+ }
238
+ }
239
+ export class SchemaManager {
240
+ constructor(connections) {
241
+ this.connections = connections;
242
+ this.schemas = new Map();
243
+ }
244
+ create(name) {
245
+ if (this.schemas.has(name)) {
246
+ throw new Error(`Schema with name '${name}' already exists`);
247
+ }
248
+ return new SchemaBuilder(this, name);
249
+ }
250
+ register(def) {
251
+ this.schemas.set(def.name, def);
252
+ return this;
253
+ }
254
+ use(name) {
255
+ const def = this.schemas.get(name);
256
+ if (!def)
257
+ throw new Error(`Unknown schema '${name}'`);
258
+ return new SchemaQuery(this, def);
259
+ }
260
+ getAdapter(connectionName) {
261
+ return this.connections.getAdapter(connectionName);
262
+ }
263
+ list() {
264
+ return Array.from(this.schemas.values());
265
+ }
266
+ }
267
+ export function connection() {
268
+ return new Connections();
269
+ }
270
+ export function schema(conns) {
271
+ const ctx = conns || new Connections();
272
+ return new SchemaManager(ctx);
273
+ }
274
+ export const schemas = (() => {
275
+ const conns = new Connections();
276
+ return new SchemaManager(conns);
277
+ })();
278
+ export { createOrm } from './orm';
@@ -0,0 +1,10 @@
1
+ import type { DbAdapter, QueryOptions } from './types';
2
+ export declare function createOrm(adapter: DbAdapter): {
3
+ get(options: QueryOptions): Promise<import("@firebase/firestore").DocumentData[]>;
4
+ getOne(options: QueryOptions): Promise<any>;
5
+ getDocuments(options: QueryOptions): Promise<import("@firebase/firestore").DocumentData[]>;
6
+ addDocument(collectionName: string, data: Record<string, any>): Promise<string>;
7
+ updateDocument(collectionName: string, docId: string, data: Record<string, any>): Promise<void>;
8
+ deleteDocument(collectionName: string, docId: string): Promise<void>;
9
+ };
10
+ export type { DbAdapter, QueryOptions };
@@ -0,0 +1,28 @@
1
+ export function createOrm(adapter) {
2
+ return {
3
+ async get(options) {
4
+ if (adapter.get)
5
+ return adapter.get(options);
6
+ return adapter.getDocuments(options);
7
+ },
8
+ async getOne(options) {
9
+ var _a;
10
+ if (adapter.getOne)
11
+ return adapter.getOne(options);
12
+ const arr = adapter.get ? await adapter.get(options) : await adapter.getDocuments(options);
13
+ return (_a = arr[0]) !== null && _a !== void 0 ? _a : null;
14
+ },
15
+ async getDocuments(options) {
16
+ return adapter.getDocuments(options);
17
+ },
18
+ async addDocument(collectionName, data) {
19
+ return adapter.addDocument(collectionName, data);
20
+ },
21
+ async updateDocument(collectionName, docId, data) {
22
+ return adapter.updateDocument(collectionName, docId, data);
23
+ },
24
+ async deleteDocument(collectionName, docId) {
25
+ return adapter.deleteDocument(collectionName, docId);
26
+ },
27
+ };
28
+ }
@@ -0,0 +1,25 @@
1
+ import type { DocumentData } from 'firebase/firestore';
2
+ export interface QueryOptions {
3
+ collectionName: string;
4
+ filters: {
5
+ field: string;
6
+ operator: any;
7
+ value: any;
8
+ }[];
9
+ limit: number | null;
10
+ offset: number | null;
11
+ sortBy: {
12
+ field: string;
13
+ direction: 'asc' | 'desc';
14
+ } | null;
15
+ fields: string[];
16
+ rawWhere?: string | null;
17
+ }
18
+ export interface DbAdapter {
19
+ get?(options: QueryOptions): Promise<DocumentData[]>;
20
+ getOne?(options: QueryOptions): Promise<DocumentData | null>;
21
+ getDocuments(options: QueryOptions): Promise<DocumentData[]>;
22
+ addDocument(collectionName: string, data: DocumentData): Promise<string>;
23
+ updateDocument(collectionName: string, docId: string, data: DocumentData): Promise<void>;
24
+ deleteDocument(collectionName: string, docId: string): Promise<void>;
25
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,26 +1,20 @@
1
1
  {
2
2
  "name": "@neupgroup/mapper",
3
- "version": "1.0.0",
4
- "private": false,
3
+ "version": "1.2.0",
4
+ "description": "Neup.Mapper core library for schema and mapping utilities",
5
5
  "type": "module",
6
- "main": "index.js",
7
- "types": "index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./index.d.ts",
11
- "default": "./index.js"
12
- }
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "sideEffects": false,
13
+ "scripts": {
14
+ "build": "tsc -p ./tsconfig.json"
13
15
  },
14
16
  "publishConfig": {
15
17
  "access": "public"
16
- },
17
- "files": ["*.js", "*.d.ts"],
18
- "scripts": {
19
- "build": "tsc -p tsconfig.json",
20
- "typecheck": "tsc --noEmit"
21
- },
22
- "dependencies": {},
23
- "devDependencies": {
24
- "typescript": "^5"
25
18
  }
26
19
  }
20
+
package/api.d.ts DELETED
@@ -1,22 +0,0 @@
1
- export interface ApiRequest {
2
- method: string;
3
- url: string;
4
- headers?: Record<string, string>;
5
- body?: unknown;
6
- }
7
- export interface ApiResponse<T = unknown> {
8
- status: number;
9
- headers?: Record<string, string>;
10
- data?: T;
11
- }
12
- export interface ApiAdapter {
13
- request<T = unknown>(req: ApiRequest): Promise<ApiResponse<T>>;
14
- }
15
- export interface ApiClient {
16
- get<T = unknown>(path: string, headers?: Record<string, string>): Promise<ApiResponse<T>>;
17
- post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<ApiResponse<T>>;
18
- put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<ApiResponse<T>>;
19
- delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<ApiResponse<T>>;
20
- }
21
- export declare function createApiClient(baseUrl: string, adapter: ApiAdapter, defaultHeaders?: Record<string, string>): ApiClient;
22
- export type { ApiAdapter as IApiAdapter };
package/api.js DELETED
@@ -1,14 +0,0 @@
1
- export function createApiClient(baseUrl, adapter, defaultHeaders) {
2
- const buildUrl = (path) => {
3
- if (!baseUrl)
4
- return path;
5
- return baseUrl.endsWith("/") ? `${baseUrl}${path.replace(/^\//, "")}` : `${baseUrl}/${path.replace(/^\//, "")}`;
6
- };
7
- const mergeHeaders = (headers) => ({ ...(defaultHeaders || {}), ...(headers || {}) });
8
- return {
9
- get: (path, headers) => adapter.request({ method: "GET", url: buildUrl(path), headers: mergeHeaders(headers) }),
10
- post: (path, body, headers) => adapter.request({ method: "POST", url: buildUrl(path), headers: mergeHeaders(headers), body }),
11
- put: (path, body, headers) => adapter.request({ method: "PUT", url: buildUrl(path), headers: mergeHeaders(headers), body }),
12
- delete: (path, headers) => adapter.request({ method: "DELETE", url: buildUrl(path), headers: mergeHeaders(headers) }),
13
- };
14
- }
package/db.d.ts DELETED
@@ -1,19 +0,0 @@
1
- export type QueryParams = unknown[] | Record<string, unknown> | undefined;
2
- export interface DbAdapter {
3
- connect(config: Record<string, unknown>): Promise<void>;
4
- query<T = unknown>(sql: string, params?: QueryParams): Promise<T[]>;
5
- execute?(sql: string, params?: QueryParams): Promise<{
6
- affectedRows?: number;
7
- }>;
8
- close(): Promise<void>;
9
- }
10
- export interface Db {
11
- connect: (config: Record<string, unknown>) => Promise<void>;
12
- query: <T = unknown>(sql: string, params?: QueryParams) => Promise<T[]>;
13
- execute: (sql: string, params?: QueryParams) => Promise<{
14
- affectedRows?: number;
15
- }>;
16
- close: () => Promise<void>;
17
- }
18
- export declare function createDb(adapter: DbAdapter): Db;
19
- export type { DbAdapter as IDbAdapter };
package/db.js DELETED
@@ -1,15 +0,0 @@
1
- export function createDb(adapter) {
2
- const ensure = (fn) => fn();
3
- return {
4
- connect: (config) => ensure(() => adapter.connect(config)),
5
- query: (sql, params) => ensure(() => adapter.query(sql, params)),
6
- execute: (sql, params) => ensure(async () => {
7
- if (typeof adapter.execute === "function") {
8
- return adapter.execute(sql, params);
9
- }
10
- await adapter.query(sql, params);
11
- return { affectedRows: undefined };
12
- }),
13
- close: () => ensure(() => adapter.close()),
14
- };
15
- }
package/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./db";
2
- export * from "./api";
package/index.js DELETED
@@ -1,2 +0,0 @@
1
- export * from "./db";
2
- export * from "./api";