0

The schema looks like this:

import Game from './Game'
import {io, thinky} from '../'

const type = thinky.type


export const playerSchema = {
  id: type.string(),
  createdAt: type.date().default(thinky.r.now()),
  modifiedAt: type.date(),
  gameId: type.string(),
  name: type.string().default('Anon'),
  socket: type.string(),
  disconnected: type.boolean().default(false),
  levels: type.array().schema(type.object().schema({
    rounds: type.array().schema({
      card: type.number(),
      readyForNext: type.boolean().default(false),
      readyForNextTime: type.date(),
      tries: type.array().schema({
        answer: type.any(),
        correct: type.boolean(),
        startTime: type.date(),
        hasAnswered: type.boolean().default(false),
        hasAnsweredTime: type.date().default(null),
        hasClickedRetry: type.boolean().default(false),
        hasClickedRetryTime: type.date()
      }).default([])
    }).default([])
  })).default([])
}

When I try to save a player where levels has undefined values, I get:
"Cannot read property 'rounds' of undefined"

Further explanation: Sometimes a player will enter the game after the first level has been completed by other players. So, I would like the value of this index in the array to stay undefined.

Example Data (in YAML):
id: 1337
...
levels:
-
- rounds:
  - ...
    tries:
    - answer: [2, 4]
      ...

If i change playerSchema.levels to type.array(), I get:
"The element in the array [levels] (position 0) cannot be undefined"

Edit after comments:

Even with the defaults this doesn't work...

var thinky = require('thinky')({
  db: 'slam'
})
var type = thinky.type
var r = thinky.r


var playerSchema = {
  id: type.string(),
  createdAt: type.date().default(thinky.r.now()),
  modifiedAt: type.date(),
  gameId: type.string(),
  name: type.string().default('Anon'),
  socket: type.string(),
  disconnected: type.boolean().default(false),
  levels: type.array().schema(type.object().schema({
    rounds: type.array().schema(type.object().schema({
      card: type.number(),
      readyForNext: type.boolean().default(false),
      readyForNextTime: type.date(),
      tries: type.array().schema(type.object().schema({
        answer: type.any(),
        correct: type.boolean(),
        startTime: type.date(),
        hasAnswered: type.boolean().default(false),
        hasAnsweredTime: type.date().default(null),
        hasClickedRetry: type.boolean().default(false),
        hasClickedRetryTime: type.date()
      }).default({})).default([])
    }).default({})).default([])
  }).default({})).default([])
}

var Player = thinky.createModel('Player', playerSchema)

var player = new Player({
  levels: [undefined, {}]
})

player.save().then(console.log)

results in ...

/Users/arnar/git/slam-web-app/app/node_modules/thinky/lib/schema.js:92
      field = field[path[j]];
                   ^

TypeError: Cannot read property 'rounds' of undefined
    at generateDefault (/Users/arnar/git/slam-web-app/app/node_modules/thinky/lib/schema.js:92:20)
    at Object.generateDefault (/Users/arnar/git/slam-web-app/app/node_modules/thinky/lib/schema.js:86:11)
    at model.Document._generateDefault (/Users/arnar/git/slam-web-app/app/node_modules/thinky/lib/document.js:172:16)
    at new model (/Users/arnar/git/slam-web-app/app/node_modules/thinky/lib/model.js:131:11)
    at Object.<anonymous> (/Users/arnar/git/slam-web-app/app/tests/test-player-schema.js:36:14)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:475:10)
    at startup (node.js:117:18)
    at node.js:951:3

I even tried to create a pre validation hook, but that has no effect what so ever...

Player.pre('validate', function(next) {
  this.levels = this.levels.map(function(l) {
    return l != null ? l : {}
  })
  next()
})
demux
  • 4,544
  • 2
  • 32
  • 56
  • I don't know much about Thinky specifically, but if `undefined` values don't work, you could try reworking your code to use `null` instead. – mlucy Dec 30 '15 at 20:29

1 Answers1

0

Edit following up your comment. This is what you want (you basically need a default({}) inside the definition of the array schema:

var thinky = require('./lib/thinky.js')();
var type = thinky.type;
var r = thinky.r;


var Player = thinky.createModel('Player', {
  id: type.string(),
  levels: type.array().schema(type.object().schema({
    rounds: type.array().schema(type.object({
      card: type.number(),
      readyForNext: type.boolean().default(false),
      readyForNextTime: type.date(),
      tries: type.array().schema({
        answer: type.any(),
        correct: type.boolean(),
        startTime: type.date(),
        hasAnswered: type.boolean().default(false),
        hasAnsweredTime: type.date().default(null),
        hasClickedRetry: type.boolean().default(false),
        hasClickedRetryTime: type.date()
      }).default({})
    }).default({})).default([])
  })).default([])
})

var player = new Player({
  levels: [{}] 
});

player.save().then(console.log);

Author of thinky here. This works for me:

var thinky = require('./lib/thinky.js')();
var type = thinky.type;
var r = thinky.r;


var Player = thinky.createModel('Player', {
  id: type.string(),
  levels: type.array().schema(type.object().schema({
    rounds: type.array().schema({
      card: type.number(),
      readyForNext: type.boolean().default(false),
      readyForNextTime: type.date(),
      tries: type.array().schema({
        answer: type.any(),
        correct: type.boolean(),
        startTime: type.date(),
        hasAnswered: type.boolean().default(false),
        hasAnsweredTime: type.date().default(null),
        hasClickedRetry: type.boolean().default(false),
        hasClickedRetryTime: type.date()
      }).default([])
    }).default({})
  })).default([])
})

var player = new Player({
  levels: undefined
});

player.save().then(console.log);

On a side note, you may want to replace one default([]) with default({}) since you are setting a type object.

neumino
  • 4,342
  • 1
  • 18
  • 17
  • `levels` should be an array. `levels = undefined` works fine but `levels = [undefined, {..}]` does not work. – demux Jan 02 '16 at 21:50
  • Just edited my answer. You are missing a default to make `level: [undefined, {}]` to work. – neumino Jan 03 '16 at 00:12
  • But I don't want `{}` to be the default, I want it to stay `undefined`. Also, I think you're wrong on your side note. You're setting the default of `rounds` to `{}` while it should be `[]`. I don't have defaults on the objects within the arrays, because they should be `undefined`. – demux Jan 03 '16 at 00:36
  • In this case it's pretty simple. You cannot save `undefined` as it's not a JSON value. – neumino Jan 03 '16 at 19:34
  • Yeah, but I can't save `null` either. And what am I doing wrong with the pre validation hook? – demux Jan 03 '16 at 20:42
  • I tried `undefined` in `rethinkdb` without `thinky`, and it does indeed not work, so I'll have to settle for `null`. But I'm not sure if `undefined` not being a JSON value is a valid explanation. Date is not a JSON value, and yet it is stored in `rethinkdb`. But at this point, all I really want to know is: "Why can't I manipulate the data in the pre validation hook?" – demux Jan 04 '16 at 04:03