meadow-integration 1.0.23 → 1.0.25

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.
@@ -1,72 +1,455 @@
1
1
  /*
2
2
  Unit tests for Retold Integration Adapter
3
+
4
+ Validates that the integration adapter correctly fetches the remote
5
+ schema, marshals source records, and upserts them to the server.
6
+
7
+ Uses a mock HTTP server to simulate meadow-endpoints API responses.
3
8
  */
4
9
 
5
10
  const Chai = require('chai');
6
11
  const Expect = Chai.expect;
7
12
 
13
+ const libHTTP = require('http');
8
14
  const libPict = require('pict');
9
15
  const libIntegrationAdapter = require('../source/Meadow-Service-Integration-Adapter.js');
16
+ const libMeadowCloneRestClient = require('../source/services/clone/Meadow-Service-RestClient.js');
10
17
 
11
- suite
12
- (
13
- 'Integration Adapter Basic',
14
- () =>
18
+ // ── Test Constants ──────────────────────────────────────────────────────────────
19
+
20
+ const MOCK_PORT = 18199;
21
+ const MOCK_BASE_URL = `http://localhost:${MOCK_PORT}/1.0/`;
22
+
23
+ // ── Mock Schema ─────────────────────────────────────────────────────────────────
24
+ // This is what the Schema endpoint returns — a JSON schema with properties.
25
+
26
+ const MOCK_SCHEMA =
27
+ {
28
+ title: 'TestEntity',
29
+ type: 'object',
30
+ properties:
31
+ {
32
+ IDTestEntity: { type: 'integer' },
33
+ GUIDTestEntity: { type: 'string', size: 128 },
34
+ Name: { type: 'string', size: 200 },
35
+ Value: { type: 'integer' }
36
+ },
37
+ required: ['IDTestEntity']
38
+ };
39
+
40
+ // ── Mock Server State ───────────────────────────────────────────────────────────
41
+
42
+ let _MockState =
43
+ {
44
+ NextID: 1,
45
+ UpsertedRecords: [],
46
+ StoredRecords: {}
47
+ };
48
+
49
+ function resetMockState()
50
+ {
51
+ _MockState.NextID = 1;
52
+ _MockState.UpsertedRecords = [];
53
+ _MockState.StoredRecords = {};
54
+ }
55
+
56
+ // ── Mock HTTP Server ────────────────────────────────────────────────────────────
57
+ // Simulates meadow-endpoints API responses for the TestEntity entity.
58
+
59
+ function createMockServer()
60
+ {
61
+ return libHTTP.createServer(
62
+ (pRequest, pResponse) =>
15
63
  {
16
- setup(() => { });
64
+ let tmpURL = pRequest.url;
65
+ let tmpBody = '';
17
66
 
18
- suite
19
- (
20
- 'Basic Tests',
67
+ pResponse.setHeader('Content-Type', 'application/json');
68
+
69
+ pRequest.on('data',
70
+ (pChunk) =>
71
+ {
72
+ tmpBody += pChunk;
73
+ });
74
+
75
+ pRequest.on('end',
76
+ () =>
77
+ {
78
+ // GET /1.0/TestEntity/Schema
79
+ if (pRequest.method === 'GET' && tmpURL.match(/\/1\.0\/TestEntity\/Schema/))
80
+ {
81
+ pResponse.end(JSON.stringify(MOCK_SCHEMA));
82
+ return;
83
+ }
84
+
85
+ // PUT /1.0/TestEntity/Upsert
86
+ if (pRequest.method === 'PUT' && tmpURL.match(/\/1\.0\/TestEntity\/Upsert/))
87
+ {
88
+ let tmpRecord = {};
89
+ try
90
+ {
91
+ tmpRecord = JSON.parse(tmpBody);
92
+ }
93
+ catch (pError)
94
+ {
95
+ pResponse.statusCode = 400;
96
+ pResponse.end(JSON.stringify({ Error: 'Invalid JSON' }));
97
+ return;
98
+ }
99
+
100
+ // Assign an auto-incremented ID if not present or zero
101
+ if (!tmpRecord.IDTestEntity || tmpRecord.IDTestEntity === 0)
102
+ {
103
+ tmpRecord.IDTestEntity = _MockState.NextID++;
104
+ }
105
+
106
+ // Store and track the upserted record
107
+ _MockState.UpsertedRecords.push(JSON.parse(JSON.stringify(tmpRecord)));
108
+ _MockState.StoredRecords[tmpRecord.GUIDTestEntity] = tmpRecord;
109
+
110
+ pResponse.end(JSON.stringify(tmpRecord));
111
+ return;
112
+ }
113
+
114
+ // GET /1.0/TestEntitys/By/GUIDTestEntity/{guid}/0/1
115
+ if (pRequest.method === 'GET' && tmpURL.match(/\/1\.0\/TestEntitys\/By\/GUIDTestEntity\//))
116
+ {
117
+ let tmpParts = tmpURL.split('/');
118
+ // URL pattern: /1.0/TestEntitys/By/GUIDTestEntity/{guid}/0/1
119
+ let tmpGUID = tmpParts[5];
120
+ let tmpRecord = _MockState.StoredRecords[tmpGUID];
121
+ if (tmpRecord)
122
+ {
123
+ pResponse.end(JSON.stringify([tmpRecord]));
124
+ }
125
+ else
126
+ {
127
+ pResponse.end(JSON.stringify([]));
128
+ }
129
+ return;
130
+ }
131
+
132
+ // Fallback — 404
133
+ pResponse.statusCode = 404;
134
+ pResponse.end(JSON.stringify({ Error: `Unknown endpoint: ${pRequest.method} ${tmpURL}` }));
135
+ });
136
+ });
137
+ }
138
+
139
+ suite
140
+ (
141
+ 'Integration Adapter Basic',
142
+ () =>
143
+ {
144
+ setup(() => { });
145
+
146
+ suite
147
+ (
148
+ 'Basic Tests',
149
+ () =>
150
+ {
151
+ test(
152
+ 'Object Instantiation',
153
+ (fDone) =>
154
+ {
155
+ let _Fable = new libPict();
156
+ _Fable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
157
+ let tmpIntegrationAdapter = _Fable.instantiateServiceProvider('IntegrationAdapter', { Entity: 'TestEntity' }, 'TestEntity');
158
+ Expect(tmpIntegrationAdapter).to.be.an('object');
159
+ return fDone();
160
+ });
161
+ }
162
+ );
163
+ }
164
+ );
165
+
166
+ suite
167
+ (
168
+ 'Integration Adapter with Mock Server',
169
+ () =>
170
+ {
171
+ let _MockServer = null;
172
+
173
+ suiteSetup
174
+ (
175
+ (fDone) =>
176
+ {
177
+ _MockServer = createMockServer();
178
+ _MockServer.listen(MOCK_PORT,
21
179
  () =>
22
180
  {
23
- test(
24
- 'Object Instantiation',
25
- (fDone) =>
26
- {
27
- let _Fable = new libPict();
28
- _Fable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
29
- let tmpIntegrationAdapter = _Fable.instantiateServiceProvider('IntegrationAdapter', { Entity: 'TestEntity' }, 'TestEntity');
30
- Expect(tmpIntegrationAdapter).to.be.an('object');
181
+ return fDone();
182
+ });
183
+ }
184
+ );
185
+
186
+ suiteTeardown
187
+ (
188
+ (fDone) =>
189
+ {
190
+ if (_MockServer)
191
+ {
192
+ _MockServer.close(fDone);
193
+ }
194
+ else
195
+ {
196
+ return fDone();
197
+ }
198
+ }
199
+ );
200
+
201
+ setup
202
+ (
203
+ () =>
204
+ {
205
+ resetMockState();
206
+ }
207
+ );
208
+
209
+ // ── Schema Fetch ────────────────────────────────────────────────────
210
+
211
+ suite
212
+ (
213
+ 'Schema Fetch',
214
+ () =>
215
+ {
216
+ test
217
+ (
218
+ 'meadowSchema should be populated after integrateRecords',
219
+ (fDone) =>
220
+ {
221
+ let tmpFable = new libPict(
222
+ {
223
+ Product: 'AdapterTest',
224
+ ProductVersion: '1.0.0',
225
+ LogStreams: [{ streamtype: 'console', level: 'error' }]
226
+ });
227
+ tmpFable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
228
+ tmpFable.serviceManager.addServiceType('MeadowCloneRestClient', libMeadowCloneRestClient);
229
+ tmpFable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
230
+ {
231
+ ServerURL: MOCK_BASE_URL
232
+ });
233
+
234
+ let tmpAdapter = tmpFable.instantiateServiceProvider('IntegrationAdapter',
235
+ {
236
+ Entity: 'TestEntity',
237
+ SimpleMarshal: true
238
+ }, 'TestEntity');
239
+
240
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'test-schema-1', Name: 'SchemaCheck', Value: 1 });
241
+
242
+ // Before integration, meadowSchema should not be set
243
+ Expect(tmpAdapter.meadowSchema).to.not.be.ok;
244
+
245
+ tmpAdapter.integrateRecords(
246
+ (pError) =>
247
+ {
248
+ Expect(pError).to.not.exist;
249
+
250
+ // After integration, meadowSchema should be populated
251
+ Expect(tmpAdapter.meadowSchema).to.be.an('object');
252
+ Expect(tmpAdapter.meadowSchema).to.have.property('properties');
253
+ Expect(tmpAdapter.meadowSchema.properties).to.have.property('Name');
254
+ Expect(tmpAdapter.meadowSchema.properties).to.have.property('Value');
255
+ Expect(tmpAdapter.meadowSchema.properties).to.have.property('IDTestEntity');
256
+ Expect(tmpAdapter.meadowSchema.properties).to.have.property('GUIDTestEntity');
257
+
31
258
  return fDone();
32
259
  });
33
- /* This works if you have the right database set up; will adapt for real tests later when time arises
34
- test(
35
- 'Integrate some Book Prices',
36
- (fDone) =>
37
- {
38
- let _Fable = new libFable();
39
- _Fable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
40
- let tmpIntegrationAdapter = _Fable.instantiateServiceProvider('IntegrationAdapter', { Entity: 'BookPrice' }, 'BookPrice');
41
-
42
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-3', CouponCode:'TestyCoupon', Price:3.50 });
43
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-4', CouponCode:'TestyCoupon', Price:3.22232 });
44
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-5', CouponCode:'None', Price:3.50 });
45
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-6', CouponCode:'', Price:3.57 });
46
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-7', Price:3.50 });
47
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-8', CouponCode:'TestyCoupon', Price:183.77 });
48
- tmpIntegrationAdapter.integrateRecords(fDone);
260
+ }
261
+ );
262
+ }
263
+ );
264
+
265
+ // ── Full Integration Pipeline ───────────────────────────────────────
266
+
267
+ suite
268
+ (
269
+ 'Full Integration Pipeline',
270
+ () =>
271
+ {
272
+ test
273
+ (
274
+ 'upsert body should include marshaled field values (not just the GUID)',
275
+ function (fDone)
276
+ {
277
+ this.timeout(10000);
278
+
279
+ let tmpFable = new libPict(
280
+ {
281
+ Product: 'AdapterTest',
282
+ ProductVersion: '1.0.0',
283
+ LogStreams: [{ streamtype: 'console', level: 'error' }]
284
+ });
285
+ tmpFable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
286
+ tmpFable.serviceManager.addServiceType('MeadowCloneRestClient', libMeadowCloneRestClient);
287
+ tmpFable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
288
+ {
289
+ ServerURL: MOCK_BASE_URL
49
290
  });
50
- test(
51
- 'Integrate some Book Prices via the static method',
52
- (fDone) =>
291
+
292
+ let tmpAdapter = tmpFable.instantiateServiceProvider('IntegrationAdapter',
53
293
  {
54
- let _Fable = new libFable({});
294
+ Entity: 'TestEntity',
295
+ SimpleMarshal: true
296
+ }, 'TestEntity');
297
+
298
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'test-1', Name: 'Alice', Value: 42 });
299
+
300
+ tmpAdapter.integrateRecords(
301
+ (pError) =>
302
+ {
303
+ Expect(pError).to.not.exist;
304
+
305
+ // The mock server should have received exactly one upsert
306
+ Expect(_MockState.UpsertedRecords.length).to.equal(1,
307
+ `Expected 1 upserted record, got ${_MockState.UpsertedRecords.length}`);
55
308
 
56
- _Fable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
309
+ let tmpUpsertedRecord = _MockState.UpsertedRecords[0];
310
+
311
+ // The GUID should be present (with the adapter prefix)
312
+ Expect(tmpUpsertedRecord).to.have.property('GUIDTestEntity');
313
+ Expect(tmpUpsertedRecord.GUIDTestEntity).to.be.a('string');
314
+ Expect(tmpUpsertedRecord.GUIDTestEntity).to.include('test-1');
315
+
316
+ // CRITICAL: Verify field values were marshaled through.
317
+ // If the arrow-function arguments bug is present, the schema
318
+ // fetch would fail silently, meadowSchema would be null, and
319
+ // SimpleMarshal would not copy Name and Value through.
320
+ Expect(tmpUpsertedRecord).to.have.property('Name');
321
+ Expect(tmpUpsertedRecord.Name).to.equal('Alice');
322
+ Expect(tmpUpsertedRecord).to.have.property('Value');
323
+ Expect(tmpUpsertedRecord.Value).to.equal(42);
324
+
325
+ // Verify the schema was also populated
326
+ Expect(tmpAdapter.meadowSchema).to.be.an('object');
327
+ Expect(tmpAdapter.meadowSchema.properties).to.have.property('Name');
328
+
329
+ return fDone();
330
+ });
331
+ }
332
+ );
333
+
334
+ test
335
+ (
336
+ 'should integrate multiple records with correct field values',
337
+ function (fDone)
338
+ {
339
+ this.timeout(10000);
340
+
341
+ let tmpFable = new libPict(
342
+ {
343
+ Product: 'AdapterTest',
344
+ ProductVersion: '1.0.0',
345
+ LogStreams: [{ streamtype: 'console', level: 'error' }]
346
+ });
347
+ tmpFable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
348
+ tmpFable.serviceManager.addServiceType('MeadowCloneRestClient', libMeadowCloneRestClient);
349
+ tmpFable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
350
+ {
351
+ ServerURL: MOCK_BASE_URL
352
+ });
353
+
354
+ let tmpAdapter = tmpFable.instantiateServiceProvider('IntegrationAdapter',
355
+ {
356
+ Entity: 'TestEntity',
357
+ SimpleMarshal: true
358
+ }, 'TestEntity');
359
+
360
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'multi-1', Name: 'Alice', Value: 42 });
361
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'multi-2', Name: 'Bob', Value: 99 });
362
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'multi-3', Name: 'Charlie', Value: 7 });
363
+
364
+ tmpAdapter.integrateRecords(
365
+ (pError) =>
366
+ {
367
+ Expect(pError).to.not.exist;
57
368
 
58
- let tmpIntegrationAdapter = libIntegrationAdapter.getAdapter(_Fable, 'BookPrice', 'BP');
369
+ Expect(_MockState.UpsertedRecords.length).to.equal(3,
370
+ `Expected 3 upserted records, got ${_MockState.UpsertedRecords.length}`);
59
371
 
60
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd3', CouponCode:'TestyCoupon', Price:3.50 });
61
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd4', CouponCode:'TestyCoupon', Price:3.22232 });
62
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd5', CouponCode:'None', Price:3.50 });
63
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd6', CouponCode:'', Price:3.57 });
64
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd7', Price:3.540 });
65
- tmpIntegrationAdapter.addSourceRecord({ GUIDBookPrice:'GUID-dd8', CouponCode:'TestyCoupon', Price:183.77 });
66
- tmpIntegrationAdapter.integrateRecords(fDone);
372
+ // Build a lookup by the original GUID suffix for easy verification
373
+ let tmpByGUID = {};
374
+ for (let i = 0; i < _MockState.UpsertedRecords.length; i++)
375
+ {
376
+ let tmpRec = _MockState.UpsertedRecords[i];
377
+ if (tmpRec.GUIDTestEntity.indexOf('multi-1') > -1) tmpByGUID['multi-1'] = tmpRec;
378
+ if (tmpRec.GUIDTestEntity.indexOf('multi-2') > -1) tmpByGUID['multi-2'] = tmpRec;
379
+ if (tmpRec.GUIDTestEntity.indexOf('multi-3') > -1) tmpByGUID['multi-3'] = tmpRec;
380
+ }
381
+
382
+ Expect(tmpByGUID['multi-1'].Name).to.equal('Alice');
383
+ Expect(tmpByGUID['multi-1'].Value).to.equal(42);
384
+
385
+ Expect(tmpByGUID['multi-2'].Name).to.equal('Bob');
386
+ Expect(tmpByGUID['multi-2'].Value).to.equal(99);
387
+
388
+ Expect(tmpByGUID['multi-3'].Name).to.equal('Charlie');
389
+ Expect(tmpByGUID['multi-3'].Value).to.equal(7);
390
+
391
+ // Each record should have been assigned a server-side ID
392
+ Expect(tmpByGUID['multi-1'].IDTestEntity).to.be.above(0);
393
+ Expect(tmpByGUID['multi-2'].IDTestEntity).to.be.above(0);
394
+ Expect(tmpByGUID['multi-3'].IDTestEntity).to.be.above(0);
395
+
396
+ return fDone();
397
+ });
398
+ }
399
+ );
400
+
401
+ test
402
+ (
403
+ 'without SimpleMarshal, fields not in schema properties are excluded',
404
+ function (fDone)
405
+ {
406
+ this.timeout(10000);
407
+
408
+ let tmpFable = new libPict(
409
+ {
410
+ Product: 'AdapterTest',
411
+ ProductVersion: '1.0.0',
412
+ LogStreams: [{ streamtype: 'console', level: 'error' }]
413
+ });
414
+ tmpFable.addServiceType('IntegrationAdapter', libIntegrationAdapter);
415
+ tmpFable.serviceManager.addServiceType('MeadowCloneRestClient', libMeadowCloneRestClient);
416
+ tmpFable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
417
+ {
418
+ ServerURL: MOCK_BASE_URL
419
+ });
420
+
421
+ let tmpAdapter = tmpFable.instantiateServiceProvider('IntegrationAdapter',
422
+ {
423
+ Entity: 'TestEntity',
424
+ SimpleMarshal: false
425
+ }, 'TestEntity');
426
+
427
+ // ExtraField is not in the mock schema
428
+ tmpAdapter.addSourceRecord({ GUIDTestEntity: 'test-extra', Name: 'Diana', Value: 55, ExtraField: 'should-not-appear' });
429
+
430
+ tmpAdapter.integrateRecords(
431
+ (pError) =>
432
+ {
433
+ Expect(pError).to.not.exist;
434
+
435
+ Expect(_MockState.UpsertedRecords.length).to.equal(1);
436
+
437
+ let tmpUpsertedRecord = _MockState.UpsertedRecords[0];
438
+
439
+ // Name and Value should be marshaled through the schema
440
+ Expect(tmpUpsertedRecord).to.have.property('Name');
441
+ Expect(tmpUpsertedRecord.Name).to.equal('Diana');
442
+ Expect(tmpUpsertedRecord).to.have.property('Value');
443
+ Expect(tmpUpsertedRecord.Value).to.equal(55);
444
+
445
+ // ExtraField should NOT be in the upserted record
446
+ Expect(tmpUpsertedRecord).to.not.have.property('ExtraField');
447
+
448
+ return fDone();
67
449
  });
68
- */
69
450
  }
70
451
  );
71
- }
72
- );
452
+ }
453
+ );
454
+ }
455
+ );
@@ -79,7 +79,15 @@ suite
79
79
  NameFirst TEXT DEFAULT '',
80
80
  NameLast TEXT DEFAULT '',
81
81
  FullName TEXT DEFAULT '',
82
- Config TEXT DEFAULT ''
82
+ Config TEXT DEFAULT '',
83
+ IDCustomer INTEGER DEFAULT 0,
84
+ Email TEXT DEFAULT '',
85
+ Phone TEXT DEFAULT '',
86
+ Address TEXT DEFAULT '',
87
+ City TEXT DEFAULT '',
88
+ State TEXT DEFAULT '',
89
+ Postal TEXT DEFAULT '',
90
+ Country TEXT DEFAULT ''
83
91
  );
84
92
  CREATE TABLE IF NOT EXISTS Book (
85
93
  IDBook INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -97,13 +105,15 @@ suite
97
105
  ISBN TEXT DEFAULT '',
98
106
  Language TEXT DEFAULT '',
99
107
  ImageURL TEXT DEFAULT '',
100
- PublicationYear INTEGER DEFAULT 0
108
+ PublicationYear INTEGER DEFAULT 0,
109
+ IDCustomer INTEGER DEFAULT 0
101
110
  );
102
111
  CREATE TABLE IF NOT EXISTS BookAuthorJoin (
103
112
  IDBookAuthorJoin INTEGER PRIMARY KEY AUTOINCREMENT,
104
113
  GUIDBookAuthorJoin TEXT DEFAULT '',
105
114
  IDBook INTEGER DEFAULT 0,
106
- IDAuthor INTEGER DEFAULT 0
115
+ IDAuthor INTEGER DEFAULT 0,
116
+ IDCustomer INTEGER DEFAULT 0
107
117
  );
108
118
  CREATE TABLE IF NOT EXISTS Author (
109
119
  IDAuthor INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -116,7 +126,8 @@ suite
116
126
  DeleteDate TEXT DEFAULT '',
117
127
  DeletingIDUser INTEGER DEFAULT 0,
118
128
  Name TEXT DEFAULT '',
119
- IDUser INTEGER DEFAULT 0
129
+ IDUser INTEGER DEFAULT 0,
130
+ IDCustomer INTEGER DEFAULT 0
120
131
  );
121
132
  CREATE TABLE IF NOT EXISTS BookPrice (
122
133
  IDBookPrice INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -133,7 +144,8 @@ suite
133
144
  EndDate TEXT DEFAULT '',
134
145
  Discountable INTEGER DEFAULT 0,
135
146
  CouponCode TEXT DEFAULT '',
136
- IDBook INTEGER DEFAULT 0
147
+ IDBook INTEGER DEFAULT 0,
148
+ IDCustomer INTEGER DEFAULT 0
137
149
  );
138
150
  CREATE TABLE IF NOT EXISTS BookStore (
139
151
  IDBookStore INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -150,7 +162,11 @@ suite
150
162
  City TEXT DEFAULT '',
151
163
  State TEXT DEFAULT '',
152
164
  Postal TEXT DEFAULT '',
153
- Country TEXT DEFAULT ''
165
+ Country TEXT DEFAULT '',
166
+ IDCustomer INTEGER DEFAULT 0,
167
+ StoreType TEXT DEFAULT '',
168
+ Phone TEXT DEFAULT '',
169
+ Email TEXT DEFAULT ''
154
170
  );
155
171
  CREATE TABLE IF NOT EXISTS BookStoreInventory (
156
172
  IDBookStoreInventory INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -168,7 +184,8 @@ suite
168
184
  IDBook INTEGER DEFAULT 0,
169
185
  IDBookStore INTEGER DEFAULT 0,
170
186
  IDBookPrice INTEGER DEFAULT 0,
171
- StockingAssociate INTEGER DEFAULT 0
187
+ StockingAssociate INTEGER DEFAULT 0,
188
+ IDCustomer INTEGER DEFAULT 0
172
189
  );
173
190
  CREATE TABLE IF NOT EXISTS Review (
174
191
  IDReview INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -183,7 +200,84 @@ suite
183
200
  Text TEXT DEFAULT '',
184
201
  Rating INTEGER DEFAULT 0,
185
202
  IDBook INTEGER DEFAULT 0,
186
- IDUser INTEGER DEFAULT 0
203
+ IDUser INTEGER DEFAULT 0,
204
+ IDCustomer INTEGER DEFAULT 0
205
+ );
206
+ CREATE TABLE IF NOT EXISTS Customer (
207
+ IDCustomer INTEGER PRIMARY KEY AUTOINCREMENT,
208
+ GUIDCustomer TEXT DEFAULT '',
209
+ CreateDate TEXT DEFAULT '',
210
+ CreatingIDUser INTEGER DEFAULT 0,
211
+ UpdateDate TEXT DEFAULT '',
212
+ UpdatingIDUser INTEGER DEFAULT 0,
213
+ Deleted INTEGER DEFAULT 0,
214
+ DeleteDate TEXT DEFAULT '',
215
+ DeletingIDUser INTEGER DEFAULT 0,
216
+ Name TEXT DEFAULT '',
217
+ Description TEXT DEFAULT '',
218
+ ContactName TEXT DEFAULT '',
219
+ ContactEmail TEXT DEFAULT '',
220
+ ContactPhone TEXT DEFAULT '',
221
+ Address TEXT DEFAULT '',
222
+ City TEXT DEFAULT '',
223
+ State TEXT DEFAULT '',
224
+ Postal TEXT DEFAULT '',
225
+ Country TEXT DEFAULT '',
226
+ Active INTEGER DEFAULT 0
227
+ );
228
+ CREATE TABLE IF NOT EXISTS BookStoreEmployee (
229
+ IDBookStoreEmployee INTEGER PRIMARY KEY AUTOINCREMENT,
230
+ GUIDBookStoreEmployee TEXT DEFAULT '',
231
+ CreateDate TEXT DEFAULT '',
232
+ CreatingIDUser INTEGER DEFAULT 0,
233
+ UpdateDate TEXT DEFAULT '',
234
+ UpdatingIDUser INTEGER DEFAULT 0,
235
+ Deleted INTEGER DEFAULT 0,
236
+ DeleteDate TEXT DEFAULT '',
237
+ DeletingIDUser INTEGER DEFAULT 0,
238
+ Title TEXT DEFAULT '',
239
+ HireDate TEXT DEFAULT '',
240
+ TerminationDate TEXT DEFAULT '',
241
+ IsActive INTEGER DEFAULT 0,
242
+ IDUser INTEGER DEFAULT 0,
243
+ IDBookStore INTEGER DEFAULT 0,
244
+ IDCustomer INTEGER DEFAULT 0
245
+ );
246
+ CREATE TABLE IF NOT EXISTS BookStoreSale (
247
+ IDBookStoreSale INTEGER PRIMARY KEY AUTOINCREMENT,
248
+ GUIDBookStoreSale TEXT DEFAULT '',
249
+ CreateDate TEXT DEFAULT '',
250
+ CreatingIDUser INTEGER DEFAULT 0,
251
+ UpdateDate TEXT DEFAULT '',
252
+ UpdatingIDUser INTEGER DEFAULT 0,
253
+ Deleted INTEGER DEFAULT 0,
254
+ DeleteDate TEXT DEFAULT '',
255
+ DeletingIDUser INTEGER DEFAULT 0,
256
+ SaleDate TEXT DEFAULT '',
257
+ TotalAmount REAL DEFAULT 0,
258
+ PaymentMethod TEXT DEFAULT '',
259
+ TransactionID TEXT DEFAULT '',
260
+ IDBookStore INTEGER DEFAULT 0,
261
+ IDUser INTEGER DEFAULT 0,
262
+ IDCustomer INTEGER DEFAULT 0
263
+ );
264
+ CREATE TABLE IF NOT EXISTS BookStoreSaleItem (
265
+ IDBookStoreSaleItem INTEGER PRIMARY KEY AUTOINCREMENT,
266
+ GUIDBookStoreSaleItem TEXT DEFAULT '',
267
+ CreateDate TEXT DEFAULT '',
268
+ CreatingIDUser INTEGER DEFAULT 0,
269
+ UpdateDate TEXT DEFAULT '',
270
+ UpdatingIDUser INTEGER DEFAULT 0,
271
+ Deleted INTEGER DEFAULT 0,
272
+ DeleteDate TEXT DEFAULT '',
273
+ DeletingIDUser INTEGER DEFAULT 0,
274
+ Quantity INTEGER DEFAULT 0,
275
+ UnitPrice REAL DEFAULT 0,
276
+ LineTotal REAL DEFAULT 0,
277
+ IDBookStoreSale INTEGER DEFAULT 0,
278
+ IDBook INTEGER DEFAULT 0,
279
+ IDBookPrice INTEGER DEFAULT 0,
280
+ IDCustomer INTEGER DEFAULT 0
187
281
  );
188
282
  `);
189
283